""" Django admin configuration for User models. """ from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.utils.html import format_html from django.urls import reverse from django.utils.safestring import mark_safe from unfold.admin import ModelAdmin from unfold.decorators import display from import_export import resources from import_export.admin import ImportExportModelAdmin from .models import User, UserRole, UserProfile class UserResource(resources.ModelResource): """Resource for importing/exporting users.""" class Meta: model = User fields = ( 'id', 'email', 'username', 'first_name', 'last_name', 'date_joined', 'last_login', 'is_active', 'is_staff', 'banned', 'reputation_score', 'mfa_enabled' ) export_order = fields class UserRoleInline(admin.StackedInline): """Inline for user role.""" model = UserRole can_delete = False verbose_name_plural = 'Role' fk_name = 'user' fields = ('role', 'granted_by', 'granted_at') readonly_fields = ('granted_at',) class UserProfileInline(admin.StackedInline): """Inline for user profile.""" model = UserProfile can_delete = False verbose_name_plural = 'Profile & Preferences' fk_name = 'user' fields = ( ('email_notifications', 'email_on_submission_approved', 'email_on_submission_rejected'), ('profile_public', 'show_email'), ('total_submissions', 'approved_submissions'), ) readonly_fields = ('total_submissions', 'approved_submissions') @admin.register(User) class UserAdmin(BaseUserAdmin, ModelAdmin, ImportExportModelAdmin): """Admin interface for User model.""" resource_class = UserResource list_display = [ 'email', 'username', 'display_name_admin', 'role_badge', 'reputation_badge', 'status_badge', 'mfa_badge', 'date_joined', 'last_login', ] list_filter = [ 'is_active', 'is_staff', 'is_superuser', 'banned', 'mfa_enabled', 'oauth_provider', 'date_joined', 'last_login', ] search_fields = [ 'email', 'username', 'first_name', 'last_name', ] ordering = ['-date_joined'] fieldsets = ( ('Account Information', { 'fields': ('email', 'username', 'password') }), ('Personal Information', { 'fields': ('first_name', 'last_name', 'avatar_url', 'bio') }), ('Permissions', { 'fields': ( 'is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions', ) }), ('Moderation', { 'fields': ( 'banned', 'ban_reason', 'banned_at', 'banned_by', ) }), ('OAuth', { 'fields': ('oauth_provider', 'oauth_sub'), 'classes': ('collapse',) }), ('Security', { 'fields': ('mfa_enabled', 'reputation_score'), }), ('Timestamps', { 'fields': ('date_joined', 'last_login'), 'classes': ('collapse',) }), ) add_fieldsets = ( ('Create New User', { 'classes': ('wide',), 'fields': ('email', 'username', 'password1', 'password2'), }), ) readonly_fields = [ 'date_joined', 'last_login', 'banned_at', 'oauth_provider', 'oauth_sub', ] inlines = [UserRoleInline, UserProfileInline] @display(description="Name", label=True) def display_name_admin(self, obj): """Display user's display name.""" return obj.display_name or '-' @display(description="Role", label=True) def role_badge(self, obj): """Display user role with badge.""" try: role = obj.role.role colors = { 'admin': 'red', 'moderator': 'blue', 'user': 'green', } return format_html( '{}', colors.get(role, 'gray'), role.upper() ) except UserRole.DoesNotExist: return format_html('No Role') @display(description="Reputation", label=True) def reputation_badge(self, obj): """Display reputation score.""" score = obj.reputation_score if score >= 100: color = 'green' elif score >= 50: color = 'blue' elif score >= 0: color = 'gray' else: color = 'red' return format_html( '{}', color, score ) @display(description="Status", label=True) def status_badge(self, obj): """Display user status.""" if obj.banned: return format_html( 'BANNED' ) elif not obj.is_active: return format_html( 'INACTIVE' ) else: return format_html( 'ACTIVE' ) @display(description="MFA", label=True) def mfa_badge(self, obj): """Display MFA status.""" if obj.mfa_enabled: return format_html( '✓ Enabled' ) else: return format_html( '✗ Disabled' ) def get_queryset(self, request): """Optimize queryset with select_related.""" qs = super().get_queryset(request) return qs.select_related('role', 'banned_by') actions = ['ban_users', 'unban_users', 'make_moderator', 'make_user'] @admin.action(description="Ban selected users") def ban_users(self, request, queryset): """Ban selected users.""" count = 0 for user in queryset: if not user.banned: user.ban(reason="Banned by admin", banned_by=request.user) count += 1 self.message_user( request, f"{count} user(s) have been banned." ) @admin.action(description="Unban selected users") def unban_users(self, request, queryset): """Unban selected users.""" count = 0 for user in queryset: if user.banned: user.unban() count += 1 self.message_user( request, f"{count} user(s) have been unbanned." ) @admin.action(description="Set role to Moderator") def make_moderator(self, request, queryset): """Set users' role to moderator.""" from .services import RoleService count = 0 for user in queryset: RoleService.assign_role(user, 'moderator', request.user) count += 1 self.message_user( request, f"{count} user(s) have been set to Moderator role." ) @admin.action(description="Set role to User") def make_user(self, request, queryset): """Set users' role to user.""" from .services import RoleService count = 0 for user in queryset: RoleService.assign_role(user, 'user', request.user) count += 1 self.message_user( request, f"{count} user(s) have been set to User role." ) @admin.register(UserRole) class UserRoleAdmin(ModelAdmin): """Admin interface for UserRole model.""" list_display = ['user', 'role', 'is_moderator', 'is_admin', 'granted_at', 'granted_by'] list_filter = ['role', 'granted_at'] search_fields = ['user__email', 'user__username'] ordering = ['-granted_at'] readonly_fields = ['granted_at'] def get_queryset(self, request): """Optimize queryset.""" qs = super().get_queryset(request) return qs.select_related('user', 'granted_by') @admin.register(UserProfile) class UserProfileAdmin(ModelAdmin): """Admin interface for UserProfile model.""" list_display = [ 'user', 'total_submissions', 'approved_submissions', 'approval_rate', 'email_notifications', 'profile_public', ] list_filter = [ 'email_notifications', 'profile_public', 'show_email', ] search_fields = ['user__email', 'user__username'] readonly_fields = ['created', 'modified', 'total_submissions', 'approved_submissions'] fieldsets = ( ('User', { 'fields': ('user',) }), ('Statistics', { 'fields': ('total_submissions', 'approved_submissions'), }), ('Notification Preferences', { 'fields': ( 'email_notifications', 'email_on_submission_approved', 'email_on_submission_rejected', ) }), ('Privacy Settings', { 'fields': ('profile_public', 'show_email'), }), ('Timestamps', { 'fields': ('created', 'modified'), 'classes': ('collapse',) }), ) @display(description="Approval Rate") def approval_rate(self, obj): """Display approval rate percentage.""" if obj.total_submissions == 0: return '-' rate = (obj.approved_submissions / obj.total_submissions) * 100 if rate >= 80: color = 'green' elif rate >= 60: color = 'blue' elif rate >= 40: color = 'orange' else: color = 'red' return format_html( '{:.1f}%', color, rate ) def get_queryset(self, request): """Optimize queryset.""" qs = super().get_queryset(request) return qs.select_related('user')