Ver código fonte

Move ObjectPermissionRequiredMixin to utilities.views

Jeremy Stretch 5 anos atrás
pai
commit
cc6e74dfd5

+ 1 - 2
netbox/dcim/views.py

@@ -21,13 +21,12 @@ from extras.models import Graph
 from extras.views import ObjectConfigContextView
 from extras.views import ObjectConfigContextView
 from ipam.models import Prefix, VLAN
 from ipam.models import Prefix, VLAN
 from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
 from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
-from netbox.authentication import ObjectPermissionRequiredMixin
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator
 from utilities.paginator import EnhancedPaginator
 from utilities.utils import csv_format
 from utilities.utils import csv_format
 from utilities.views import (
 from utilities.views import (
     BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, GetReturnURLMixin,
     BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, GetReturnURLMixin,
-    ObjectImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
+    ObjectImportView, ObjectDeleteView, ObjectEditView, ObjectListView, ObjectPermissionRequiredMixin,
 )
 )
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
 from . import filters, forms, tables
 from . import filters, forms, tables

+ 1 - 1
netbox/ipam/views.py

@@ -8,10 +8,10 @@ from django.views.generic import View
 from django_tables2 import RequestConfig
 from django_tables2 import RequestConfig
 
 
 from dcim.models import Device, Interface
 from dcim.models import Device, Interface
-from netbox.authentication import ObjectPermissionRequiredMixin
 from utilities.paginator import EnhancedPaginator
 from utilities.paginator import EnhancedPaginator
 from utilities.views import (
 from utilities.views import (
     BulkCreateView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
     BulkCreateView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
+    ObjectPermissionRequiredMixin,
 )
 )
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
 from . import filters, forms, tables
 from . import filters, forms, tables

+ 0 - 55
netbox/netbox/authentication.py

@@ -1,55 +0,0 @@
-from django.contrib.auth.mixins import AccessMixin
-from django.core.exceptions import ImproperlyConfigured
-
-from users.models import ObjectPermission
-
-
-class ObjectPermissionRequiredMixin(AccessMixin):
-    """
-    Similar to Django's built-in PermissionRequiredMixin, but extended to check for both model-level and object-level
-    permission assignments. If the user has only object-level permissions assigned, the view's queryset is filtered
-    to return only those objects on which the user is permitted to perform the specified action.
-    """
-    permission_required = None
-
-    def has_permission(self):
-        user = self.request.user
-
-        # First, check that the user is granted the required permission at either the model or object level.
-        if not user.has_perm(self.permission_required):
-            return False
-
-        # Superusers implicitly have all permissions
-        if user.is_superuser:
-            return True
-
-        # Determine whether the permission is model-level or object-level. Model-level permissions grant the
-        # specified action to *all* objects, so no further action is needed.
-        if self.permission_required in {*user._user_perm_cache, *user._group_perm_cache}:
-            return True
-
-        # If the permission is granted only at the object level, filter the view's queryset to return only objects
-        # on which the user is permitted to perform the specified action.
-        attrs = ObjectPermission.objects.get_attr_constraints(user, self.permission_required)
-        if attrs:
-            # Update the view's QuerySet to filter only the permitted objects
-            self.queryset = self.queryset.filter(attrs)
-            return True
-
-    def dispatch(self, request, *args, **kwargs):
-        if self.permission_required is None:
-            raise ImproperlyConfigured(
-                '{0} is missing the permission_required attribute. Define {0}.permission_required, or override '
-                '{0}.get_permission_required().'.format(self.__class__.__name__)
-            )
-
-        if not hasattr(self, 'queryset'):
-            raise ImproperlyConfigured(
-                '{} has no queryset defined. ObjectPermissionRequiredMixin may only be used on views which define '
-                'a base queryset'.format(self.__class__.__name__)
-            )
-
-        if not self.has_permission():
-            return self.handle_no_permission()
-
-        return super().dispatch(request, *args, **kwargs)

+ 15 - 0
netbox/utilities/permissions.py

@@ -0,0 +1,15 @@
+def get_permission_for_model(model, action):
+    """
+    Resolve the named permission for a given model (or instance) and action (e.g. view or add).
+
+    :param model: A model or instance
+    :param action: View, add, change, or delete (string)
+    """
+    if action not in ('view', 'add', 'change', 'delete'):
+        raise ValueError(f"Unsupported action: {action}")
+
+    return '{}.{}_{}'.format(
+        model._meta.app_label,
+        action,
+        model._meta.model_name
+    )

+ 61 - 1
netbox/utilities/views.py

@@ -4,7 +4,8 @@ from copy import deepcopy
 
 
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
+from django.contrib.auth.mixins import AccessMixin
+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
 from django.db.models import ManyToManyField, ProtectedError
 from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
 from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
@@ -32,6 +33,61 @@ from .forms import ConfirmationForm, ImportForm
 from .paginator import EnhancedPaginator, get_paginate_count
 from .paginator import EnhancedPaginator, get_paginate_count
 
 
 
 
+#
+# Mixins
+#
+
+class ObjectPermissionRequiredMixin(AccessMixin):
+    """
+    Similar to Django's built-in PermissionRequiredMixin, but extended to check for both model-level and object-level
+    permission assignments. If the user has only object-level permissions assigned, the view's queryset is filtered
+    to return only those objects on which the user is permitted to perform the specified action.
+    """
+    permission_required = None
+
+    def has_permission(self):
+        user = self.request.user
+
+        # First, check that the user is granted the required permission at either the model or object level.
+        if not user.has_perm(self.permission_required):
+            return False
+
+        # Superusers implicitly have all permissions
+        if user.is_superuser:
+            return True
+
+        # Determine whether the permission is model-level or object-level. Model-level permissions grant the
+        # specified action to *all* objects, so no further action is needed.
+        if self.permission_required in {*user._user_perm_cache, *user._group_perm_cache}:
+            return True
+
+        # If the permission is granted only at the object level, filter the view's queryset to return only objects
+        # on which the user is permitted to perform the specified action.
+        attrs = ObjectPermission.objects.get_attr_constraints(user, self.permission_required)
+        if attrs:
+            # Update the view's QuerySet to filter only the permitted objects
+            self.queryset = self.queryset.filter(attrs)
+            return True
+
+    def dispatch(self, request, *args, **kwargs):
+        if self.permission_required is None:
+            raise ImproperlyConfigured(
+                '{0} is missing the permission_required attribute. Define {0}.permission_required, or override '
+                '{0}.get_permission_required().'.format(self.__class__.__name__)
+            )
+
+        if not hasattr(self, 'queryset'):
+            raise ImproperlyConfigured(
+                '{} has no queryset defined. ObjectPermissionRequiredMixin may only be used on views which define '
+                'a base queryset'.format(self.__class__.__name__)
+            )
+
+        if not self.has_permission():
+            return self.handle_no_permission()
+
+        return super().dispatch(request, *args, **kwargs)
+
+
 class GetReturnURLMixin(object):
 class GetReturnURLMixin(object):
     """
     """
     Provides logic for determining where a user should be redirected after processing a form.
     Provides logic for determining where a user should be redirected after processing a form.
@@ -58,6 +114,10 @@ class GetReturnURLMixin(object):
         return reverse('home')
         return reverse('home')
 
 
 
 
+#
+# Generic views
+#
+
 class ObjectListView(View):
 class ObjectListView(View):
     """
     """
     List a series of objects.
     List a series of objects.