mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 07:11:08 -05:00
- Cleaned up and standardized assertions in ApiTestMixin for API response validation. - Updated ASGI settings to use os.environ for setting the DJANGO_SETTINGS_MODULE. - Removed unused imports and improved formatting in settings.py. - Refactored URL patterns in urls.py for better readability and organization. - Enhanced view functions in views.py for consistency and clarity. - Added .flake8 configuration for linting and style enforcement. - Introduced type stubs for django-environ to improve type checking with Pylance.
283 lines
8.4 KiB
Python
283 lines
8.4 KiB
Python
from django.contrib import admin
|
|
from django.contrib.auth.admin import UserAdmin
|
|
from django.utils.html import format_html
|
|
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(
|
|
'<img src="{}" width="30" height="30" style="border-radius:50%;" />',
|
|
obj.profile.avatar.url,
|
|
)
|
|
return format_html(
|
|
'<div style="width:30px; height:30px; border-radius:50%; '
|
|
"background-color:#007bff; color:white; display:flex; "
|
|
'align-items:center; justify-content:center;">{}</div>',
|
|
obj.username[0].upper(),
|
|
)
|
|
|
|
@admin.display(description="Status")
|
|
def get_status(self, obj):
|
|
if obj.is_banned:
|
|
return format_html('<span style="color: red;">Banned</span>')
|
|
if not obj.is_active:
|
|
return format_html('<span style="color: orange;">Inactive</span>')
|
|
if obj.is_superuser:
|
|
return format_html('<span style="color: purple;">Superuser</span>')
|
|
if obj.is_staff:
|
|
return format_html('<span style="color: blue;">Staff</span>')
|
|
return format_html('<span style="color: green;">Active</span>')
|
|
|
|
@admin.display(description="Ride Credits")
|
|
def get_credits(self, obj):
|
|
try:
|
|
profile = obj.profile
|
|
return format_html(
|
|
"RC: {}<br>DR: {}<br>FR: {}<br>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('<span style="color: red;">Expired</span>')
|
|
return format_html('<span style="color: green;">Valid</span>')
|
|
|
|
|
|
@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")}),
|
|
)
|