Jelajahi Sumber

Add additional_permissions to ObjectPermissionRequiredMixin

Jeremy Stretch 5 tahun lalu
induk
melakukan
3ef4287d57
3 mengubah file dengan 16 tambahan dan 16 penghapusan
  1. 5 7
      netbox/dcim/views.py
  2. 1 3
      netbox/ipam/views.py
  3. 10 6
      netbox/utilities/views.py

+ 5 - 7
netbox/dcim/views.py

@@ -1082,7 +1082,7 @@ class DeviceInventoryView(ObjectView):
 
 
 class DeviceStatusView(ObjectView):
-    permission_required = ('dcim.view_device', 'dcim.napalm_read')
+    additional_permissions = ['dcim.napalm_read']
     queryset = Device.objects.all()
 
     def get(self, request, pk):
@@ -1096,7 +1096,7 @@ class DeviceStatusView(ObjectView):
 
 
 class DeviceLLDPNeighborsView(ObjectView):
-    permission_required = ('dcim.view_device', 'dcim.napalm_read')
+    additional_permissions = ['dcim.napalm_read']
     queryset = Device.objects.all()
 
     def get(self, request, pk):
@@ -1114,7 +1114,7 @@ class DeviceLLDPNeighborsView(ObjectView):
 
 
 class DeviceConfigView(ObjectView):
-    permission_required = ('dcim.view_device', 'dcim.napalm_read')
+    additional_permissions = ['dcim.napalm_read']
     queryset = Device.objects.all()
 
     def get(self, request, pk):
@@ -1857,11 +1857,11 @@ class CableView(ObjectView):
         })
 
 
-class CableTraceView(ObjectPermissionRequiredMixin, View):
+class CableTraceView(ObjectView):
     """
     Trace a cable path beginning from the given termination.
     """
-    permission_required = 'dcim.view_cable'
+    additional_permissions = ['dcim.view_cable']
 
     def dispatch(self, request, *args, **kwargs):
         model = kwargs.pop('model')
@@ -2006,7 +2006,6 @@ class CableBulkDeleteView(BulkDeleteView):
 #
 
 class ConsoleConnectionsListView(ObjectListView):
-    permission_required = ('dcim.view_consoleport', 'dcim.view_consoleserverport')
     queryset = ConsolePort.objects.prefetch_related(
         'device', 'connected_endpoint__device'
     ).filter(
@@ -2038,7 +2037,6 @@ class ConsoleConnectionsListView(ObjectListView):
 
 
 class PowerConnectionsListView(ObjectListView):
-    permission_required = ('dcim.view_powerport', 'dcim.view_poweroutlet')
     queryset = PowerPort.objects.prefetch_related(
         'device', '_connected_poweroutlet__device'
     ).filter(

+ 1 - 3
netbox/ipam/views.py

@@ -671,7 +671,7 @@ class IPAddressEditView(ObjectEditView):
         return obj
 
 
-class IPAddressAssignView(ObjectPermissionRequiredMixin, View):
+class IPAddressAssignView(ObjectView):
     """
     Search for IPAddresses to be assigned to an Interface.
     """
@@ -719,7 +719,6 @@ class IPAddressDeleteView(ObjectDeleteView):
 
 
 class IPAddressBulkCreateView(BulkCreateView):
-    permission_required = 'ipam.add_ipaddress'
     form = forms.IPAddressBulkCreateForm
     model_form = forms.IPAddressBulkAddForm
     pattern_target = 'address'
@@ -761,7 +760,6 @@ class VLANGroupListView(ObjectListView):
 
 
 class VLANGroupEditView(ObjectEditView):
-    permission_required = 'ipam.add_vlangroup'
     queryset = VLANGroup.objects.all()
     model_form = forms.VLANGroupForm
     default_return_url = 'ipam:vlangroup_list'

+ 10 - 6
netbox/utilities/views.py

@@ -43,18 +43,24 @@ 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.
+
+    additional_permissions: An optional iterable of statically declared permissions to evaluate in addition to those
+                            derived from the object type
     """
-    permission_required = None
+    additional_permissions = list()
 
     def get_required_permission(self):
-        return self.permission_required
+        """
+        Return the specific permission necessary to perform the requested action on an object.
+        """
+        raise NotImplementedError(f"{self.__class__.__name__} must implement get_required_permission()")
 
     def has_permission(self):
         user = self.request.user
         permission_required = self.get_required_permission()
 
-        # First, check that the user is granted the required permission at either the model or object level.
-        if not user.has_perm(permission_required):
+        # First, check that the user is granted the required permission(s) at either the model or object level.
+        if not user.has_perms((permission_required, *self.additional_permissions)):
             return False
 
         # Superusers implicitly have all permissions
@@ -148,8 +154,6 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
     action_buttons = ('add', 'import', 'export')
 
     def get_required_permission(self):
-        if getattr(self, 'permission_required') is not None:
-            return self.permission_required
         return get_permission_for_model(self.queryset.model, 'view')
 
     def queryset_to_yaml(self):