Преглед изворни кода

Introduce restrict_queryset()

Jeremy Stretch пре 5 година
родитељ
комит
58989b85c8
3 измењених фајлова са 24 додато и 17 уклоњено
  1. 3 8
      netbox/utilities/api.py
  2. 18 0
      netbox/utilities/permissions.py
  3. 3 9
      netbox/utilities/views.py

+ 3 - 8
netbox/utilities/api.py

@@ -6,7 +6,7 @@ from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDoesNotExist, PermissionDenied
 from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDoesNotExist, PermissionDenied
 from django.db import transaction
 from django.db import transaction
-from django.db.models import ManyToManyField, ProtectedError, Q
+from django.db.models import ManyToManyField, ProtectedError
 from django.urls import reverse
 from django.urls import reverse
 from rest_framework.exceptions import APIException
 from rest_framework.exceptions import APIException
 from rest_framework.permissions import BasePermission
 from rest_framework.permissions import BasePermission
@@ -16,7 +16,7 @@ from rest_framework.serializers import Field, ModelSerializer, ValidationError
 from rest_framework.viewsets import ModelViewSet as _ModelViewSet
 from rest_framework.viewsets import ModelViewSet as _ModelViewSet
 
 
 from netbox.api import TokenPermissions
 from netbox.api import TokenPermissions
-from users.models import ObjectPermission
+from utilities.permissions import restrict_queryset
 from .utils import dict_to_filter_params, dynamic_import
 from .utils import dict_to_filter_params, dynamic_import
 
 
 
 
@@ -340,12 +340,7 @@ class ModelViewSet(_ModelViewSet):
         permission_required = TokenPermissions.perms_map[request.method][0] % kwargs
         permission_required = TokenPermissions.perms_map[request.method][0] % kwargs
 
 
         # Update the view's QuerySet to filter only the permitted objects
         # Update the view's QuerySet to filter only the permitted objects
-        obj_perm_attrs = request.user._object_perm_cache[permission_required]
-        attrs = Q()
-        for perm_attrs in obj_perm_attrs:
-            if perm_attrs:
-                attrs |= Q(**perm_attrs)
-        self.queryset = self.queryset.filter(attrs)
+        self.queryset = restrict_queryset(self.queryset, request.user, permission_required)
 
 
     def dispatch(self, request, *args, **kwargs):
     def dispatch(self, request, *args, **kwargs):
         logger = logging.getLogger('netbox.api.views.ModelViewSet')
         logger = logging.getLogger('netbox.api.views.ModelViewSet')

+ 18 - 0
netbox/utilities/permissions.py

@@ -1,4 +1,5 @@
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
+from django.db.models import Q
 
 
 
 
 def get_permission_for_model(model, action):
 def get_permission_for_model(model, action):
@@ -33,3 +34,20 @@ def resolve_permission(name):
         raise ValueError(f"Unknown app/model for {name}")
         raise ValueError(f"Unknown app/model for {name}")
 
 
     return content_type, action
     return content_type, action
+
+
+def restrict_queryset(queryset, user, permission_required):
+    """
+    Filters a QuerySet to return only the objects on which the specified user has been granted the specified
+    permission.
+
+    :param queryset: Base QuerySet to be restricted
+    :param user: User instance
+    :param permission_required: Name of the required permission (e.g. "dcim.view_site")
+    """
+    obj_perm_attrs = user._object_perm_cache[permission_required]
+    attrs = Q()
+    for perm_attrs in obj_perm_attrs:
+        if perm_attrs:
+            attrs |= Q(**perm_attrs)
+    return queryset.filter(attrs)

+ 3 - 9
netbox/utilities/views.py

@@ -8,7 +8,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.contrib.auth.mixins import AccessMixin
 from django.contrib.auth.mixins import AccessMixin
 from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured, ObjectDoesNotExist, ValidationError
 from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured, ObjectDoesNotExist, ValidationError
 from django.db import transaction, IntegrityError
 from django.db import transaction, IntegrityError
-from django.db.models import ManyToManyField, ProtectedError, Q
+from django.db.models import ManyToManyField, ProtectedError
 from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
 from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
 from django.http import HttpResponse, HttpResponseServerError
 from django.http import HttpResponse, HttpResponseServerError
 from django.shortcuts import get_object_or_404, redirect, render
 from django.shortcuts import get_object_or_404, redirect, render
@@ -26,10 +26,9 @@ from django_tables2 import RequestConfig
 
 
 from extras.models import CustomField, CustomFieldValue, ExportTemplate
 from extras.models import CustomField, CustomFieldValue, ExportTemplate
 from extras.querysets import CustomFieldQueryset
 from extras.querysets import CustomFieldQueryset
-from users.models import ObjectPermission
 from utilities.exceptions import AbortTransaction
 from utilities.exceptions import AbortTransaction
 from utilities.forms import BootstrapMixin, CSVDataField, TableConfigForm
 from utilities.forms import BootstrapMixin, CSVDataField, TableConfigForm
-from utilities.permissions import get_permission_for_model
+from utilities.permissions import get_permission_for_model, restrict_queryset
 from utilities.utils import csv_format, prepare_cloned_fields
 from utilities.utils import csv_format, prepare_cloned_fields
 from .error_handlers import handle_protectederror
 from .error_handlers import handle_protectederror
 from .forms import ConfirmationForm, ImportForm
 from .forms import ConfirmationForm, ImportForm
@@ -67,12 +66,7 @@ class ObjectPermissionRequiredMixin(AccessMixin):
 
 
         # Update the view's QuerySet to filter only the permitted objects
         # Update the view's QuerySet to filter only the permitted objects
         if user.is_authenticated and not user.is_superuser:
         if user.is_authenticated and not user.is_superuser:
-            obj_perm_attrs = user._object_perm_cache[permission_required]
-            attrs = Q()
-            for perm_attrs in obj_perm_attrs:
-                if perm_attrs:
-                    attrs |= Q(**perm_attrs)
-            self.queryset = self.queryset.filter(attrs)
+            self.queryset = restrict_queryset(self.queryset, user, permission_required)
 
 
         return True
         return True