Skip to content

Commit

Permalink
Fixes #11335: Default manager for ObjectChange should filter by insta…
Browse files Browse the repository at this point in the history
…lled apps (#11709)

* 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>
  • Loading branch information
jeremystretch and abhi1693 authored Jul 5, 2023
1 parent 3307bd2 commit 63ba9fb
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 9 deletions.
2 changes: 1 addition & 1 deletion netbox/extras/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
Retrieve a list of recent changes.
"""
metadata_class = ContentTypeMetadata
queryset = ObjectChange.objects.prefetch_related('user')
queryset = ObjectChange.objects.valid_models().prefetch_related('user')
serializer_class = serializers.ObjectChangeSerializer
filterset_class = filtersets.ObjectChangeFilterSet

Expand Down
4 changes: 2 additions & 2 deletions netbox/extras/models/change_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.urls import reverse

from extras.choices import *
from utilities.querysets import RestrictedQuerySet
from ..querysets import ObjectChangeQuerySet

__all__ = (
'ObjectChange',
Expand Down Expand Up @@ -82,7 +82,7 @@ class ObjectChange(models.Model):
null=True
)

objects = RestrictedQuerySet.as_manager()
objects = ObjectChangeQuerySet.as_manager()

class Meta:
ordering = ['-time']
Expand Down
13 changes: 13 additions & 0 deletions netbox/extras/querysets.py
Original file line number Diff line number Diff line change
@@ -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.db.models import OuterRef, Subquery, Q

Expand Down Expand Up @@ -151,3 +153,14 @@ def _get_config_context_filters(self):
)

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)
3 changes: 2 additions & 1 deletion netbox/extras/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from core.choices import ManagedFileRootPathChoices
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.reports import Report
from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
Expand Down Expand Up @@ -579,6 +578,7 @@ def setUp(self):
super().setUp()

# 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

def test_get_report(self):
Expand Down Expand Up @@ -621,6 +621,7 @@ def setUp(self):
super().setUp()

# 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

def test_get_script(self):
Expand Down
8 changes: 4 additions & 4 deletions netbox/extras/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ class ConfigTemplateBulkSyncDataView(generic.BulkSyncDataView):
#

class ObjectChangeListView(generic.ObjectListView):
queryset = ObjectChange.objects.all()
queryset = ObjectChange.objects.valid_models()
filterset = filtersets.ObjectChangeFilterSet
filterset_form = forms.ObjectChangeFilterForm
table = tables.ObjectChangeTable
Expand All @@ -521,10 +521,10 @@ class ObjectChangeListView(generic.ObjectListView):

@register_model_view(ObjectChange)
class ObjectChangeView(generic.ObjectView):
queryset = ObjectChange.objects.all()
queryset = ObjectChange.objects.valid_models()

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
).exclude(
pk=instance.pk
Expand All @@ -534,7 +534,7 @@ def get_extra_context(self, request, instance):
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_id=instance.changed_object_id,
)
Expand Down
4 changes: 3 additions & 1 deletion netbox/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ class ProfileView(LoginRequiredMixin, View):
def get(self, request):

# 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'
)[:20]
changelog_table = ObjectChangeTable(changelog)
Expand Down

0 comments on commit 63ba9fb

Please sign in to comment.