from django.contrib import admin from django.contrib.admin import AdminSite from django.utils.html import format_html from django.urls import reverse from django.utils.safestring import mark_safe from .models import EditSubmission, PhotoSubmission class ModerationAdminSite(AdminSite): site_header = "ThrillWiki Moderation" site_title = "ThrillWiki Moderation" index_title = "Moderation Dashboard" def has_permission(self, request): """Only allow moderators and above to access this admin site""" return request.user.is_authenticated and request.user.role in [ "MODERATOR", "ADMIN", "SUPERUSER", ] moderation_site = ModerationAdminSite(name="moderation") class EditSubmissionAdmin(admin.ModelAdmin): list_display = [ "id", "user_link", "content_type", "content_link", "status", "created_at", "handled_by", ] list_filter = ["status", "content_type", "created_at"] search_fields = ["user__username", "reason", "source", "notes"] readonly_fields = [ "user", "content_type", "object_id", "changes", "created_at", ] def user_link(self, obj): url = reverse("admin:accounts_user_change", args=[obj.user.id]) return format_html('{}', url, obj.user.username) user_link.short_description = "User" def content_link(self, obj): if hasattr(obj.content_object, "get_absolute_url"): url = obj.content_object.get_absolute_url() return format_html('{}', url, str(obj.content_object)) return str(obj.content_object) content_link.short_description = "Content" def save_model(self, request, obj, form, change): if "status" in form.changed_data: if obj.status == "APPROVED": obj.approve(request.user) elif obj.status == "REJECTED": obj.reject(request.user) elif obj.status == "ESCALATED": obj.escalate(request.user) super().save_model(request, obj, form, change) class PhotoSubmissionAdmin(admin.ModelAdmin): list_display = [ "id", "user_link", "content_type", "content_link", "photo_preview", "status", "created_at", "handled_by", ] list_filter = ["status", "content_type", "created_at"] search_fields = ["user__username", "caption", "notes"] readonly_fields = [ "user", "content_type", "object_id", "photo_preview", "created_at", ] def user_link(self, obj): url = reverse("admin:accounts_user_change", args=[obj.user.id]) return format_html('{}', url, obj.user.username) user_link.short_description = "User" def content_link(self, obj): if hasattr(obj.content_object, "get_absolute_url"): url = obj.content_object.get_absolute_url() return format_html('{}', url, str(obj.content_object)) return str(obj.content_object) content_link.short_description = "Content" def photo_preview(self, obj): if obj.photo: return format_html( '', obj.photo.url, ) return "" photo_preview.short_description = "Photo Preview" def save_model(self, request, obj, form, change): if "status" in form.changed_data: if obj.status == "APPROVED": obj.approve(request.user, obj.notes) elif obj.status == "REJECTED": obj.reject(request.user, obj.notes) super().save_model(request, obj, form, change) class HistoryEventAdmin(admin.ModelAdmin): """Admin interface for viewing model history events""" list_display = [ "pgh_label", "pgh_created_at", "get_object_link", "get_context", ] list_filter = ["pgh_label", "pgh_created_at"] readonly_fields = [ "pgh_label", "pgh_obj_id", "pgh_data", "pgh_context", "pgh_created_at", ] date_hierarchy = "pgh_created_at" def get_object_link(self, obj): """Display a link to the related object if possible""" if obj.pgh_obj and hasattr(obj.pgh_obj, "get_absolute_url"): url = obj.pgh_obj.get_absolute_url() return format_html('{}', url, str(obj.pgh_obj)) return str(obj.pgh_obj or "") get_object_link.short_description = "Object" def get_context(self, obj): """Format the context data nicely""" if not obj.pgh_context: return "-" html = [""] for key, value in obj.pgh_context.items(): html.append(f"") html.append("
{key}{value}
") return mark_safe("".join(html)) get_context.short_description = "Context" # Register with moderation site only moderation_site.register(EditSubmission, EditSubmissionAdmin) moderation_site.register(PhotoSubmission, PhotoSubmissionAdmin) # We will register concrete event models as they are created during migrations # Example: moderation_site.register(DesignerEvent, HistoryEventAdmin)