Source code for tcms.kiwi_auth.admin

# -*- coding: utf-8 -*-

from django import forms
from django.contrib import admin, messages
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import GroupAdmin, UserAdmin, sensitive_post_parameters_m
from django.contrib.auth.models import Group, Permission
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _

from tcms.utils.user import delete_user

User = get_user_model()  # pylint: disable=invalid-name


def _modifying_myself(request, object_id):
    return request.user.pk == int(object_id)


[docs] class GroupAdminForm(forms.ModelForm):
[docs] class Meta: model = Group fields = ["name", "permissions"]
users = forms.ModelMultipleChoiceField( queryset=User.objects.all(), required=False, widget=FilteredSelectMultiple("users", False), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["users"].label = _("Users") if self.instance.pk: self.fields["users"].initial = self.instance.user_set.all()
[docs] def save(self, commit=True): instance = super().save(commit=commit) instance.save() self.instance.user_set.set(self.cleaned_data["users"]) self.save_m2m() return instance
[docs] class KiwiUserAdmin(UserAdmin): list_display = UserAdmin.list_display + ( "is_active", "is_superuser", "date_joined", "last_login", ) ordering = ["-pk"] # same as -date_joined
[docs] def has_view_permission(self, request, obj=None): return _modifying_myself( request, getattr(obj, "pk", 0) ) or super().has_view_permission(request, obj)
[docs] def has_change_permission(self, request, obj=None): return _modifying_myself( request, getattr(obj, "pk", 0) ) or super().has_change_permission(request, obj)
[docs] def has_delete_permission(self, request, obj=None): return _modifying_myself( request, getattr(obj, "pk", 0) ) or super().has_delete_permission(request, obj)
# pylint: disable=too-many-arguments
[docs] def render_change_form( self, request, context, add=False, change=False, form_url="", obj=None ): if obj: if not context["adminform"].form._meta.help_texts: context["adminform"].form._meta.help_texts = {} label = _("Reset email address") url = reverse_lazy("reset-user-email", args=[obj.pk]) context["adminform"].form._meta.help_texts[ "email" ] = f"<a href='{url}'>{label}</a>" if not self.has_change_permission(request, obj): context.update( { "show_save": False, "show_save_and_continue": False, } ) context.update( { "show_save_and_add_another": self.has_add_permission(request), } ) return super().render_change_form( request, context, add=add, change=change, form_url=form_url, obj=obj )
[docs] def get_readonly_fields(self, request, obj=None): # adding new user if not obj: return super().get_readonly_fields(request, obj) readonly_fields = [ "username", "last_login", "date_joined", "email", ] # only other superusers can set the is_superuser flag if not request.user.is_superuser: readonly_fields.append("is_superuser") # if you have explicit change_user permission you can modify these fields # however users are not able to give themselves elevated permissions if not self.has_change_permission(request, None): readonly_fields.extend( [ "is_staff", "is_active", "groups", "user_permissions", ] ) # lastly users can't modify others unless they have the expolicit permission if not _modifying_myself(request, obj.pk): readonly_fields.extend(["first_name", "last_name", "email"]) return readonly_fields
[docs] def get_fieldsets(self, request, obj=None): # adding new account b/c we have permissions if not obj and self.has_add_permission(request): return super().get_fieldsets(request, obj) first_fieldset_fields = ("username",) if obj and _modifying_myself(request, obj.pk): first_fieldset_fields += ("password",) remaining_fieldsets = ( (_("Personal info"), {"fields": ("first_name", "last_name", "email")}), ( _("Permissions"), { "fields": ( "is_active", "is_staff", "is_superuser", "groups", "user_permissions", ) }, ), ) if request.user.is_superuser: field_sets = super().get_fieldsets(request, obj) if field_sets[0][0] is None and "password" in field_sets[0][1]["fields"]: remaining_fieldsets = field_sets[1:] return ((None, {"fields": first_fieldset_fields}),) + remaining_fieldsets
[docs] @sensitive_post_parameters_m def user_change_password( self, request, id, form_url="" ): # pylint: disable=redefined-builtin if _modifying_myself(request, id): return HttpResponseRedirect(reverse("admin:password_change")) raise PermissionDenied
[docs] @admin.options.csrf_protect_m def delete_view(self, request, object_id, extra_context=None): user = User.objects.get(pk=object_id) # check whether the last superuser is being deleted if user.is_superuser and User.objects.filter(is_superuser=True).count() == 1: messages.add_message( request, messages.ERROR, _("This is the last superuser, it cannot be deleted!"), ) return HttpResponseRedirect( reverse("admin:auth_user_change", args=[user.pk]) ) if not _modifying_myself(request, object_id): return super().delete_view(request, object_id, extra_context) # allow deletion of the user own account permission = Permission.objects.get( content_type__app_label="auth", codename="delete_user" ) try: request.user.user_permissions.add(permission) return super().delete_view(request, object_id, extra_context) finally: request.user.user_permissions.remove(permission)
[docs] def response_delete(self, request, obj_display, obj_id): result = super().response_delete(request, obj_display, obj_id) if not _modifying_myself(request, obj_id): return result # user doesn't exist anymore so go to the login page return HttpResponseRedirect(reverse("tcms-login"))
[docs] def delete_model(self, request, obj): delete_user(obj)
[docs] class KiwiGroupAdmin(GroupAdmin): form = GroupAdminForm
[docs] def has_delete_permission(self, request, obj=None): if obj and obj.name in ["Tester", "Administrator"]: return False return super().has_delete_permission(request, obj)
[docs] def get_fields(self, request, obj=None): fields = super().get_fields(request, obj=obj) name_index = fields.index("name") # make sure Name is always the first field if name_index > 0: del fields[name_index] fields.insert(0, "name") return fields
[docs] def get_readonly_fields(self, request, obj=None): readonly_fields = super().get_readonly_fields(request, obj) if obj and obj.name in ["Tester", "Administrator"]: readonly_fields += ("name",) return readonly_fields
# user admin extended functionality admin.site.unregister(User) admin.site.register(User, KiwiUserAdmin) admin.site.unregister(Group) admin.site.register(Group, KiwiGroupAdmin)