Skip to content

Commit

Permalink
fix #7672: Improve UX for PermissionAdmin
Browse files Browse the repository at this point in the history
fix #7672: Improve UX for PermissionAdmin

fix #7672: Improve UX for PermissionAdmin
  • Loading branch information
jrief committed Oct 18, 2023
1 parent 160669e commit 2d49477
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 77 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Features:
* Python 3.11, 3.10 support
* Remove patching of PageContent by djangocms-versioning (#7446)
* Utility function get_placeholder_from_slot for PlaceholderRelationField (#7479)
* Use autocomplete for entities from model `User` and `Group` instead of the raw primary key.

Bug Fixes:
----------
Expand Down
134 changes: 57 additions & 77 deletions cms/admin/permissionadmin.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,26 @@
from copy import deepcopy

from django.contrib import admin
from django.contrib.admin import site
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin
from django.contrib.sites.models import Site
from django.db import OperationalError
from django.utils.translation import gettext_lazy as _

from cms.admin.forms import (
GlobalPagePermissionAdminForm,
PagePermissionInlineAdminForm,
ViewRestrictionInlineAdminForm,
)
from cms.exceptions import NoPermissionsException
from cms.models import GlobalPagePermission, PagePermission
from cms.utils import page_permissions, permissions
from cms.utils.conf import get_cms_setting
from cms.utils.helpers import classproperty
from cms.utils.permissions import get_subordinate_users, get_subordinate_groups

PERMISSION_ADMIN_INLINES = []

user_model = get_user_model()
admin_class = UserAdmin
for model, admin_instance in site._registry.items():
for model, admin_instance in admin.site._registry.items():
if model == user_model:
admin_class = admin_instance.__class__


class TabularInline(admin.TabularInline):
pass


class PagePermissionInlineAdmin(TabularInline):
model = PagePermission
# use special form, so we can override of user and group field
form = PagePermissionInlineAdminForm
extra = 0 # edit page load time boost
show_with_view_permissions = False

class PagePermissionAdminMixin:
def has_change_permission(self, request, obj=None):
if not obj:
return False
Expand All @@ -51,38 +33,45 @@ def has_change_permission(self, request, obj=None):
def has_add_permission(self, request, obj=None):
return self.has_change_permission(request, obj)

@classproperty
def raw_id_fields(cls):
# Dynamically set raw_id_fields based on settings
threshold = get_cms_setting('RAW_ID_USERS')

# Given a fresh django-cms install and a django settings with the
# CMS_RAW_ID_USERS = CMS_PERMISSION = True
# django throws an OperationalError when running
# ./manage migrate
# because auth_user doesn't exists yet
try:
threshold = threshold and get_user_model().objects.count() > threshold
except OperationalError:
threshold = False

return ['user'] if threshold else []

def get_queryset(self, request):
"""
Queryset change, so user with global change permissions can see
all permissions. Otherwise user can see only permissions for
all permissions. Otherwise, a user can see only permissions for
peoples which are under him (he can't see his permissions, because
this will lead to violation, when he can add more power to himself)
"""
site = Site.objects.get_current(request)

try:
# can see only permissions for users which are under him in tree
qs = self.model.objects.subordinate_to_user(request.user, site)
queryset = self.model.objects.subordinate_to_user(request.user, site)
except NoPermissionsException:
return self.model.objects.none()
return qs.filter(can_view=self.show_with_view_permissions)
queryset = self.model.objects.none()
return queryset

def formfield_for_dbfield(self, db_field, request, **kwargs):
site = Site.objects.get_current(request)
formfield = super().formfield_for_dbfield(db_field, request, **kwargs)
if db_field.name == 'user':
formfield._queryset = get_subordinate_users(request.user, site)
if db_field.name == 'group':
formfield._queryset = get_subordinate_groups(request.user, site)
return formfield


class PagePermissionInlineAdmin(PagePermissionAdminMixin, admin.TabularInline):
model = PagePermission
# use special form, so we can override of user and group field
# form = PagePermissionInlineAdminForm
classes = ['collapse', 'collapsed']
fields = ['user', 'group', 'can_add', 'can_change', 'can_delete', 'can_change_advanced_settings',
'can_change_permissions', 'can_move_page', 'grant_on',
]
extra = 0 # edit page load time boost
autocomplete_fields = ['user', 'group']

def get_queryset(self, request):
return super().get_queryset(request).filter(can_view=False)

def get_formset(self, request, obj=None, **kwargs):
"""
Expand All @@ -106,26 +95,36 @@ def get_formset(self, request, obj=None, **kwargs):

kwargs['exclude'] = exclude
formset_cls = super().get_formset(request, obj=obj, **kwargs)
qs = self.get_queryset(request)
if obj is not None:
qs = qs.filter(page=obj)
formset_cls._queryset = qs
queryset = self.get_queryset(request)
if obj:
queryset = queryset.filter(page=obj)
formset_cls._queryset = queryset
return formset_cls


class ViewRestrictionInlineAdmin(PagePermissionInlineAdmin):
class ViewRestrictionInlineAdmin(PagePermissionAdminMixin, admin.TabularInline):
model = PagePermission
extra = 0 # edit page load time boost
form = ViewRestrictionInlineAdminForm
verbose_name = _("View restriction")
verbose_name_plural = _("View restrictions")
show_with_view_permissions = True
fields = ['user', 'group', 'grant_on', 'can_view']
autocomplete_fields = ['user', 'group']

def formfield_for_dbfield(self, db_field, request, **kwargs):
formfield = super().formfield_for_dbfield(db_field, request, **kwargs)
if db_field.name == 'can_view':
formfield.widget = formfield.hidden_widget()
formfield.initial = True
return formfield

def get_queryset(self, request):
return super().get_queryset(request).filter(can_view=True)


class GlobalPagePermissionAdmin(admin.ModelAdmin):
list_display = ['user', 'group', 'can_change', 'can_delete', 'can_publish', 'can_change_permissions']
list_filter = ['user', 'group', 'can_change', 'can_delete', 'can_publish', 'can_change_permissions']

form = GlobalPagePermissionAdminForm
search_fields = []
for field in admin_class.search_fields:
search_fields.append("user__%s" % field)
Expand All @@ -135,15 +134,13 @@ class GlobalPagePermissionAdmin(admin.ModelAdmin):
list_filter.append('can_change_advanced_settings')

def get_list_filter(self, request):
threshold = get_cms_setting('RAW_ID_USERS')
try:
threshold = threshold and get_user_model().objects.count() > threshold
except OperationalError:
threshold = False
filter_copy = deepcopy(self.list_filter)
if threshold:
filter_copy.remove('user')
return filter_copy
list_filter = list(super().get_list_filter(request))
users_groups_threshold = get_cms_setting('USERS_GROUPS_THRESHOLD')
if Group.objects.count() <= users_groups_threshold:
list_filter.insert(0, 'group')
if get_user_model().objects.count() <= users_groups_threshold:
list_filter.insert(0, 'user')
return list_filter

def has_add_permission(self, request):
site = Site.objects.get_current(request)
Expand All @@ -157,23 +154,6 @@ def has_delete_permission(self, request, obj=None):
site = Site.objects.get_current(request)
return permissions.user_can_delete_global_permissions(request.user, site)

@classproperty
def raw_id_fields(cls):
# Dynamically set raw_id_fields based on settings
threshold = get_cms_setting('RAW_ID_USERS')

# Given a fresh django-cms install and a django settings with the
# CMS_RAW_ID_USERS = CMS_PERMISSION = True
# django throws an OperationalError when running
# ./manage migrate
# because auth_user doesn't exists yet
try:
threshold = threshold and get_user_model().objects.count() > threshold
except OperationalError:
threshold = False

return ['user'] if threshold else []


if get_cms_setting('PERMISSION'):
admin.site.register(GlobalPagePermission, GlobalPagePermissionAdmin)
Expand Down

0 comments on commit 2d49477

Please sign in to comment.