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 import pghistory 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 HistoryAdmin(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) moderation_site.register(pghistory.models.Event, HistoryAdmin)