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

Transition ObjectListView to use ObjectPermissionRequiredMixin

Jeremy Stretch пре 5 година
родитељ
комит
993ee8c900

+ 3 - 6
netbox/circuits/views.py

@@ -23,8 +23,7 @@ from .models import Circuit, CircuitTermination, CircuitType, Provider
 # Providers
 # Providers
 #
 #
 
 
-class ProviderListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'circuits.view_provider'
+class ProviderListView(ObjectListView):
     queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
     queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
     filterset = filters.ProviderFilterSet
     filterset = filters.ProviderFilterSet
     filterset_form = forms.ProviderFilterForm
     filterset_form = forms.ProviderFilterForm
@@ -107,8 +106,7 @@ class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Circuit Types
 # Circuit Types
 #
 #
 
 
-class CircuitTypeListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'circuits.view_circuittype'
+class CircuitTypeListView(ObjectListView):
     queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
     queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
     table = tables.CircuitTypeTable
     table = tables.CircuitTypeTable
 
 
@@ -143,8 +141,7 @@ class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Circuits
 # Circuits
 #
 #
 
 
-class CircuitListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'circuits.view_circuit'
+class CircuitListView(ObjectListView):
     _terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))
     _terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))
     queryset = Circuit.objects.prefetch_related(
     queryset = Circuit.objects.prefetch_related(
         'provider', 'type', 'tenant', 'terminations__site'
         'provider', 'type', 'tenant', 'terminations__site'

+ 27 - 52
netbox/dcim/views.py

@@ -141,8 +141,7 @@ class BulkDisconnectView(GetReturnURLMixin, View):
 # Regions
 # Regions
 #
 #
 
 
-class RegionListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_region'
+class RegionListView(ObjectListView):
     queryset = Region.objects.add_related_count(
     queryset = Region.objects.add_related_count(
         Region.objects.all(),
         Region.objects.all(),
         Site,
         Site,
@@ -186,8 +185,7 @@ class RegionBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Sites
 # Sites
 #
 #
 
 
-class SiteListView(ObjectPermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_site'
+class SiteListView(ObjectListView):
     queryset = Site.objects.prefetch_related('region', 'tenant')
     queryset = Site.objects.prefetch_related('region', 'tenant')
     filterset = filters.SiteFilterSet
     filterset = filters.SiteFilterSet
     filterset_form = forms.SiteFilterForm
     filterset_form = forms.SiteFilterForm
@@ -267,8 +265,7 @@ class SiteBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Rack groups
 # Rack groups
 #
 #
 
 
-class RackGroupListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_rackgroup'
+class RackGroupListView(ObjectListView):
     queryset = RackGroup.objects.add_related_count(
     queryset = RackGroup.objects.add_related_count(
         RackGroup.objects.all(),
         RackGroup.objects.all(),
         Rack,
         Rack,
@@ -312,8 +309,7 @@ class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Rack roles
 # Rack roles
 #
 #
 
 
-class RackRoleListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_rackrole'
+class RackRoleListView(ObjectListView):
     queryset = RackRole.objects.annotate(rack_count=Count('racks'))
     queryset = RackRole.objects.annotate(rack_count=Count('racks'))
     table = tables.RackRoleTable
     table = tables.RackRoleTable
 
 
@@ -348,8 +344,7 @@ class RackRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Racks
 # Racks
 #
 #
 
 
-class RackListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_rack'
+class RackListView(ObjectListView):
     queryset = Rack.objects.prefetch_related(
     queryset = Rack.objects.prefetch_related(
         'site', 'group', 'tenant', 'role', 'devices__device_type'
         'site', 'group', 'tenant', 'role', 'devices__device_type'
     ).annotate(
     ).annotate(
@@ -476,8 +471,7 @@ class RackBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Rack reservations
 # Rack reservations
 #
 #
 
 
-class RackReservationListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_rackreservation'
+class RackReservationListView(ObjectListView):
     queryset = RackReservation.objects.prefetch_related('rack__site')
     queryset = RackReservation.objects.prefetch_related('rack__site')
     filterset = filters.RackReservationFilterSet
     filterset = filters.RackReservationFilterSet
     filterset_form = forms.RackReservationFilterForm
     filterset_form = forms.RackReservationFilterForm
@@ -561,8 +555,7 @@ class RackReservationBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Manufacturers
 # Manufacturers
 #
 #
 
 
-class ManufacturerListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_manufacturer'
+class ManufacturerListView(ObjectListView):
     queryset = Manufacturer.objects.annotate(
     queryset = Manufacturer.objects.annotate(
         devicetype_count=Count('device_types', distinct=True),
         devicetype_count=Count('device_types', distinct=True),
         inventoryitem_count=Count('inventory_items', distinct=True),
         inventoryitem_count=Count('inventory_items', distinct=True),
@@ -601,8 +594,7 @@ class ManufacturerBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Device types
 # Device types
 #
 #
 
 
-class DeviceTypeListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_devicetype'
+class DeviceTypeListView(ObjectListView):
     queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances'))
     queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances'))
     filterset = filters.DeviceTypeFilterSet
     filterset = filters.DeviceTypeFilterSet
     filterset_form = forms.DeviceTypeFilterForm
     filterset_form = forms.DeviceTypeFilterForm
@@ -1026,8 +1018,7 @@ class DeviceBayTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Device roles
 # Device roles
 #
 #
 
 
-class DeviceRoleListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_devicerole'
+class DeviceRoleListView(ObjectListView):
     queryset = DeviceRole.objects.all()
     queryset = DeviceRole.objects.all()
     table = tables.DeviceRoleTable
     table = tables.DeviceRoleTable
 
 
@@ -1062,8 +1053,7 @@ class DeviceRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Platforms
 # Platforms
 #
 #
 
 
-class PlatformListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_platform'
+class PlatformListView(ObjectListView):
     queryset = Platform.objects.all()
     queryset = Platform.objects.all()
     table = tables.PlatformTable
     table = tables.PlatformTable
 
 
@@ -1098,8 +1088,7 @@ class PlatformBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Devices
 # Devices
 #
 #
 
 
-class DeviceListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_device'
+class DeviceListView(ObjectListView):
     queryset = Device.objects.prefetch_related(
     queryset = Device.objects.prefetch_related(
         'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6'
         'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6'
     )
     )
@@ -1323,8 +1312,7 @@ class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Console ports
 # Console ports
 #
 #
 
 
-class ConsolePortListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_consoleport'
+class ConsolePortListView(ObjectListView):
     queryset = ConsolePort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = ConsolePort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.ConsolePortFilterSet
     filterset = filters.ConsolePortFilterSet
     filterset_form = forms.ConsolePortFilterForm
     filterset_form = forms.ConsolePortFilterForm
@@ -1379,8 +1367,7 @@ class ConsolePortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Console server ports
 # Console server ports
 #
 #
 
 
-class ConsoleServerPortListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_consoleserverport'
+class ConsoleServerPortListView(ObjectListView):
     queryset = ConsoleServerPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = ConsoleServerPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.ConsoleServerPortFilterSet
     filterset = filters.ConsoleServerPortFilterSet
     filterset_form = forms.ConsoleServerPortFilterForm
     filterset_form = forms.ConsoleServerPortFilterForm
@@ -1447,8 +1434,7 @@ class ConsoleServerPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Power ports
 # Power ports
 #
 #
 
 
-class PowerPortListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_powerport'
+class PowerPortListView(ObjectListView):
     queryset = PowerPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = PowerPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.PowerPortFilterSet
     filterset = filters.PowerPortFilterSet
     filterset_form = forms.PowerPortFilterForm
     filterset_form = forms.PowerPortFilterForm
@@ -1503,8 +1489,7 @@ class PowerPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Power outlets
 # Power outlets
 #
 #
 
 
-class PowerOutletListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_poweroutlet'
+class PowerOutletListView(ObjectListView):
     queryset = PowerOutlet.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = PowerOutlet.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.PowerOutletFilterSet
     filterset = filters.PowerOutletFilterSet
     filterset_form = forms.PowerOutletFilterForm
     filterset_form = forms.PowerOutletFilterForm
@@ -1571,8 +1556,7 @@ class PowerOutletBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Interfaces
 # Interfaces
 #
 #
 
 
-class InterfaceListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_interface'
+class InterfaceListView(ObjectListView):
     queryset = Interface.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = Interface.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.InterfaceFilterSet
     filterset = filters.InterfaceFilterSet
     filterset_form = forms.InterfaceFilterForm
     filterset_form = forms.InterfaceFilterForm
@@ -1676,8 +1660,7 @@ class InterfaceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Front ports
 # Front ports
 #
 #
 
 
-class FrontPortListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_frontport'
+class FrontPortListView(ObjectListView):
     queryset = FrontPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = FrontPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.FrontPortFilterSet
     filterset = filters.FrontPortFilterSet
     filterset_form = forms.FrontPortFilterForm
     filterset_form = forms.FrontPortFilterForm
@@ -1744,8 +1727,7 @@ class FrontPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Rear ports
 # Rear ports
 #
 #
 
 
-class RearPortListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_rearport'
+class RearPortListView(ObjectListView):
     queryset = RearPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     queryset = RearPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable')
     filterset = filters.RearPortFilterSet
     filterset = filters.RearPortFilterSet
     filterset_form = forms.RearPortFilterForm
     filterset_form = forms.RearPortFilterForm
@@ -1812,8 +1794,7 @@ class RearPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Device bays
 # Device bays
 #
 #
 
 
-class DeviceBayListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_devicebay'
+class DeviceBayListView(ObjectListView):
     queryset = DeviceBay.objects.prefetch_related(
     queryset = DeviceBay.objects.prefetch_related(
         'device', 'device__site', 'installed_device', 'installed_device__site'
         'device', 'device__site', 'installed_device', 'installed_device__site'
     )
     )
@@ -2045,8 +2026,7 @@ class DeviceBulkAddDeviceBayView(PermissionRequiredMixin, BulkComponentCreateVie
 # Cables
 # Cables
 #
 #
 
 
-class CableListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_cable'
+class CableListView(ObjectListView):
     queryset = Cable.objects.prefetch_related(
     queryset = Cable.objects.prefetch_related(
         'termination_a', 'termination_b'
         'termination_a', 'termination_b'
     )
     )
@@ -2215,7 +2195,7 @@ class CableBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Connections
 # Connections
 #
 #
 
 
-class ConsoleConnectionsListView(PermissionRequiredMixin, ObjectListView):
+class ConsoleConnectionsListView(ObjectListView):
     permission_required = ('dcim.view_consoleport', 'dcim.view_consoleserverport')
     permission_required = ('dcim.view_consoleport', 'dcim.view_consoleserverport')
     queryset = ConsolePort.objects.prefetch_related(
     queryset = ConsolePort.objects.prefetch_related(
         'device', 'connected_endpoint__device'
         'device', 'connected_endpoint__device'
@@ -2247,7 +2227,7 @@ class ConsoleConnectionsListView(PermissionRequiredMixin, ObjectListView):
         return '\n'.join(csv_data)
         return '\n'.join(csv_data)
 
 
 
 
-class PowerConnectionsListView(PermissionRequiredMixin, ObjectListView):
+class PowerConnectionsListView(ObjectListView):
     permission_required = ('dcim.view_powerport', 'dcim.view_poweroutlet')
     permission_required = ('dcim.view_powerport', 'dcim.view_poweroutlet')
     queryset = PowerPort.objects.prefetch_related(
     queryset = PowerPort.objects.prefetch_related(
         'device', '_connected_poweroutlet__device'
         'device', '_connected_poweroutlet__device'
@@ -2279,8 +2259,7 @@ class PowerConnectionsListView(PermissionRequiredMixin, ObjectListView):
         return '\n'.join(csv_data)
         return '\n'.join(csv_data)
 
 
 
 
-class InterfaceConnectionsListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_interface'
+class InterfaceConnectionsListView(ObjectListView):
     queryset = Interface.objects.prefetch_related(
     queryset = Interface.objects.prefetch_related(
         'device', 'cable', '_connected_interface__device'
         'device', 'cable', '_connected_interface__device'
     ).filter(
     ).filter(
@@ -2319,8 +2298,7 @@ class InterfaceConnectionsListView(PermissionRequiredMixin, ObjectListView):
 # Inventory items
 # Inventory items
 #
 #
 
 
-class InventoryItemListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_inventoryitem'
+class InventoryItemListView(ObjectListView):
     queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
     queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
     filterset = filters.InventoryItemFilterSet
     filterset = filters.InventoryItemFilterSet
     filterset_form = forms.InventoryItemFilterForm
     filterset_form = forms.InventoryItemFilterForm
@@ -2376,8 +2354,7 @@ class InventoryItemBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Virtual chassis
 # Virtual chassis
 #
 #
 
 
-class VirtualChassisListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_virtualchassis'
+class VirtualChassisListView(ObjectListView):
     queryset = VirtualChassis.objects.prefetch_related('master').annotate(member_count=Count('members'))
     queryset = VirtualChassis.objects.prefetch_related('master').annotate(member_count=Count('members'))
     table = tables.VirtualChassisTable
     table = tables.VirtualChassisTable
     filterset = filters.VirtualChassisFilterSet
     filterset = filters.VirtualChassisFilterSet
@@ -2644,8 +2621,7 @@ class VirtualChassisBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Power panels
 # Power panels
 #
 #
 
 
-class PowerPanelListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_powerpanel'
+class PowerPanelListView(ObjectListView):
     queryset = PowerPanel.objects.prefetch_related(
     queryset = PowerPanel.objects.prefetch_related(
         'site', 'rack_group'
         'site', 'rack_group'
     ).annotate(
     ).annotate(
@@ -2724,8 +2700,7 @@ class PowerPanelBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Power feeds
 # Power feeds
 #
 #
 
 
-class PowerFeedListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'dcim.view_powerfeed'
+class PowerFeedListView(ObjectListView):
     queryset = PowerFeed.objects.prefetch_related(
     queryset = PowerFeed.objects.prefetch_related(
         'power_panel', 'rack'
         'power_panel', 'rack'
     )
     )

+ 3 - 6
netbox/extras/views.py

@@ -25,8 +25,7 @@ from .tables import ConfigContextTable, ObjectChangeTable, TagTable, TaggedItemT
 # Tags
 # Tags
 #
 #
 
 
-class TagListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'extras.view_tag'
+class TagListView(ObjectListView):
     queryset = Tag.objects.annotate(
     queryset = Tag.objects.annotate(
         items=Count('extras_taggeditem_items', distinct=True)
         items=Count('extras_taggeditem_items', distinct=True)
     ).order_by(
     ).order_by(
@@ -106,8 +105,7 @@ class TagBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Config contexts
 # Config contexts
 #
 #
 
 
-class ConfigContextListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'extras.view_configcontext'
+class ConfigContextListView(ObjectListView):
     queryset = ConfigContext.objects.all()
     queryset = ConfigContext.objects.all()
     filterset = filters.ConfigContextFilterSet
     filterset = filters.ConfigContextFilterSet
     filterset_form = forms.ConfigContextFilterForm
     filterset_form = forms.ConfigContextFilterForm
@@ -200,8 +198,7 @@ class ObjectConfigContextView(View):
 # Change logging
 # Change logging
 #
 #
 
 
-class ObjectChangeListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'extras.view_objectchange'
+class ObjectChangeListView(ObjectListView):
     queryset = ObjectChange.objects.prefetch_related('user', 'changed_object_type')
     queryset = ObjectChange.objects.prefetch_related('user', 'changed_object_type')
     filterset = filters.ObjectChangeFilterSet
     filterset = filters.ObjectChangeFilterSet
     filterset_form = forms.ObjectChangeFilterForm
     filterset_form = forms.ObjectChangeFilterForm

+ 9 - 18
netbox/ipam/views.py

@@ -113,8 +113,7 @@ def add_available_vlans(vlan_group, vlans):
 # VRFs
 # VRFs
 #
 #
 
 
-class VRFListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_vrf'
+class VRFListView(ObjectListView):
     queryset = VRF.objects.prefetch_related('tenant')
     queryset = VRF.objects.prefetch_related('tenant')
     filterset = filters.VRFFilterSet
     filterset = filters.VRFFilterSet
     filterset_form = forms.VRFFilterForm
     filterset_form = forms.VRFFilterForm
@@ -182,8 +181,7 @@ class VRFBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # RIRs
 # RIRs
 #
 #
 
 
-class RIRListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_rir'
+class RIRListView(ObjectListView):
     queryset = RIR.objects.annotate(aggregate_count=Count('aggregates'))
     queryset = RIR.objects.annotate(aggregate_count=Count('aggregates'))
     filterset = filters.RIRFilterSet
     filterset = filters.RIRFilterSet
     filterset_form = forms.RIRFilterForm
     filterset_form = forms.RIRFilterForm
@@ -290,8 +288,7 @@ class RIRBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Aggregates
 # Aggregates
 #
 #
 
 
-class AggregateListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_aggregate'
+class AggregateListView(ObjectListView):
     queryset = Aggregate.objects.prefetch_related('rir').annotate(
     queryset = Aggregate.objects.prefetch_related('rir').annotate(
         child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
         child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
     )
     )
@@ -409,8 +406,7 @@ class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Prefix/VLAN roles
 # Prefix/VLAN roles
 #
 #
 
 
-class RoleListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_role'
+class RoleListView(ObjectListView):
     queryset = Role.objects.all()
     queryset = Role.objects.all()
     table = tables.RoleTable
     table = tables.RoleTable
 
 
@@ -445,8 +441,7 @@ class RoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Prefixes
 # Prefixes
 #
 #
 
 
-class PrefixListView(ObjectPermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_prefix'
+class PrefixListView(ObjectListView):
     queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
     queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
     filterset = filters.PrefixFilterSet
     filterset = filters.PrefixFilterSet
     filterset_form = forms.PrefixFilterForm
     filterset_form = forms.PrefixFilterForm
@@ -638,8 +633,7 @@ class PrefixBulkDeleteView(ObjectPermissionRequiredMixin, BulkDeleteView):
 # IP addresses
 # IP addresses
 #
 #
 
 
-class IPAddressListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_ipaddress'
+class IPAddressListView(ObjectListView):
     queryset = IPAddress.objects.prefetch_related(
     queryset = IPAddress.objects.prefetch_related(
         'vrf__tenant', 'tenant', 'nat_inside', 'interface__device', 'interface__virtual_machine'
         'vrf__tenant', 'tenant', 'nat_inside', 'interface__device', 'interface__virtual_machine'
     )
     )
@@ -813,8 +807,7 @@ class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # VLAN groups
 # VLAN groups
 #
 #
 
 
-class VLANGroupListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_vlangroup'
+class VLANGroupListView(ObjectListView):
     queryset = VLANGroup.objects.prefetch_related('site').annotate(vlan_count=Count('vlans'))
     queryset = VLANGroup.objects.prefetch_related('site').annotate(vlan_count=Count('vlans'))
     filterset = filters.VLANGroupFilterSet
     filterset = filters.VLANGroupFilterSet
     filterset_form = forms.VLANGroupFilterForm
     filterset_form = forms.VLANGroupFilterForm
@@ -889,8 +882,7 @@ class VLANGroupVLANsView(PermissionRequiredMixin, View):
 # VLANs
 # VLANs
 #
 #
 
 
-class VLANListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_vlan'
+class VLANListView(ObjectListView):
     queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role').prefetch_related('prefixes')
     queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role').prefetch_related('prefixes')
     filterset = filters.VLANFilterSet
     filterset = filters.VLANFilterSet
     filterset_form = forms.VLANFilterForm
     filterset_form = forms.VLANFilterForm
@@ -985,8 +977,7 @@ class VLANBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Services
 # Services
 #
 #
 
 
-class ServiceListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'ipam.view_service'
+class ServiceListView(ObjectListView):
     queryset = Service.objects.prefetch_related('device', 'virtual_machine')
     queryset = Service.objects.prefetch_related('device', 'virtual_machine')
     filterset = filters.ServiceFilterSet
     filterset = filters.ServiceFilterSet
     filterset_form = forms.ServiceFilterForm
     filterset_form = forms.ServiceFilterForm

+ 2 - 4
netbox/secrets/views.py

@@ -30,8 +30,7 @@ def get_session_key(request):
 # Secret roles
 # Secret roles
 #
 #
 
 
-class SecretRoleListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'secrets.view_secretrole'
+class SecretRoleListView(ObjectListView):
     queryset = SecretRole.objects.annotate(secret_count=Count('secrets'))
     queryset = SecretRole.objects.annotate(secret_count=Count('secrets'))
     table = tables.SecretRoleTable
     table = tables.SecretRoleTable
 
 
@@ -66,8 +65,7 @@ class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Secrets
 # Secrets
 #
 #
 
 
-class SecretListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'secrets.view_secret'
+class SecretListView(ObjectListView):
     queryset = Secret.objects.prefetch_related('role', 'device')
     queryset = Secret.objects.prefetch_related('role', 'device')
     filterset = filters.SecretFilterSet
     filterset = filters.SecretFilterSet
     filterset_form = forms.SecretFilterForm
     filterset_form = forms.SecretFilterForm

+ 2 - 4
netbox/tenancy/views.py

@@ -18,8 +18,7 @@ from .models import Tenant, TenantGroup
 # Tenant groups
 # Tenant groups
 #
 #
 
 
-class TenantGroupListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'tenancy.view_tenantgroup'
+class TenantGroupListView(ObjectListView):
     queryset = TenantGroup.objects.add_related_count(
     queryset = TenantGroup.objects.add_related_count(
         TenantGroup.objects.all(),
         TenantGroup.objects.all(),
         Tenant,
         Tenant,
@@ -60,8 +59,7 @@ class TenantGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 #  Tenants
 #  Tenants
 #
 #
 
 
-class TenantListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'tenancy.view_tenant'
+class TenantListView(ObjectListView):
     queryset = Tenant.objects.prefetch_related('group')
     queryset = Tenant.objects.prefetch_related('group')
     filterset = filters.TenantFilterSet
     filterset = filters.TenantFilterSet
     filterset_form = forms.TenantFilterForm
     filterset_form = forms.TenantFilterForm

+ 19 - 14
netbox/utilities/views.py

@@ -27,6 +27,7 @@ from extras.querysets import CustomFieldQueryset
 from users.models import ObjectPermission
 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.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
@@ -45,11 +46,15 @@ class ObjectPermissionRequiredMixin(AccessMixin):
     """
     """
     permission_required = None
     permission_required = None
 
 
+    def get_required_permission(self):
+        return self.permission_required
+
     def has_permission(self):
     def has_permission(self):
         user = self.request.user
         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.
         # 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):
+        if not user.has_perm(permission_required):
             return False
             return False
 
 
         # Superusers implicitly have all permissions
         # Superusers implicitly have all permissions
@@ -58,23 +63,18 @@ class ObjectPermissionRequiredMixin(AccessMixin):
 
 
         # Determine whether the permission is model-level or object-level. Model-level permissions grant the
         # 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.
         # specified action to *all* objects, so no further action is needed.
-        if self.permission_required in {*user._user_perm_cache, *user._group_perm_cache}:
+        if permission_required in {*user._user_perm_cache, *user._group_perm_cache}:
             return True
             return True
 
 
         # If the permission is granted only at the object level, filter the view's queryset to return only objects
         # 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.
         # on which the user is permitted to perform the specified action.
-        attrs = ObjectPermission.objects.get_attr_constraints(user, self.permission_required)
+        attrs = ObjectPermission.objects.get_attr_constraints(user, permission_required)
         if attrs:
         if attrs:
             # Update the view's QuerySet to filter only the permitted objects
             # Update the view's QuerySet to filter only the permitted objects
             self.queryset = self.queryset.filter(attrs)
             self.queryset = self.queryset.filter(attrs)
             return True
             return True
 
 
     def dispatch(self, request, *args, **kwargs):
     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'):
         if not hasattr(self, 'queryset'):
             raise ImproperlyConfigured(
             raise ImproperlyConfigured(
@@ -118,15 +118,15 @@ class GetReturnURLMixin(object):
 # Generic views
 # Generic views
 #
 #
 
 
-class ObjectListView(View):
+class ObjectListView(ObjectPermissionRequiredMixin, View):
     """
     """
     List a series of objects.
     List a series of objects.
 
 
-    queryset: The queryset of objects to display
-    filter: A django-filter FilterSet that is applied to the queryset
-    filter_form: The form used to render filter options
-    table: The django-tables2 Table used to render the objects list
-    template_name: The name of the template
+    :param queryset: The queryset of objects to display
+    :param filter: A django-filter FilterSet that is applied to the queryset
+    :param filter_form: The form used to render filter options
+    :param table: The django-tables2 Table used to render the objects list
+    :param template_name: The name of the template
     """
     """
     queryset = None
     queryset = None
     filterset = None
     filterset = None
@@ -135,6 +135,11 @@ class ObjectListView(View):
     template_name = 'utilities/obj_list.html'
     template_name = 'utilities/obj_list.html'
     action_buttons = ('add', 'import', 'export')
     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):
     def queryset_to_yaml(self):
         """
         """
         Export the queryset of objects as concatenated YAML documents.
         Export the queryset of objects as concatenated YAML documents.

+ 4 - 8
netbox/virtualization/views.py

@@ -22,8 +22,7 @@ from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 # Cluster types
 # Cluster types
 #
 #
 
 
-class ClusterTypeListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'virtualization.view_clustertype'
+class ClusterTypeListView(ObjectListView):
     queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
     queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
     table = tables.ClusterTypeTable
     table = tables.ClusterTypeTable
 
 
@@ -58,8 +57,7 @@ class ClusterTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Cluster groups
 # Cluster groups
 #
 #
 
 
-class ClusterGroupListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'virtualization.view_clustergroup'
+class ClusterGroupListView(ObjectListView):
     queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
     queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
     table = tables.ClusterGroupTable
     table = tables.ClusterGroupTable
 
 
@@ -94,8 +92,7 @@ class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Clusters
 # Clusters
 #
 #
 
 
-class ClusterListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'virtualization.view_cluster'
+class ClusterListView(ObjectListView):
     queryset = Cluster.objects.prefetch_related('type', 'group', 'site', 'tenant')
     queryset = Cluster.objects.prefetch_related('type', 'group', 'site', 'tenant')
     table = tables.ClusterTable
     table = tables.ClusterTable
     filterset = filters.ClusterFilterSet
     filterset = filters.ClusterFilterSet
@@ -251,8 +248,7 @@ class ClusterRemoveDevicesView(PermissionRequiredMixin, View):
 # Virtual machines
 # Virtual machines
 #
 #
 
 
-class VirtualMachineListView(PermissionRequiredMixin, ObjectListView):
-    permission_required = 'virtualization.view_virtualmachine'
+class VirtualMachineListView(ObjectListView):
     queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
     queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
     filterset = filters.VirtualMachineFilterSet
     filterset = filters.VirtualMachineFilterSet
     filterset_form = forms.VirtualMachineFilterForm
     filterset_form = forms.VirtualMachineFilterForm