diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 29d5498c6..0f5ea01a9 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1747,96 +1747,88 @@ class DeviceBayBulkDeleteView(BulkDeleteView): # Bulk Device component creation # -class DeviceBulkAddConsolePortView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_consoleport' +class DeviceBulkAddConsolePortView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.ConsolePortBulkCreateForm - model = ConsolePort + queryset = ConsolePort.objects.all() model_form = forms.ConsolePortForm filterset = filters.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' -class DeviceBulkAddConsoleServerPortView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_consoleserverport' +class DeviceBulkAddConsoleServerPortView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.ConsoleServerPortBulkCreateForm - model = ConsoleServerPort + queryset = ConsoleServerPort.objects.all() model_form = forms.ConsoleServerPortForm filterset = filters.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' -class DeviceBulkAddPowerPortView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_powerport' +class DeviceBulkAddPowerPortView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.PowerPortBulkCreateForm - model = PowerPort + queryset = PowerPort.objects.all() model_form = forms.PowerPortForm filterset = filters.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' -class DeviceBulkAddPowerOutletView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_poweroutlet' +class DeviceBulkAddPowerOutletView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.PowerOutletBulkCreateForm - model = PowerOutlet + queryset = PowerOutlet.objects.all() model_form = forms.PowerOutletForm filterset = filters.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' -class DeviceBulkAddInterfaceView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_interface' +class DeviceBulkAddInterfaceView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.InterfaceBulkCreateForm - model = Interface + queryset = Interface.objects.all() model_form = forms.InterfaceForm filterset = filters.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' -# class DeviceBulkAddFrontPortView(PermissionRequiredMixin, BulkComponentCreateView): -# permission_required = 'dcim.add_frontport' +# class DeviceBulkAddFrontPortView(BulkComponentCreateView): # parent_model = Device # parent_field = 'device' # form = forms.FrontPortBulkCreateForm -# model = FrontPort +# queryset = FrontPort.objects.all() # model_form = forms.FrontPortForm # filterset = filters.DeviceFilterSet # table = tables.DeviceTable # default_return_url = 'dcim:device_list' -class DeviceBulkAddRearPortView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_rearport' +class DeviceBulkAddRearPortView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.RearPortBulkCreateForm - model = RearPort + queryset = RearPort.objects.all() model_form = forms.RearPortForm filterset = filters.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' -class DeviceBulkAddDeviceBayView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_devicebay' +class DeviceBulkAddDeviceBayView(BulkComponentCreateView): parent_model = Device parent_field = 'device' form = forms.DeviceBayBulkCreateForm - model = DeviceBay + queryset = DeviceBay.objects.all() model_form = forms.DeviceBayForm filterset = filters.DeviceFilterSet table = tables.DeviceTable diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index c008b0501..87f63678a 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -1118,14 +1118,14 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View }) -class BulkComponentCreateView(GetReturnURLMixin, View): +class BulkComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): """ Add one or more components (e.g. interfaces, console ports, etc.) to a set of Devices or VirtualMachines. """ parent_model = None parent_field = None form = None - model = None + queryset = None model_form = None filterset = None table = None @@ -1134,7 +1134,7 @@ class BulkComponentCreateView(GetReturnURLMixin, View): def post(self, request): logger = logging.getLogger('netbox.views.BulkComponentCreateView') parent_model_name = self.parent_model._meta.verbose_name_plural - model_name = self.model._meta.verbose_name_plural + model_name = self.queryset.model._meta.verbose_name_plural # Are we editing *all* objects in the queryset or just a selected subset? if request.POST.get('_all') and self.filterset is not None: @@ -1179,9 +1179,18 @@ class BulkComponentCreateView(GetReturnURLMixin, View): for e in errors: form.add_error(field, '{} {}: {}'.format(obj, name, ', '.join(e))) + # Enforce object-level permissions + if self.queryset.filter(pk__in=[obj.pk for obj in new_components]).count() != len(new_components): + raise ObjectDoesNotExist + except IntegrityError: pass + except ObjectDoesNotExist: + msg = "Component creation failed due to object-level permissions violation" + logger.debug(msg) + form.add_error(None, msg) + if not form.errors: msg = "Added {} {} to {} {}.".format( len(new_components), diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index f7cf523d9..e6d4f4946 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -325,12 +325,11 @@ class InterfaceBulkDeleteView(BulkDeleteView): # Bulk Device component creation # -class VirtualMachineBulkAddInterfaceView(PermissionRequiredMixin, BulkComponentCreateView): - permission_required = 'dcim.add_interface' +class VirtualMachineBulkAddInterfaceView(BulkComponentCreateView): parent_model = VirtualMachine parent_field = 'virtual_machine' form = forms.InterfaceBulkCreateForm - model = Interface + queryset = Interface.objects.all() model_form = forms.InterfaceForm filterset = filters.VirtualMachineFilterSet table = tables.VirtualMachineTable