From 5d5d4ac7148d265a20179546be32341d33469033 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 26 Jan 2017 13:20:56 -0500 Subject: [PATCH 1/3] Fixes #845: Fix missing edit/delete buttons on object tables for non-superusers --- netbox/circuits/views.py | 3 --- netbox/dcim/views.py | 9 --------- netbox/ipam/views.py | 8 -------- netbox/secrets/views.py | 2 -- netbox/templates/ipam/ipaddress_list.html | 1 - netbox/templates/utilities/obj_table.html | 10 +++++----- netbox/tenancy/views.py | 2 -- netbox/utilities/tables.py | 4 ---- netbox/utilities/templatetags/helpers.py | 18 ------------------ netbox/utilities/views.py | 9 ++++++--- 10 files changed, 11 insertions(+), 55 deletions(-) diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index c5fae7384..c85fad1a1 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -25,7 +25,6 @@ class ProviderListView(ObjectListView): filter = filters.ProviderFilter filter_form = forms.ProviderFilterForm table = tables.ProviderTable - edit_permissions = ['circuits.change_provider', 'circuits.delete_provider'] template_name = 'circuits/provider_list.html' @@ -87,7 +86,6 @@ class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class CircuitTypeListView(ObjectListView): queryset = CircuitType.objects.annotate(circuit_count=Count('circuits')) table = tables.CircuitTypeTable - edit_permissions = ['circuits.change_circuittype', 'circuits.delete_circuittype'] template_name = 'circuits/circuittype_list.html' @@ -115,7 +113,6 @@ class CircuitListView(ObjectListView): filter = filters.CircuitFilter filter_form = forms.CircuitFilterForm table = tables.CircuitTable - edit_permissions = ['circuits.change_circuit', 'circuits.delete_circuit'] template_name = 'circuits/circuit_list.html' diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 96c8e167e..17f74eae3 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -137,7 +137,6 @@ class SiteListView(ObjectListView): filter = filters.SiteFilter filter_form = forms.SiteFilterForm table = tables.SiteTable - edit_permissions = ['dcim.change_rack', 'dcim.delete_rack'] template_name = 'dcim/site_list.html' @@ -204,7 +203,6 @@ class RackGroupListView(ObjectListView): filter = filters.RackGroupFilter filter_form = forms.RackGroupFilterForm table = tables.RackGroupTable - edit_permissions = ['dcim.change_rackgroup', 'dcim.delete_rackgroup'] template_name = 'dcim/rackgroup_list.html' @@ -231,7 +229,6 @@ class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class RackRoleListView(ObjectListView): queryset = RackRole.objects.annotate(rack_count=Count('racks')) table = tables.RackRoleTable - edit_permissions = ['dcim.change_rackrole', 'dcim.delete_rackrole'] template_name = 'dcim/rackrole_list.html' @@ -260,7 +257,6 @@ class RackListView(ObjectListView): filter = filters.RackFilter filter_form = forms.RackFilterForm table = tables.RackTable - edit_permissions = ['dcim.change_rack', 'dcim.delete_rack'] template_name = 'dcim/rack_list.html' @@ -328,7 +324,6 @@ class RackBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class ManufacturerListView(ObjectListView): queryset = Manufacturer.objects.annotate(devicetype_count=Count('device_types')) table = tables.ManufacturerTable - edit_permissions = ['dcim.change_manufacturer', 'dcim.delete_manufacturer'] template_name = 'dcim/manufacturer_list.html' @@ -356,7 +351,6 @@ class DeviceTypeListView(ObjectListView): filter = filters.DeviceTypeFilter filter_form = forms.DeviceTypeFilterForm table = tables.DeviceTypeTable - edit_permissions = ['dcim.change_devicetype', 'dcim.delete_devicetype'] template_name = 'dcim/devicetype_list.html' @@ -550,7 +544,6 @@ class DeviceBayTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class DeviceRoleListView(ObjectListView): queryset = DeviceRole.objects.annotate(device_count=Count('devices')) table = tables.DeviceRoleTable - edit_permissions = ['dcim.change_devicerole', 'dcim.delete_devicerole'] template_name = 'dcim/devicerole_list.html' @@ -576,7 +569,6 @@ class DeviceRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class PlatformListView(ObjectListView): queryset = Platform.objects.annotate(device_count=Count('devices')) table = tables.PlatformTable - edit_permissions = ['dcim.change_platform', 'dcim.delete_platform'] template_name = 'dcim/platform_list.html' @@ -605,7 +597,6 @@ class DeviceListView(ObjectListView): filter = filters.DeviceFilter filter_form = forms.DeviceFilterForm table = tables.DeviceTable - edit_permissions = ['dcim.change_device', 'dcim.delete_device'] template_name = 'dcim/device_list.html' diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 3d2c93a1f..38c641e05 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -95,7 +95,6 @@ class VRFListView(ObjectListView): filter = filters.VRFFilter filter_form = forms.VRFFilterForm table = tables.VRFTable - edit_permissions = ['ipam.change_vrf', 'ipam.delete_vrf'] template_name = 'ipam/vrf_list.html' @@ -160,7 +159,6 @@ class RIRListView(ObjectListView): filter = filters.RIRFilter filter_form = forms.RIRFilterForm table = tables.RIRTable - edit_permissions = ['ipam.change_rir', 'ipam.delete_rir'] template_name = 'ipam/rir_list.html' def alter_queryset(self, request): @@ -267,7 +265,6 @@ class AggregateListView(ObjectListView): filter = filters.AggregateFilter filter_form = forms.AggregateFilterForm table = tables.AggregateTable - edit_permissions = ['ipam.change_aggregate', 'ipam.delete_aggregate'] template_name = 'ipam/aggregate_list.html' def extra_context(self): @@ -351,7 +348,6 @@ class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class RoleListView(ObjectListView): queryset = Role.objects.all() table = tables.RoleTable - edit_permissions = ['ipam.change_role', 'ipam.delete_role'] template_name = 'ipam/role_list.html' @@ -379,7 +375,6 @@ class PrefixListView(ObjectListView): filter = filters.PrefixFilter filter_form = forms.PrefixFilterForm table = tables.PrefixTable - edit_permissions = ['ipam.change_prefix', 'ipam.delete_prefix'] template_name = 'ipam/prefix_list.html' def alter_queryset(self, request): @@ -510,7 +505,6 @@ class IPAddressListView(ObjectListView): filter = filters.IPAddressFilter filter_form = forms.IPAddressFilterForm table = tables.IPAddressTable - edit_permissions = ['ipam.change_ipaddress', 'ipam.delete_ipaddress'] template_name = 'ipam/ipaddress_list.html' @@ -680,7 +674,6 @@ class VLANGroupListView(ObjectListView): filter = filters.VLANGroupFilter filter_form = forms.VLANGroupFilterForm table = tables.VLANGroupTable - edit_permissions = ['ipam.change_vlangroup', 'ipam.delete_vlangroup'] template_name = 'ipam/vlangroup_list.html' @@ -709,7 +702,6 @@ class VLANListView(ObjectListView): filter = filters.VLANFilter filter_form = forms.VLANFilterForm table = tables.VLANTable - edit_permissions = ['ipam.change_vlan', 'ipam.delete_vlan'] template_name = 'ipam/vlan_list.html' diff --git a/netbox/secrets/views.py b/netbox/secrets/views.py index da161ec1e..d67cd18a0 100644 --- a/netbox/secrets/views.py +++ b/netbox/secrets/views.py @@ -22,7 +22,6 @@ from .models import SecretRole, Secret, UserKey class SecretRoleListView(ObjectListView): queryset = SecretRole.objects.annotate(secret_count=Count('secrets')) table = tables.SecretRoleTable - edit_permissions = ['secrets.change_secretrole', 'secrets.delete_secretrole'] template_name = 'secrets/secretrole_list.html' @@ -51,7 +50,6 @@ class SecretListView(ObjectListView): filter = filters.SecretFilter filter_form = forms.SecretFilterForm table = tables.SecretTable - edit_permissions = ['secrets.change_secret', 'secrets.delete_secret'] template_name = 'secrets/secret_list.html' diff --git a/netbox/templates/ipam/ipaddress_list.html b/netbox/templates/ipam/ipaddress_list.html index bb442c824..ac1d980a2 100644 --- a/netbox/templates/ipam/ipaddress_list.html +++ b/netbox/templates/ipam/ipaddress_list.html @@ -1,5 +1,4 @@ {% extends '_base.html' %} -{% load render_table from django_tables2 %} {% load helpers %} {% block title %}IP Addresses{% endblock %} diff --git a/netbox/templates/utilities/obj_table.html b/netbox/templates/utilities/obj_table.html index 4458783b2..7f237632d 100644 --- a/netbox/templates/utilities/obj_table.html +++ b/netbox/templates/utilities/obj_table.html @@ -1,6 +1,6 @@ {% load render_table from django_tables2 %} {% load helpers %} -{% if table.model|user_can_change:request.user or table.model|user_can_delete:request.user %} +{% if permissions.change or permissions.delete %}
{% csrf_token %} @@ -14,12 +14,12 @@
- {% if bulk_edit_url and table.model|user_can_change:request.user %} + {% if bulk_edit_url and permissions.change %} {% endif %} - {% if bulk_delete_url and table.model|user_can_delete:request.user %} + {% if bulk_delete_url and permissions.delete %} @@ -30,12 +30,12 @@ {% endif %} {% render_table table table_template|default:'table.html' %} {% block extra_actions %}{% endblock %} - {% if bulk_edit_url and table.model|user_can_change:request.user %} + {% if bulk_edit_url and permissions.change %} {% endif %} - {% if bulk_delete_url and table.model|user_can_delete:request.user %} + {% if bulk_delete_url and permissions.delete %} diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 060e81596..f4bb05b69 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -21,7 +21,6 @@ from . import filters, forms, tables class TenantGroupListView(ObjectListView): queryset = TenantGroup.objects.annotate(tenant_count=Count('tenants')) table = tables.TenantGroupTable - edit_permissions = ['tenancy.change_tenantgroup', 'tenancy.delete_tenantgroup'] template_name = 'tenancy/tenantgroup_list.html' @@ -49,7 +48,6 @@ class TenantListView(ObjectListView): filter = filters.TenantFilter filter_form = forms.TenantFilterForm table = tables.TenantTable - edit_permissions = ['tenancy.change_tenant', 'tenancy.delete_tenant'] template_name = 'tenancy/tenant_list.html' diff --git a/netbox/utilities/tables.py b/netbox/utilities/tables.py index 9111bd976..a53227937 100644 --- a/netbox/utilities/tables.py +++ b/netbox/utilities/tables.py @@ -17,10 +17,6 @@ class BaseTable(tables.Table): 'class': 'table table-hover', } - @property - def model(self): - return self._meta.model - class ToggleColumn(tables.CheckBoxColumn): diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index f26a06488..74d490390 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -44,24 +44,6 @@ def startswith(value, arg): return str(value).startswith(arg) -@register.filter() -def user_can_add(model, user): - perm_name = '{}:add_{}'.format(model._meta.app_label, model.__class__.__name__.lower()) - return user.has_perm(perm_name) - - -@register.filter() -def user_can_change(model, user): - perm_name = '{}:change_{}'.format(model._meta.app_label, model.__class__.__name__.lower()) - return user.has_perm(perm_name) - - -@register.filter() -def user_can_delete(model, user): - perm_name = '{}:delete_{}'.format(model._meta.app_label, model.__class__.__name__.lower()) - return user.has_perm(perm_name) - - # # Tags # diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 482ce5405..2fd8123b0 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -46,14 +46,12 @@ class ObjectListView(View): 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 - edit_permissions: Editing controls are displayed only if the user has these permissions template_name: The name of the template """ queryset = None filter = None filter_form = None table = None - edit_permissions = [] template_name = None def get(self, request): @@ -95,14 +93,19 @@ class ObjectListView(View): # Provide a hook to tweak the queryset based on the request immediately prior to rendering the object list self.queryset = self.alter_queryset(request) + # Compile user model permissions for access from within the template + perm_base_name = '{}.{{}}_{}'.format(model._meta.app_label, model._meta.model_name) + permissions = {p: request.user.has_perm(perm_base_name.format(p)) for p in ['add', 'change', 'delete']} + # Construct the table based on the user's permissions table = self.table(self.queryset) - if 'pk' in table.base_columns and any([request.user.has_perm(perm) for perm in self.edit_permissions]): + if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']): table.base_columns['pk'].visible = True RequestConfig(request, paginate={'klass': EnhancedPaginator}).configure(table) context = { 'table': table, + 'permissions': permissions, 'filter_form': self.filter_form(request.GET, label_suffix='') if self.filter_form else None, 'export_templates': ExportTemplate.objects.filter(content_type=object_ct), } From b2ef7bb104e8ac4f1203b1e0d269be8753be30b4 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 26 Jan 2017 13:57:00 -0500 Subject: [PATCH 2/3] Release v1.8.3 --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index c2c893e58..d5909a960 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -12,7 +12,7 @@ except ImportError: "the documentation.") -VERSION = '1.8.3-dev' +VERSION = '1.8.3' # Import local configuration for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']: From b8b2ea7ccbe9b1132f6a22c143548d99d966e6d4 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 26 Jan 2017 14:00:08 -0500 Subject: [PATCH 3/3] Post-release version bump --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index d5909a960..f5d7df4d4 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -12,7 +12,7 @@ except ImportError: "the documentation.") -VERSION = '1.8.3' +VERSION = '1.8.4-dev' # Import local configuration for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']: