diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index fc56dfa09..a13a7ef2a 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -2,6 +2,10 @@ ## v2.9.0 (FUTURE) +### Enhancements + +* [#4919](https://github.com/netbox-community/netbox/issues/4919) - Allow adding/changing assigned permissions within group and user admin views + ### Bug Fixes * [#4905](https://github.com/netbox-community/netbox/issues/4905) - Fix front port count on device type view diff --git a/netbox/users/admin.py b/netbox/users/admin.py index 2c3963c0a..6e8684aae 100644 --- a/netbox/users/admin.py +++ b/netbox/users/admin.py @@ -9,6 +9,49 @@ from extras.admin import order_content_types from .models import AdminGroup, AdminUser, ObjectPermission, Token, UserConfig +# +# Inline models +# + +class ObjectPermissionInline(admin.TabularInline): + exclude = None + extra = 3 + readonly_fields = ['object_types', 'actions', 'constraints'] + verbose_name = 'Permission' + verbose_name_plural = 'Permissions' + + def get_queryset(self, request): + return super().get_queryset(request).prefetch_related('objectpermission__object_types') + + @staticmethod + def object_types(instance): + # Don't call .values_list() here because we want to reference the pre-fetched object_types + return ', '.join([ot.name for ot in instance.objectpermission.object_types.all()]) + + @staticmethod + def actions(instance): + return ', '.join(instance.objectpermission.actions) + + @staticmethod + def constraints(instance): + return instance.objectpermission.constraints + + +class GroupObjectPermissionInline(ObjectPermissionInline): + model = AdminGroup.object_permissions.through + + +class UserObjectPermissionInline(ObjectPermissionInline): + model = AdminUser.object_permissions.through + + +class UserConfigInline(admin.TabularInline): + model = UserConfig + readonly_fields = ('data',) + can_delete = False + verbose_name = 'Preferences' + + # # Users & groups # @@ -24,40 +67,13 @@ class GroupAdmin(admin.ModelAdmin): list_display = ('name', 'user_count') ordering = ('name',) search_fields = ('name',) + inlines = [GroupObjectPermissionInline] - def user_count(self, obj): + @staticmethod + def user_count(obj): return obj.user_set.count() -class UserConfigInline(admin.TabularInline): - model = UserConfig - readonly_fields = ('data',) - can_delete = False - verbose_name = 'Preferences' - - -class ObjectPermissionInline(admin.TabularInline): - model = AdminUser.object_permissions.through - fields = ['object_types', 'actions', 'constraints'] - readonly_fields = fields - extra = 0 - verbose_name = 'Permission' - verbose_name_plural = 'Permissions' - - def object_types(self, instance): - return ', '.join(instance.objectpermission.object_types.values_list('model', flat=True)) - - def actions(self, instance): - return ', '.join(instance.objectpermission.actions) - - def constraints(self, instance): - return instance.objectpermission.constraints - - def has_add_permission(self, request, obj): - # Don't allow the creation of new ObjectPermission assignments via this form - return False - - @admin.register(AdminUser) class UserAdmin(UserAdmin_): list_display = [ @@ -71,7 +87,7 @@ class UserAdmin(UserAdmin_): }), ('Important dates', {'fields': ('last_login', 'date_joined')}), ) - inlines = [ObjectPermissionInline, UserConfigInline] + inlines = [UserObjectPermissionInline, UserConfigInline] filter_horizontal = ('groups',) @@ -241,7 +257,10 @@ class ObjectPermissionAdmin(admin.ModelAdmin): return super().get_queryset(request).prefetch_related('object_types', 'users', 'groups') def get_name(self, obj): - return obj.name or f'Permission #{obj.pk}' + return '{}: {}'.format( + ', '.join([ot.name for ot in obj.object_types.all()]), + ', '.join(obj.actions) + ) get_name.short_description = 'Name' def list_models(self, obj): diff --git a/netbox/users/models.py b/netbox/users/models.py index b8c799d65..a531ba867 100644 --- a/netbox/users/models.py +++ b/netbox/users/models.py @@ -16,6 +16,8 @@ from utilities.utils import flatten_dict __all__ = ( + 'AdminGroup', + 'AdminUser', 'ObjectPermission', 'Token', 'UserConfig', @@ -278,9 +280,4 @@ class ObjectPermission(models.Model): verbose_name = "permission" def __str__(self): - if self.name: - return self.name - return '{}: {}'.format( - ', '.join(self.object_types.values_list('model', flat=True)), - ', '.join(self.actions) - ) + return self.name or f'Permission #{self.pk}'