from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.utils.html import format_html from django.urls import reverse from django.contrib.auth.models import Group from .models import User, UserProfile, EmailVerification, TopList, TopListItem class UserProfileInline(admin.StackedInline): model = UserProfile can_delete = False verbose_name_plural = 'Profile' fieldsets = ( ('Personal Info', { 'fields': ('display_name', 'avatar', 'pronouns', 'bio') }), ('Social Media', { 'fields': ('twitter', 'instagram', 'youtube', 'discord') }), ('Ride Credits', { 'fields': ( 'coaster_credits', 'dark_ride_credits', 'flat_ride_credits', 'water_ride_credits' ) }), ) class TopListItemInline(admin.TabularInline): model = TopListItem extra = 1 fields = ('content_type', 'object_id', 'rank', 'notes') ordering = ('rank',) @admin.register(User) class CustomUserAdmin(UserAdmin): list_display = ('username', 'email', 'get_avatar', 'get_status', 'role', 'date_joined', 'last_login', 'get_credits') list_filter = ('is_active', 'is_staff', 'role', 'is_banned', 'groups', 'date_joined') search_fields = ('username', 'email') ordering = ('-date_joined',) actions = ['activate_users', 'deactivate_users', 'ban_users', 'unban_users'] inlines = [UserProfileInline] fieldsets = ( (None, {'fields': ('username', 'password')}), ('Personal info', {'fields': ('email', 'pending_email')}), ('Roles and Permissions', { 'fields': ('role', 'groups', 'user_permissions'), 'description': 'Role determines group membership. Groups determine permissions.', }), ('Status', { 'fields': ('is_active', 'is_staff', 'is_superuser'), 'description': 'These are automatically managed based on role.', }), ('Ban Status', { 'fields': ('is_banned', 'ban_reason', 'ban_date'), }), ('Preferences', { 'fields': ('theme_preference',), }), ('Important dates', {'fields': ('last_login', 'date_joined')}), ) add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('username', 'email', 'password1', 'password2', 'role'), }), ) @admin.display(description='Avatar') def get_avatar(self, obj): if obj.profile.avatar: return format_html('', obj.profile.avatar.url) return format_html('
{}
', obj.username[0].upper()) @admin.display(description='Status') def get_status(self, obj): if obj.is_banned: return format_html('Banned') if not obj.is_active: return format_html('Inactive') if obj.is_superuser: return format_html('Superuser') if obj.is_staff: return format_html('Staff') return format_html('Active') @admin.display(description='Ride Credits') def get_credits(self, obj): try: profile = obj.profile return format_html( 'RC: {}
DR: {}
FR: {}
WR: {}', profile.coaster_credits, profile.dark_ride_credits, profile.flat_ride_credits, profile.water_ride_credits ) except UserProfile.DoesNotExist: return '-' @admin.action(description="Activate selected users") def activate_users(self, request, queryset): queryset.update(is_active=True) @admin.action(description="Deactivate selected users") def deactivate_users(self, request, queryset): queryset.update(is_active=False) @admin.action(description="Ban selected users") def ban_users(self, request, queryset): from django.utils import timezone queryset.update(is_banned=True, ban_date=timezone.now()) @admin.action(description="Unban selected users") def unban_users(self, request, queryset): queryset.update(is_banned=False, ban_date=None, ban_reason='') def save_model(self, request, obj, form, change): creating = not obj.pk super().save_model(request, obj, form, change) if creating and obj.role != User.Roles.USER: # Ensure new user with role gets added to appropriate group group = Group.objects.filter(name=obj.role).first() if group: obj.groups.add(group) @admin.register(UserProfile) class UserProfileAdmin(admin.ModelAdmin): list_display = ('user', 'display_name', 'coaster_credits', 'dark_ride_credits', 'flat_ride_credits', 'water_ride_credits') list_filter = ('coaster_credits', 'dark_ride_credits', 'flat_ride_credits', 'water_ride_credits') search_fields = ('user__username', 'user__email', 'display_name', 'bio') fieldsets = ( ('User Information', { 'fields': ('user', 'display_name', 'avatar', 'pronouns', 'bio') }), ('Social Media', { 'fields': ('twitter', 'instagram', 'youtube', 'discord') }), ('Ride Credits', { 'fields': ( 'coaster_credits', 'dark_ride_credits', 'flat_ride_credits', 'water_ride_credits' ) }), ) @admin.register(EmailVerification) class EmailVerificationAdmin(admin.ModelAdmin): list_display = ('user', 'created_at', 'last_sent', 'is_expired') list_filter = ('created_at', 'last_sent') search_fields = ('user__username', 'user__email', 'token') readonly_fields = ('created_at', 'last_sent') fieldsets = ( ('Verification Details', { 'fields': ('user', 'token') }), ('Timing', { 'fields': ('created_at', 'last_sent') }), ) @admin.display(description='Status') def is_expired(self, obj): from django.utils import timezone from datetime import timedelta if timezone.now() - obj.last_sent > timedelta(days=1): return format_html('Expired') return format_html('Valid') @admin.register(TopList) class TopListAdmin(admin.ModelAdmin): list_display = ('title', 'user', 'category', 'created_at', 'updated_at') list_filter = ('category', 'created_at', 'updated_at') search_fields = ('title', 'user__username', 'description') inlines = [TopListItemInline] fieldsets = ( ('Basic Information', { 'fields': ('user', 'title', 'category', 'description') }), ('Timestamps', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) readonly_fields = ('created_at', 'updated_at') @admin.register(TopListItem) class TopListItemAdmin(admin.ModelAdmin): list_display = ('top_list', 'content_type', 'object_id', 'rank') list_filter = ('top_list__category', 'rank') search_fields = ('top_list__title', 'notes') ordering = ('top_list', 'rank') fieldsets = ( ('List Information', { 'fields': ('top_list', 'rank') }), ('Item Details', { 'fields': ('content_type', 'object_id', 'notes') }), )