From 34b8d2a0978f24af66e74f0145f4180e24bc2e37 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 20 Jul 2023 14:32:25 -0400 Subject: [PATCH] Misc cleanup --- .../migrations/0004_netboxgroup_netboxuser.py | 4 +- netbox/users/models.py | 5 +- netbox/users/tables.py | 16 ++++-- netbox/users/urls.py | 18 +++---- netbox/users/views.py | 53 +++++++------------ netbox/utilities/permissions.py | 22 +++----- netbox/utilities/querysets.py | 3 +- netbox/utilities/views.py | 1 - 8 files changed, 50 insertions(+), 72 deletions(-) diff --git a/netbox/users/migrations/0004_netboxgroup_netboxuser.py b/netbox/users/migrations/0004_netboxgroup_netboxuser.py index afbc0eefb..59d941643 100644 --- a/netbox/users/migrations/0004_netboxgroup_netboxuser.py +++ b/netbox/users/migrations/0004_netboxgroup_netboxuser.py @@ -41,10 +41,10 @@ class Migration(migrations.Migration): ), migrations.AlterModelOptions( name='netboxgroup', - options={'ordering': ['name'], 'verbose_name': 'Group'}, + options={'ordering': ('name',), 'verbose_name': 'Group'}, ), migrations.AlterModelOptions( name='netboxuser', - options={'ordering': ['username'], 'verbose_name': 'User'}, + options={'ordering': ('username',), 'verbose_name': 'User'}, ), ] diff --git a/netbox/users/models.py b/netbox/users/models.py index 3a4a0b4b2..a8060dd63 100644 --- a/netbox/users/models.py +++ b/netbox/users/models.py @@ -69,7 +69,7 @@ class NetBoxUser(User): class Meta: verbose_name = 'User' proxy = True - ordering = ['username',] + ordering = ('username',) def get_absolute_url(self): return reverse('users:netboxuser', args=[self.pk]) @@ -84,7 +84,7 @@ class NetBoxGroup(Group): class Meta: verbose_name = 'Group' proxy = True - ordering = ['name',] + ordering = ('name',) def get_absolute_url(self): return reverse('users:netboxgroup', args=[self.pk]) @@ -94,7 +94,6 @@ class NetBoxGroup(Group): # User preferences # - class UserConfig(models.Model): """ This model stores arbitrary user-specific preferences in a JSON data structure. diff --git a/netbox/users/tables.py b/netbox/users/tables.py index 304f2c8a3..741a4b024 100644 --- a/netbox/users/tables.py +++ b/netbox/users/tables.py @@ -57,8 +57,12 @@ class TokenTable(NetBoxTable): class UserTable(NetBoxTable): - username = tables.Column(linkify=True) - groups = tables.ManyToManyColumn() + username = tables.Column( + linkify=True + ) + groups = columns.ManyToManyColumn( + linkify_item=('users:netboxgroup', {'pk': tables.A('pk')}) + ) is_active = columns.BooleanColumn() is_staff = columns.BooleanColumn() is_superuser = columns.BooleanColumn() @@ -100,8 +104,12 @@ class ObjectPermissionTable(NetBoxTable): custom_actions = columns.ArrayColumn( accessor=tables.A('actions') ) - users = tables.ManyToManyColumn() - groups = tables.ManyToManyColumn() + users = columns.ManyToManyColumn( + linkify_item=('users:netboxuser', {'pk': tables.A('pk')}) + ) + groups = columns.ManyToManyColumn( + linkify_item=('users:netboxgroup', {'pk': tables.A('pk')}) + ) actions = columns.ActionsColumn( actions=('edit', 'delete'), ) diff --git a/netbox/users/urls.py b/netbox/users/urls.py index 573a44224..ca331d144 100644 --- a/netbox/users/urls.py +++ b/netbox/users/urls.py @@ -16,18 +16,18 @@ urlpatterns = [ path('api-tokens//', include(get_model_urls('users', 'token'))), # Users - path('users/', views.NetBoxUserListView.as_view(), name='netboxuser_list'), - path('users/add/', views.NetBoxUserEditView.as_view(), name='netboxuser_add'), - path('users/edit/', views.NetBoxUserBulkEditView.as_view(), name='netboxuser_bulk_edit'), - path('users/import/', views.NetBoxUserBulkImportView.as_view(), name='netboxuser_import'), - path('users/delete/', views.NetBoxUserBulkDeleteView.as_view(), name='netboxuser_bulk_delete'), + path('users/', views.UserListView.as_view(), name='netboxuser_list'), + path('users/add/', views.UserEditView.as_view(), name='netboxuser_add'), + path('users/edit/', views.UserBulkEditView.as_view(), name='netboxuser_bulk_edit'), + path('users/import/', views.UserBulkImportView.as_view(), name='netboxuser_import'), + path('users/delete/', views.UserBulkDeleteView.as_view(), name='netboxuser_bulk_delete'), path('users//', include(get_model_urls('users', 'netboxuser'))), # Groups - path('groups/', views.NetBoxGroupListView.as_view(), name='netboxgroup_list'), - path('groups/add/', views.NetBoxGroupEditView.as_view(), name='netboxgroup_add'), - path('groups/import/', views.NetBoxGroupBulkImportView.as_view(), name='netboxgroup_import'), - path('groups/delete/', views.NetBoxGroupBulkDeleteView.as_view(), name='netboxgroup_bulk_delete'), + path('groups/', views.GroupListView.as_view(), name='netboxgroup_list'), + path('groups/add/', views.GroupEditView.as_view(), name='netboxgroup_add'), + path('groups/import/', views.GroupBulkImportView.as_view(), name='netboxgroup_import'), + path('groups/delete/', views.GroupBulkDeleteView.as_view(), name='netboxgroup_bulk_delete'), path('groups//', include(get_model_urls('users', 'netboxgroup'))), # Permissions diff --git a/netbox/users/views.py b/netbox/users/views.py index c93b8cc82..99635b514 100644 --- a/netbox/users/views.py +++ b/netbox/users/views.py @@ -2,11 +2,10 @@ import logging from django.conf import settings from django.contrib import messages -from django.contrib.auth import login as auth_login, logout as auth_logout, update_session_auth_hash, get_user_model +from django.contrib.auth import login as auth_login, logout as auth_logout, update_session_auth_hash from django.contrib.auth.mixins import LoginRequiredMixin -from django.contrib.auth.models import Group, User, update_last_login +from django.contrib.auth.models import update_last_login from django.contrib.auth.signals import user_logged_in -from django.core.exceptions import ImproperlyConfigured from django.db.models import Count from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render, resolve_url @@ -23,8 +22,6 @@ from netbox.authentication import get_auth_backend_display, get_saml_idps from netbox.config import get_config from netbox.views import generic from utilities.forms import ConfirmationForm -from utilities.permissions import get_permission_for_model -from utilities.querysets import RestrictedQuerySet from utilities.views import register_model_view from . import filtersets, forms, tables from .models import Token, UserConfig, NetBoxGroup, NetBoxUser, ObjectPermission @@ -362,7 +359,7 @@ class TokenDeleteView(LoginRequiredMixin, View): # -class NetBoxUserListView(generic.ObjectListView): +class UserListView(generic.ObjectListView): queryset = NetBoxUser.objects.all() filterset = filtersets.UserFilterSet filterset_form = forms.UserFilterForm @@ -370,47 +367,43 @@ class NetBoxUserListView(generic.ObjectListView): @register_model_view(NetBoxUser) -class NetBoxUserView(generic.ObjectView): +class UserView(generic.ObjectView): queryset = NetBoxUser.objects.all() template_name = 'users/user.html' def get_extra_context(self, request, instance): - # Compile changelog table - changelog = ObjectChange.objects.restrict(request.user, 'view').filter(user=request.user).prefetch_related( - 'changed_object_type' - )[:20] + changelog = ObjectChange.objects.restrict(request.user, 'view').filter(user=request.user)[:20] changelog_table = ObjectChangeTable(changelog) return { 'changelog_table': changelog_table, - 'active_tab': 'user', } @register_model_view(NetBoxUser, 'edit') -class NetBoxUserEditView(generic.ObjectEditView): +class UserEditView(generic.ObjectEditView): queryset = NetBoxUser.objects.all() form = forms.UserForm @register_model_view(NetBoxUser, 'delete') -class NetBoxUserDeleteView(generic.ObjectDeleteView): +class UserDeleteView(generic.ObjectDeleteView): queryset = NetBoxUser.objects.all() -class NetBoxUserBulkEditView(generic.BulkEditView): +class UserBulkEditView(generic.BulkEditView): queryset = NetBoxUser.objects.all() filterset = filtersets.UserFilterSet table = tables.UserTable form = forms.UserBulkEditForm -class NetBoxUserBulkImportView(generic.BulkImportView): +class UserBulkImportView(generic.BulkImportView): queryset = NetBoxUser.objects.all() model_form = forms.UserImportForm -class NetBoxUserBulkDeleteView(generic.BulkDeleteView): +class UserBulkDeleteView(generic.BulkDeleteView): queryset = NetBoxUser.objects.all() filterset = filtersets.UserFilterSet table = tables.UserTable @@ -421,42 +414,37 @@ class NetBoxUserBulkDeleteView(generic.BulkDeleteView): # -class NetBoxGroupListView(generic.ObjectListView): - queryset = NetBoxGroup.objects.all().annotate(users_count=Count('user')) +class GroupListView(generic.ObjectListView): + queryset = NetBoxGroup.objects.annotate(users_count=Count('user')) filterset = filtersets.GroupFilterSet filterset_form = forms.GroupFilterForm table = tables.GroupTable @register_model_view(NetBoxGroup) -class NetBoxGroupView(generic.ObjectView): +class GroupView(generic.ObjectView): queryset = NetBoxGroup.objects.all() template_name = 'users/group.html' - def get_extra_context(self, request, instance): - return { - 'active_tab': 'group', - } - @register_model_view(NetBoxGroup, 'edit') -class NetBoxGroupEditView(generic.ObjectEditView): +class GroupEditView(generic.ObjectEditView): queryset = NetBoxGroup.objects.all() form = forms.GroupForm @register_model_view(NetBoxGroup, 'delete') -class NetBoxGroupDeleteView(generic.ObjectDeleteView): +class GroupDeleteView(generic.ObjectDeleteView): queryset = NetBoxGroup.objects.all() -class NetBoxGroupBulkImportView(generic.BulkImportView): +class GroupBulkImportView(generic.BulkImportView): queryset = NetBoxGroup.objects.all() model_form = forms.GroupImportForm -class NetBoxGroupBulkDeleteView(generic.BulkDeleteView): - queryset = NetBoxGroup.objects.all() +class GroupBulkDeleteView(generic.BulkDeleteView): + queryset = NetBoxGroup.objects.annotate(users_count=Count('user')) filterset = filtersets.GroupFilterSet table = tables.GroupTable @@ -477,11 +465,6 @@ class ObjectPermissionView(generic.ObjectView): queryset = ObjectPermission.objects.all() template_name = 'users/objectpermission.html' - def get_extra_context(self, request, instance): - return { - 'active_tab': 'objectpermission', - } - @register_model_view(ObjectPermission, 'edit') class ObjectPermissionEditView(generic.ObjectEditView): diff --git a/netbox/utilities/permissions.py b/netbox/utilities/permissions.py index 6bdf2b9c4..813a8f944 100644 --- a/netbox/utilities/permissions.py +++ b/netbox/utilities/permissions.py @@ -18,17 +18,10 @@ def get_permission_for_model(model, action): :param model: A model or instance :param action: View, add, change, or delete (string) """ + # Resolve to the "concrete" model (for proxy models) + model = model._meta.concrete_model - # Get non proxied model - concrete_model = model - while concrete_model._meta.proxy_for_model: - concrete_model = concrete_model._meta.proxy_for_model - - return '{}.{}_{}'.format( - concrete_model._meta.app_label, - action, - concrete_model._meta.model_name - ) + return f'{model._meta.app_label}.{action}_{model._meta.model_name}' def resolve_permission(name): @@ -75,17 +68,14 @@ def permission_is_exempt(name): if action == 'view': if ( + # All models (excluding those in EXEMPT_EXCLUDE_MODELS) are exempt from view permission enforcement + '*' in settings.EXEMPT_VIEW_PERMISSIONS and (app_label, model_name) not in settings.EXEMPT_EXCLUDE_MODELS + ) or ( # This specific model is exempt from view permission enforcement f'{app_label}.{model_name}' in settings.EXEMPT_VIEW_PERMISSIONS ): return True - if ( - # All models (excluding those in EXEMPT_EXCLUDE_MODELS) are exempt from view permission enforcement - '*' in settings.EXEMPT_VIEW_PERMISSIONS and ((app_label, model_name) not in settings.EXEMPT_EXCLUDE_MODELS) - ): - return True - return False diff --git a/netbox/utilities/querysets.py b/netbox/utilities/querysets.py index aad16a780..50917dd0f 100644 --- a/netbox/utilities/querysets.py +++ b/netbox/utilities/querysets.py @@ -1,8 +1,7 @@ -from django.contrib.contenttypes.models import ContentType from django.db.models import Prefetch, QuerySet from users.constants import CONSTRAINT_TOKEN_USER -from utilities.permissions import permission_is_exempt, qs_filter_from_constraints, get_permission_for_model +from utilities.permissions import get_permission_for_model, permission_is_exempt, qs_filter_from_constraints __all__ = ( 'RestrictedPrefetch', diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index a639524b7..589b71f50 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -5,7 +5,6 @@ from django.urls.exceptions import NoReverseMatch from netbox.registry import registry from .permissions import resolve_permission -from .querysets import RestrictedQuerySet __all__ = ( 'ContentTypePermissionRequiredMixin',