from django import forms from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin from django.contrib.auth.models import Group from django.db import models from django.utils.html import format_html from django.utils.translation import gettext_lazy as _, ngettext from rest_framework.authtoken.models import TokenProxy from unfold.admin import ModelAdmin, StackedInline from unfold.decorators import display from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm from unfold.contrib.filters.admin import RangeDateTimeFilter from apps.account.models import User, ClientUser, LocationHistory from utils.admin import project_admin_site from apps.account.admin.location import LocationHistoryInline from apps.account.admin.verification import VerificationDocumentInline # ========================================================= # 1. Base User Admin Form & Admin # ========================================================= class UserAdminCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = User fields = ("first_name", "last_name", "fullname", "email") def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if 'email' in self.fields: self.fields['email'].required = True def clean_email(self): email = self.cleaned_data.get('email') if User.objects.filter(email=email).exists(): raise forms.ValidationError(_("A user with this email already exists.")) return email class UserAdminChangeForm(UserChangeForm): class Meta(UserChangeForm.Meta): model = User def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if 'email' in self.fields: self.fields['email'].required = True class UserAdmin(ModelAdmin, BaseUserAdmin): form = UserAdminChangeForm add_form = UserAdminCreationForm change_password_form = AdminPasswordChangeForm compressed_fields = False list_display = ('first_name', 'last_name', 'fullname', 'email', 'role', 'user_type', 'is_staff', 'is_active', 'display_date_joined',) ordering = ("-id",) search_fields = ('email', 'first_name', 'last_name', 'fullname', 'username',) list_filter = [ "role", "user_type", "is_active", "is_staff", ("last_login", RangeDateTimeFilter), ("date_joined", RangeDateTimeFilter), ] inlines = [LocationHistoryInline, VerificationDocumentInline] add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ( ('first_name', 'last_name'), ('fullname', 'email'), 'role', 'phone_number', ('title', 'rank'), ('institution_name', 'website'), 'address', 'birthdate', 'gender', 'avatar', 'skill', 'info' ), }), ) fieldsets = ( (None, { "fields": ( ("first_name", "last_name"), ("fullname", "email"), ("password",), ), }), (_("Profile Details"), { "classes": ["tab"], "fields": ( ("avatar",), ("phone_number", "gender"), ("title", "rank"), ("institution_name", "website"), ("address",), ("birthdate", "language"), ("skill",), ("info",), ), }), (_("Access & Role"), { "classes": ["tab"], "fields": ( ("role", "user_type"), ("is_active", "is_staff", "is_superuser"), ("groups", "user_permissions"), ), }), (_("Custom Permissions"), { "classes": ["tab"], "description": _("Override specific permissions for this individual user (JSON dictionary of {permission_name: True/False}). Overrides take precedence over the role defaults."), "fields": ( "custom_permissions", ), }), (_("Timestamps & Metadata"), { "classes": ["tab"], "fields": ( ("date_joined", "last_login"), ("deleted_at",), ), }), ) readonly_fields = ('date_joined', 'last_login') @display(description=_("Date Joined")) def display_date_joined(self, instance: User): return instance.date_joined.strftime("%Y-%m-%d %H:%M") if instance.date_joined else "-" class GroupAdmin(BaseGroupAdmin, ModelAdmin): list_display = ('name', 'permissions_count') search_fields = ('name',) ordering = ('name',) filter_horizontal = ('permissions',) fieldsets = ( (None, {'fields': ('name',)}), (_('Permissions'), {'fields': ('permissions',), 'classes': ['tab']}), ) @display(description=_("Permissions")) def permissions_count(self, obj): count = obj.permissions.count() return ngettext("{count} permission", "{count} permissions", count).format(count=count) if count > 0 else "-" def has_add_permission(self, request): return bool(request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_superuser or request.user.can_access_admin_panel())) def has_change_permission(self, request, obj=None): return bool(request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_superuser or request.user.can_access_admin_panel())) def has_delete_permission(self, request, obj=None): return bool(request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_superuser or request.user.can_access_admin_panel())) # ========================================================= # 2. Registrations # ========================================================= try: admin.site.unregister(User) except admin.sites.NotRegistered: pass try: admin.site.register(User, UserAdmin) except admin.sites.AlreadyRegistered: pass project_admin_site.register(User, UserAdmin) project_admin_site.register(Group, GroupAdmin) try: admin.site.unregister(TokenProxy) except admin.sites.NotRegistered: pass