Просмотр исходного кода

Transition ComponentCreateView to use ObjectPermissionRequiredMixin

Jeremy Stretch 5 лет назад
Родитель
Сommit
f36c797e98
3 измененных файлов с 72 добавлено и 72 удалено
  1. 36 54
      netbox/dcim/views.py
  2. 34 15
      netbox/utilities/views.py
  3. 2 3
      netbox/virtualization/views.py

+ 36 - 54
netbox/dcim/views.py

@@ -671,9 +671,8 @@ class DeviceTypeBulkDeleteView(BulkDeleteView):
 # Console port templates
 #
 
-class ConsolePortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_consoleporttemplate'
-    model = ConsolePortTemplate
+class ConsolePortTemplateCreateView(ComponentCreateView):
+    queryset = ConsolePortTemplate.objects.all()
     form = forms.ConsolePortTemplateCreateForm
     model_form = forms.ConsolePortTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -703,9 +702,8 @@ class ConsolePortTemplateBulkDeleteView(BulkDeleteView):
 # Console server port templates
 #
 
-class ConsoleServerPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_consoleserverporttemplate'
-    model = ConsoleServerPortTemplate
+class ConsoleServerPortTemplateCreateView(ComponentCreateView):
+    queryset = ConsoleServerPortTemplate.objects.all()
     form = forms.ConsoleServerPortTemplateCreateForm
     model_form = forms.ConsoleServerPortTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -735,9 +733,8 @@ class ConsoleServerPortTemplateBulkDeleteView(BulkDeleteView):
 # Power port templates
 #
 
-class PowerPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_powerporttemplate'
-    model = PowerPortTemplate
+class PowerPortTemplateCreateView(ComponentCreateView):
+    queryset = PowerPortTemplate.objects.all()
     form = forms.PowerPortTemplateCreateForm
     model_form = forms.PowerPortTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -767,9 +764,8 @@ class PowerPortTemplateBulkDeleteView(BulkDeleteView):
 # Power outlet templates
 #
 
-class PowerOutletTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_poweroutlettemplate'
-    model = PowerOutletTemplate
+class PowerOutletTemplateCreateView(ComponentCreateView):
+    queryset = PowerOutletTemplate.objects.all()
     form = forms.PowerOutletTemplateCreateForm
     model_form = forms.PowerOutletTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -799,9 +795,8 @@ class PowerOutletTemplateBulkDeleteView(BulkDeleteView):
 # Interface templates
 #
 
-class InterfaceTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_interfacetemplate'
-    model = InterfaceTemplate
+class InterfaceTemplateCreateView(ComponentCreateView):
+    queryset = InterfaceTemplate.objects.all()
     form = forms.InterfaceTemplateCreateForm
     model_form = forms.InterfaceTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -831,9 +826,8 @@ class InterfaceTemplateBulkDeleteView(BulkDeleteView):
 # Front port templates
 #
 
-class FrontPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_frontporttemplate'
-    model = FrontPortTemplate
+class FrontPortTemplateCreateView(ComponentCreateView):
+    queryset = FrontPortTemplate.objects.all()
     form = forms.FrontPortTemplateCreateForm
     model_form = forms.FrontPortTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -863,9 +857,8 @@ class FrontPortTemplateBulkDeleteView(BulkDeleteView):
 # Rear port templates
 #
 
-class RearPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_rearporttemplate'
-    model = RearPortTemplate
+class RearPortTemplateCreateView(ComponentCreateView):
+    queryset = RearPortTemplate.objects.all()
     form = forms.RearPortTemplateCreateForm
     model_form = forms.RearPortTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -895,9 +888,8 @@ class RearPortTemplateBulkDeleteView(BulkDeleteView):
 # Device bay templates
 #
 
-class DeviceBayTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_devicebaytemplate'
-    model = DeviceBayTemplate
+class DeviceBayTemplateCreateView(ComponentCreateView):
+    queryset = DeviceBayTemplate.objects.all()
     form = forms.DeviceBayTemplateCreateForm
     model_form = forms.DeviceBayTemplateForm
     template_name = 'dcim/device_component_add.html'
@@ -913,7 +905,6 @@ class DeviceBayTemplateDeleteView(ObjectDeleteView):
 
 
 # class DeviceBayTemplateBulkEditView(BulkEditView):
-#     permission_required = 'dcim.change_devicebaytemplate'
 #     queryset = DeviceBayTemplate.objects.all()
 #     table = tables.DeviceBayTemplateTable
 #     form = forms.DeviceBayTemplateBulkEditForm
@@ -1105,7 +1096,7 @@ class DeviceStatusView(ObjectView):
         })
 
 
-class DeviceLLDPNeighborsView(PermissionRequiredMixin, View):
+class DeviceLLDPNeighborsView(ObjectView):
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
     queryset = Device.objects.all()
 
@@ -1123,7 +1114,7 @@ class DeviceLLDPNeighborsView(PermissionRequiredMixin, View):
         })
 
 
-class DeviceConfigView(PermissionRequiredMixin, View):
+class DeviceConfigView(ObjectView):
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
     queryset = Device.objects.all()
 
@@ -1209,9 +1200,8 @@ class ConsolePortListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class ConsolePortCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_consoleport'
-    model = ConsolePort
+class ConsolePortCreateView(ComponentCreateView):
+    queryset = ConsolePort.objects.all()
     form = forms.ConsolePortCreateForm
     model_form = forms.ConsolePortForm
     template_name = 'dcim/device_component_add.html'
@@ -1259,9 +1249,8 @@ class ConsoleServerPortListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class ConsoleServerPortCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_consoleserverport'
-    model = ConsoleServerPort
+class ConsoleServerPortCreateView(ComponentCreateView):
+    queryset = ConsoleServerPort.objects.all()
     form = forms.ConsoleServerPortCreateForm
     model_form = forms.ConsoleServerPortForm
     template_name = 'dcim/device_component_add.html'
@@ -1319,9 +1308,8 @@ class PowerPortListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class PowerPortCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_powerport'
-    model = PowerPort
+class PowerPortCreateView(ComponentCreateView):
+    queryset = PowerPort.objects.all()
     form = forms.PowerPortCreateForm
     model_form = forms.PowerPortForm
     template_name = 'dcim/device_component_add.html'
@@ -1369,9 +1357,8 @@ class PowerOutletListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class PowerOutletCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_poweroutlet'
-    model = PowerOutlet
+class PowerOutletCreateView(ComponentCreateView):
+    queryset = PowerOutlet.objects.all()
     form = forms.PowerOutletCreateForm
     model_form = forms.PowerOutletForm
     template_name = 'dcim/device_component_add.html'
@@ -1465,9 +1452,8 @@ class InterfaceView(ObjectView):
         })
 
 
-class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_interface'
-    model = Interface
+class InterfaceCreateView(ComponentCreateView):
+    queryset = Interface.objects.all()
     form = forms.InterfaceCreateForm
     model_form = forms.InterfaceForm
     template_name = 'dcim/device_component_add.html'
@@ -1526,9 +1512,8 @@ class FrontPortListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class FrontPortCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_frontport'
-    model = FrontPort
+class FrontPortCreateView(ComponentCreateView):
+    queryset = FrontPort.objects.all()
     form = forms.FrontPortCreateForm
     model_form = forms.FrontPortForm
     template_name = 'dcim/device_component_add.html'
@@ -1586,9 +1571,8 @@ class RearPortListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class RearPortCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_rearport'
-    model = RearPort
+class RearPortCreateView(ComponentCreateView):
+    queryset = RearPort.objects.all()
     form = forms.RearPortCreateForm
     model_form = forms.RearPortForm
     template_name = 'dcim/device_component_add.html'
@@ -1648,9 +1632,8 @@ class DeviceBayListView(ObjectListView):
     action_buttons = ('import', 'export')
 
 
-class DeviceBayCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_devicebay'
-    model = DeviceBay
+class DeviceBayCreateView(ComponentCreateView):
+    queryset = DeviceBay.objects.all()
     form = forms.DeviceBayCreateForm
     model_form = forms.DeviceBayForm
     template_name = 'dcim/device_component_add.html'
@@ -2144,9 +2127,8 @@ class InventoryItemEditView(ObjectEditView):
     model_form = forms.InventoryItemForm
 
 
-class InventoryItemCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_inventoryitem'
-    model = InventoryItem
+class InventoryItemCreateView(ComponentCreateView):
+    queryset = InventoryItem.objects.all()
     form = forms.InventoryItemCreateForm
     model_form = forms.InventoryItemForm
     template_name = 'dcim/device_component_add.html'

+ 34 - 15
netbox/utilities/views.py

@@ -1033,28 +1033,32 @@ class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
 #
 
 # TODO: Replace with BulkCreateView
-class ComponentCreateView(GetReturnURLMixin, View):
+class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
     """
     Add one or more components (e.g. interfaces, console ports, etc.) to a Device or VirtualMachine.
     """
-    model = None
+    queryset = None
     form = None
     model_form = None
     template_name = None
 
+    def get_required_permission(self):
+        return get_permission_for_model(self.queryset.model, 'add')
+
     def get(self, request):
 
         form = self.form(initial=request.GET)
 
         return render(request, self.template_name, {
-            'component_type': self.model._meta.verbose_name,
+            'component_type': self.queryset.model._meta.verbose_name,
             'form': form,
             'return_url': self.get_return_url(request),
         })
 
     def post(self, request):
-
+        logger = logging.getLogger('netbox.views.ComponentCreateView')
         form = self.form(request.POST, initial=request.GET)
+
         if form.is_valid():
 
             new_components = []
@@ -1080,20 +1084,35 @@ class ComponentCreateView(GetReturnURLMixin, View):
 
             if not form.errors:
 
-                # Create the new components
-                for component_form in new_components:
-                    component_form.save()
+                try:
 
-                messages.success(request, "Added {} {}".format(
-                    len(new_components), self.model._meta.verbose_name_plural
-                ))
-                if '_addanother' in request.POST:
-                    return redirect(request.get_full_path())
-                else:
-                    return redirect(self.get_return_url(request))
+                    with transaction.atomic():
+
+                        # Create the new components
+                        new_objs = []
+                        for component_form in new_components:
+                            obj = component_form.save()
+                            new_objs.append(obj)
+
+                        # Enforce object-level permissions
+                        if self.queryset.filter(pk__in=[obj.pk for obj in new_objs]).count() != len(new_objs):
+                            raise ObjectDoesNotExist
+
+                    messages.success(request, "Added {} {}".format(
+                        len(new_components), self.queryset.model._meta.verbose_name_plural
+                    ))
+                    if '_addanother' in request.POST:
+                        return redirect(request.get_full_path())
+                    else:
+                        return redirect(self.get_return_url(request))
+
+                except ObjectDoesNotExist:
+                    msg = "Component creation failed due to object-level permissions violation"
+                    logger.debug(msg)
+                    form.add_error(None, msg)
 
         return render(request, self.template_name, {
-            'component_type': self.model._meta.verbose_name,
+            'component_type': self.queryset.model._meta.verbose_name,
             'form': form,
             'return_url': self.get_return_url(request),
         })

+ 2 - 3
netbox/virtualization/views.py

@@ -293,9 +293,8 @@ class VirtualMachineBulkDeleteView(BulkDeleteView):
 # VM interfaces
 #
 
-class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
-    permission_required = 'dcim.add_interface'
-    model = Interface
+class InterfaceCreateView(ComponentCreateView):
+    queryset = Interface.objects.all()
     form = forms.InterfaceCreateForm
     model_form = forms.InterfaceForm
     template_name = 'virtualization/virtualmachine_component_add.html'