Misc cleanup

This commit is contained in:
Jeremy Stretch 2023-07-20 14:32:25 -04:00
parent b5362f059c
commit 34b8d2a097
8 changed files with 50 additions and 72 deletions

View File

@ -41,10 +41,10 @@ class Migration(migrations.Migration):
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='netboxgroup', name='netboxgroup',
options={'ordering': ['name'], 'verbose_name': 'Group'}, options={'ordering': ('name',), 'verbose_name': 'Group'},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='netboxuser', name='netboxuser',
options={'ordering': ['username'], 'verbose_name': 'User'}, options={'ordering': ('username',), 'verbose_name': 'User'},
), ),
] ]

View File

@ -69,7 +69,7 @@ class NetBoxUser(User):
class Meta: class Meta:
verbose_name = 'User' verbose_name = 'User'
proxy = True proxy = True
ordering = ['username',] ordering = ('username',)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('users:netboxuser', args=[self.pk]) return reverse('users:netboxuser', args=[self.pk])
@ -84,7 +84,7 @@ class NetBoxGroup(Group):
class Meta: class Meta:
verbose_name = 'Group' verbose_name = 'Group'
proxy = True proxy = True
ordering = ['name',] ordering = ('name',)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('users:netboxgroup', args=[self.pk]) return reverse('users:netboxgroup', args=[self.pk])
@ -94,7 +94,6 @@ class NetBoxGroup(Group):
# User preferences # User preferences
# #
class UserConfig(models.Model): class UserConfig(models.Model):
""" """
This model stores arbitrary user-specific preferences in a JSON data structure. This model stores arbitrary user-specific preferences in a JSON data structure.

View File

@ -57,8 +57,12 @@ class TokenTable(NetBoxTable):
class UserTable(NetBoxTable): class UserTable(NetBoxTable):
username = tables.Column(linkify=True) username = tables.Column(
groups = tables.ManyToManyColumn() linkify=True
)
groups = columns.ManyToManyColumn(
linkify_item=('users:netboxgroup', {'pk': tables.A('pk')})
)
is_active = columns.BooleanColumn() is_active = columns.BooleanColumn()
is_staff = columns.BooleanColumn() is_staff = columns.BooleanColumn()
is_superuser = columns.BooleanColumn() is_superuser = columns.BooleanColumn()
@ -100,8 +104,12 @@ class ObjectPermissionTable(NetBoxTable):
custom_actions = columns.ArrayColumn( custom_actions = columns.ArrayColumn(
accessor=tables.A('actions') accessor=tables.A('actions')
) )
users = tables.ManyToManyColumn() users = columns.ManyToManyColumn(
groups = tables.ManyToManyColumn() linkify_item=('users:netboxuser', {'pk': tables.A('pk')})
)
groups = columns.ManyToManyColumn(
linkify_item=('users:netboxgroup', {'pk': tables.A('pk')})
)
actions = columns.ActionsColumn( actions = columns.ActionsColumn(
actions=('edit', 'delete'), actions=('edit', 'delete'),
) )

View File

@ -16,18 +16,18 @@ urlpatterns = [
path('api-tokens/<int:pk>/', include(get_model_urls('users', 'token'))), path('api-tokens/<int:pk>/', include(get_model_urls('users', 'token'))),
# Users # Users
path('users/', views.NetBoxUserListView.as_view(), name='netboxuser_list'), path('users/', views.UserListView.as_view(), name='netboxuser_list'),
path('users/add/', views.NetBoxUserEditView.as_view(), name='netboxuser_add'), path('users/add/', views.UserEditView.as_view(), name='netboxuser_add'),
path('users/edit/', views.NetBoxUserBulkEditView.as_view(), name='netboxuser_bulk_edit'), path('users/edit/', views.UserBulkEditView.as_view(), name='netboxuser_bulk_edit'),
path('users/import/', views.NetBoxUserBulkImportView.as_view(), name='netboxuser_import'), path('users/import/', views.UserBulkImportView.as_view(), name='netboxuser_import'),
path('users/delete/', views.NetBoxUserBulkDeleteView.as_view(), name='netboxuser_bulk_delete'), path('users/delete/', views.UserBulkDeleteView.as_view(), name='netboxuser_bulk_delete'),
path('users/<int:pk>/', include(get_model_urls('users', 'netboxuser'))), path('users/<int:pk>/', include(get_model_urls('users', 'netboxuser'))),
# Groups # Groups
path('groups/', views.NetBoxGroupListView.as_view(), name='netboxgroup_list'), path('groups/', views.GroupListView.as_view(), name='netboxgroup_list'),
path('groups/add/', views.NetBoxGroupEditView.as_view(), name='netboxgroup_add'), path('groups/add/', views.GroupEditView.as_view(), name='netboxgroup_add'),
path('groups/import/', views.NetBoxGroupBulkImportView.as_view(), name='netboxgroup_import'), path('groups/import/', views.GroupBulkImportView.as_view(), name='netboxgroup_import'),
path('groups/delete/', views.NetBoxGroupBulkDeleteView.as_view(), name='netboxgroup_bulk_delete'), path('groups/delete/', views.GroupBulkDeleteView.as_view(), name='netboxgroup_bulk_delete'),
path('groups/<int:pk>/', include(get_model_urls('users', 'netboxgroup'))), path('groups/<int:pk>/', include(get_model_urls('users', 'netboxgroup'))),
# Permissions # Permissions

View File

@ -2,11 +2,10 @@ import logging
from django.conf import settings from django.conf import settings
from django.contrib import messages 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.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.contrib.auth.signals import user_logged_in
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Count from django.db.models import Count
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render, resolve_url 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.config import get_config
from netbox.views import generic from netbox.views import generic
from utilities.forms import ConfirmationForm 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 utilities.views import register_model_view
from . import filtersets, forms, tables from . import filtersets, forms, tables
from .models import Token, UserConfig, NetBoxGroup, NetBoxUser, ObjectPermission 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() queryset = NetBoxUser.objects.all()
filterset = filtersets.UserFilterSet filterset = filtersets.UserFilterSet
filterset_form = forms.UserFilterForm filterset_form = forms.UserFilterForm
@ -370,47 +367,43 @@ class NetBoxUserListView(generic.ObjectListView):
@register_model_view(NetBoxUser) @register_model_view(NetBoxUser)
class NetBoxUserView(generic.ObjectView): class UserView(generic.ObjectView):
queryset = NetBoxUser.objects.all() queryset = NetBoxUser.objects.all()
template_name = 'users/user.html' template_name = 'users/user.html'
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
# Compile changelog table changelog = ObjectChange.objects.restrict(request.user, 'view').filter(user=request.user)[:20]
changelog = ObjectChange.objects.restrict(request.user, 'view').filter(user=request.user).prefetch_related(
'changed_object_type'
)[:20]
changelog_table = ObjectChangeTable(changelog) changelog_table = ObjectChangeTable(changelog)
return { return {
'changelog_table': changelog_table, 'changelog_table': changelog_table,
'active_tab': 'user',
} }
@register_model_view(NetBoxUser, 'edit') @register_model_view(NetBoxUser, 'edit')
class NetBoxUserEditView(generic.ObjectEditView): class UserEditView(generic.ObjectEditView):
queryset = NetBoxUser.objects.all() queryset = NetBoxUser.objects.all()
form = forms.UserForm form = forms.UserForm
@register_model_view(NetBoxUser, 'delete') @register_model_view(NetBoxUser, 'delete')
class NetBoxUserDeleteView(generic.ObjectDeleteView): class UserDeleteView(generic.ObjectDeleteView):
queryset = NetBoxUser.objects.all() queryset = NetBoxUser.objects.all()
class NetBoxUserBulkEditView(generic.BulkEditView): class UserBulkEditView(generic.BulkEditView):
queryset = NetBoxUser.objects.all() queryset = NetBoxUser.objects.all()
filterset = filtersets.UserFilterSet filterset = filtersets.UserFilterSet
table = tables.UserTable table = tables.UserTable
form = forms.UserBulkEditForm form = forms.UserBulkEditForm
class NetBoxUserBulkImportView(generic.BulkImportView): class UserBulkImportView(generic.BulkImportView):
queryset = NetBoxUser.objects.all() queryset = NetBoxUser.objects.all()
model_form = forms.UserImportForm model_form = forms.UserImportForm
class NetBoxUserBulkDeleteView(generic.BulkDeleteView): class UserBulkDeleteView(generic.BulkDeleteView):
queryset = NetBoxUser.objects.all() queryset = NetBoxUser.objects.all()
filterset = filtersets.UserFilterSet filterset = filtersets.UserFilterSet
table = tables.UserTable table = tables.UserTable
@ -421,42 +414,37 @@ class NetBoxUserBulkDeleteView(generic.BulkDeleteView):
# #
class NetBoxGroupListView(generic.ObjectListView): class GroupListView(generic.ObjectListView):
queryset = NetBoxGroup.objects.all().annotate(users_count=Count('user')) queryset = NetBoxGroup.objects.annotate(users_count=Count('user'))
filterset = filtersets.GroupFilterSet filterset = filtersets.GroupFilterSet
filterset_form = forms.GroupFilterForm filterset_form = forms.GroupFilterForm
table = tables.GroupTable table = tables.GroupTable
@register_model_view(NetBoxGroup) @register_model_view(NetBoxGroup)
class NetBoxGroupView(generic.ObjectView): class GroupView(generic.ObjectView):
queryset = NetBoxGroup.objects.all() queryset = NetBoxGroup.objects.all()
template_name = 'users/group.html' template_name = 'users/group.html'
def get_extra_context(self, request, instance):
return {
'active_tab': 'group',
}
@register_model_view(NetBoxGroup, 'edit') @register_model_view(NetBoxGroup, 'edit')
class NetBoxGroupEditView(generic.ObjectEditView): class GroupEditView(generic.ObjectEditView):
queryset = NetBoxGroup.objects.all() queryset = NetBoxGroup.objects.all()
form = forms.GroupForm form = forms.GroupForm
@register_model_view(NetBoxGroup, 'delete') @register_model_view(NetBoxGroup, 'delete')
class NetBoxGroupDeleteView(generic.ObjectDeleteView): class GroupDeleteView(generic.ObjectDeleteView):
queryset = NetBoxGroup.objects.all() queryset = NetBoxGroup.objects.all()
class NetBoxGroupBulkImportView(generic.BulkImportView): class GroupBulkImportView(generic.BulkImportView):
queryset = NetBoxGroup.objects.all() queryset = NetBoxGroup.objects.all()
model_form = forms.GroupImportForm model_form = forms.GroupImportForm
class NetBoxGroupBulkDeleteView(generic.BulkDeleteView): class GroupBulkDeleteView(generic.BulkDeleteView):
queryset = NetBoxGroup.objects.all() queryset = NetBoxGroup.objects.annotate(users_count=Count('user'))
filterset = filtersets.GroupFilterSet filterset = filtersets.GroupFilterSet
table = tables.GroupTable table = tables.GroupTable
@ -477,11 +465,6 @@ class ObjectPermissionView(generic.ObjectView):
queryset = ObjectPermission.objects.all() queryset = ObjectPermission.objects.all()
template_name = 'users/objectpermission.html' template_name = 'users/objectpermission.html'
def get_extra_context(self, request, instance):
return {
'active_tab': 'objectpermission',
}
@register_model_view(ObjectPermission, 'edit') @register_model_view(ObjectPermission, 'edit')
class ObjectPermissionEditView(generic.ObjectEditView): class ObjectPermissionEditView(generic.ObjectEditView):

View File

@ -18,17 +18,10 @@ def get_permission_for_model(model, action):
:param model: A model or instance :param model: A model or instance
:param action: View, add, change, or delete (string) :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 return f'{model._meta.app_label}.{action}_{model._meta.model_name}'
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
)
def resolve_permission(name): def resolve_permission(name):
@ -75,17 +68,14 @@ def permission_is_exempt(name):
if action == 'view': if action == 'view':
if ( 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 # This specific model is exempt from view permission enforcement
f'{app_label}.{model_name}' in settings.EXEMPT_VIEW_PERMISSIONS f'{app_label}.{model_name}' in settings.EXEMPT_VIEW_PERMISSIONS
): ):
return True 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 return False

View File

@ -1,8 +1,7 @@
from django.contrib.contenttypes.models import ContentType
from django.db.models import Prefetch, QuerySet from django.db.models import Prefetch, QuerySet
from users.constants import CONSTRAINT_TOKEN_USER 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__ = ( __all__ = (
'RestrictedPrefetch', 'RestrictedPrefetch',

View File

@ -5,7 +5,6 @@ from django.urls.exceptions import NoReverseMatch
from netbox.registry import registry from netbox.registry import registry
from .permissions import resolve_permission from .permissions import resolve_permission
from .querysets import RestrictedQuerySet
__all__ = ( __all__ = (
'ContentTypePermissionRequiredMixin', 'ContentTypePermissionRequiredMixin',