mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
* Fixes #11335: Default manager for ObjectChange should filter by installed apps * Employ canonical model discovery mechanism * Move filtering logic to valid_models() queryset method * fixed import to avoid content type does not exist * Cleanup --------- Co-authored-by: Abhimanyu Saharan <desk.abhimanyu@gmail.com>
This commit is contained in:
@ -368,7 +368,7 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
|
|||||||
Retrieve a list of recent changes.
|
Retrieve a list of recent changes.
|
||||||
"""
|
"""
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = ObjectChange.objects.prefetch_related('user')
|
queryset = ObjectChange.objects.valid_models().prefetch_related('user')
|
||||||
serializer_class = serializers.ObjectChangeSerializer
|
serializer_class = serializers.ObjectChangeSerializer
|
||||||
filterset_class = filtersets.ObjectChangeFilterSet
|
filterset_class = filtersets.ObjectChangeFilterSet
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ from django.db import models
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from extras.choices import *
|
from extras.choices import *
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from ..querysets import ObjectChangeQuerySet
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ObjectChange',
|
'ObjectChange',
|
||||||
@ -82,7 +82,7 @@ class ObjectChange(models.Model):
|
|||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = RestrictedQuerySet.as_manager()
|
objects = ObjectChangeQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-time']
|
ordering = ['-time']
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from django.apps import apps
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.postgres.aggregates import JSONBAgg
|
from django.contrib.postgres.aggregates import JSONBAgg
|
||||||
from django.db.models import OuterRef, Subquery, Q
|
from django.db.models import OuterRef, Subquery, Q
|
||||||
|
|
||||||
@ -151,3 +153,14 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return base_query
|
return base_query
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectChangeQuerySet(RestrictedQuerySet):
|
||||||
|
|
||||||
|
def valid_models(self):
|
||||||
|
# Exclude any change records which refer to an instance of a model that's no longer installed. This
|
||||||
|
# can happen when a plugin is removed but its data remains in the database, for example.
|
||||||
|
content_type_ids = set(
|
||||||
|
ct.pk for ct in ContentType.objects.get_for_models(*apps.get_models()).values()
|
||||||
|
)
|
||||||
|
return self.filter(changed_object_type_id__in=content_type_ids)
|
||||||
|
@ -8,7 +8,6 @@ from rest_framework import status
|
|||||||
|
|
||||||
from core.choices import ManagedFileRootPathChoices
|
from core.choices import ManagedFileRootPathChoices
|
||||||
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site
|
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site
|
||||||
from extras.api.views import ReportViewSet, ScriptViewSet
|
|
||||||
from extras.models import *
|
from extras.models import *
|
||||||
from extras.reports import Report
|
from extras.reports import Report
|
||||||
from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
|
from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
|
||||||
@ -579,6 +578,7 @@ class ReportTest(APITestCase):
|
|||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
# Monkey-patch the API viewset's _get_report() method to return our test Report above
|
# Monkey-patch the API viewset's _get_report() method to return our test Report above
|
||||||
|
from extras.api.views import ReportViewSet
|
||||||
ReportViewSet._get_report = self.get_test_report
|
ReportViewSet._get_report = self.get_test_report
|
||||||
|
|
||||||
def test_get_report(self):
|
def test_get_report(self):
|
||||||
@ -621,6 +621,7 @@ class ScriptTest(APITestCase):
|
|||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
# Monkey-patch the API viewset's _get_script() method to return our test Script above
|
# Monkey-patch the API viewset's _get_script() method to return our test Script above
|
||||||
|
from extras.api.views import ScriptViewSet
|
||||||
ScriptViewSet._get_script = self.get_test_script
|
ScriptViewSet._get_script = self.get_test_script
|
||||||
|
|
||||||
def test_get_script(self):
|
def test_get_script(self):
|
||||||
|
@ -511,7 +511,7 @@ class ConfigTemplateBulkSyncDataView(generic.BulkSyncDataView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ObjectChangeListView(generic.ObjectListView):
|
class ObjectChangeListView(generic.ObjectListView):
|
||||||
queryset = ObjectChange.objects.all()
|
queryset = ObjectChange.objects.valid_models()
|
||||||
filterset = filtersets.ObjectChangeFilterSet
|
filterset = filtersets.ObjectChangeFilterSet
|
||||||
filterset_form = forms.ObjectChangeFilterForm
|
filterset_form = forms.ObjectChangeFilterForm
|
||||||
table = tables.ObjectChangeTable
|
table = tables.ObjectChangeTable
|
||||||
@ -521,10 +521,10 @@ class ObjectChangeListView(generic.ObjectListView):
|
|||||||
|
|
||||||
@register_model_view(ObjectChange)
|
@register_model_view(ObjectChange)
|
||||||
class ObjectChangeView(generic.ObjectView):
|
class ObjectChangeView(generic.ObjectView):
|
||||||
queryset = ObjectChange.objects.all()
|
queryset = ObjectChange.objects.valid_models()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
related_changes = ObjectChange.objects.restrict(request.user, 'view').filter(
|
related_changes = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(
|
||||||
request_id=instance.request_id
|
request_id=instance.request_id
|
||||||
).exclude(
|
).exclude(
|
||||||
pk=instance.pk
|
pk=instance.pk
|
||||||
@ -534,7 +534,7 @@ class ObjectChangeView(generic.ObjectView):
|
|||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
objectchanges = ObjectChange.objects.restrict(request.user, 'view').filter(
|
objectchanges = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(
|
||||||
changed_object_type=instance.changed_object_type,
|
changed_object_type=instance.changed_object_type,
|
||||||
changed_object_id=instance.changed_object_id,
|
changed_object_id=instance.changed_object_id,
|
||||||
)
|
)
|
||||||
|
@ -159,7 +159,9 @@ class ProfileView(LoginRequiredMixin, View):
|
|||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
|
||||||
# Compile changelog table
|
# Compile changelog table
|
||||||
changelog = ObjectChange.objects.restrict(request.user, 'view').filter(user=request.user).prefetch_related(
|
changelog = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(
|
||||||
|
user=request.user
|
||||||
|
).prefetch_related(
|
||||||
'changed_object_type'
|
'changed_object_type'
|
||||||
)[:20]
|
)[:20]
|
||||||
changelog_table = ObjectChangeTable(changelog)
|
changelog_table = ObjectChangeTable(changelog)
|
||||||
|
Reference in New Issue
Block a user