from django.contrib import admin from django.urls import reverse from .models import Submission, SubmissionFile, ImageCrop, Scope class ImageCropInline(admin.TabularInline): model = ImageCrop extra = 1 fields = [ "label", "x1", "y1", "x2", "y2", "ocr_status", "created_at", ] readonly_fields = ["created_at"] class SubmissionFileInline(admin.TabularInline): model = SubmissionFile extra = 0 fields = [ "original_filename", "file_size", "content_type", "ocr_status", "created_at", ] readonly_fields = [ "file_size", "content_type", "created_at", ] def get_queryset(self, request): return super().get_queryset(request) @admin.register(Scope) class ScopeAdmin(admin.ModelAdmin): list_display = [ "name", "event_game", "external_id", "is_active", "assigned_user_count", "synced_at", "created_at", ] list_filter = ["is_active", "event_game__event", "event_game__game"] search_fields = ["name", "external_id", "event_game__game__name"] readonly_fields = ["id", "created_at", "updated_at", "synced_at"] filter_horizontal = ["assigned_users"] autocomplete_fields = ["event_game"] def get_queryset(self, request): return ( super() .get_queryset(request) .select_related("event_game", "event_game__event", "event_game__game") .prefetch_related("assigned_users") ) @admin.display(description="Assigned users") def assigned_user_count(self, obj): return obj.assigned_users.count() def view_on_site(self, obj): return reverse( "submissions.view", kwargs={ "event_path": obj.event_game.event.path, "game_path": obj.event_game.game.path, "scope_id": obj.id, }, ) @admin.register(Submission) class SubmissionAdmin(admin.ModelAdmin): list_display = ["id_short", "scope", "game", "user", "notes_preview", "created_at"] list_filter = [ "scope__event_game__game", "scope__event_game__event", "created_at", "updated_at", ] search_fields = [ "id", "user__email", "notes", "scope__event_game__game__name", "scope__name", ] readonly_fields = ["id", "created_at", "updated_at"] autocomplete_fields = ["scope"] inlines = [SubmissionFileInline] def get_queryset(self, request): return ( super() .get_queryset(request) .select_related("user", "scope", "scope__event_game__game") ) @admin.display(description="Game", ordering="scope__event_game__game") def game(self, obj): return obj.scope.event_game.game @admin.display(description="ID") def id_short(self, obj): return str(obj.id)[:8] @admin.display(description="Notes") def notes_preview(self, obj): if obj.notes: return obj.notes[:50] + "..." if len(obj.notes) > 50 else obj.notes return "-" @admin.register(SubmissionFile) class SubmissionFileAdmin(admin.ModelAdmin): list_display = [ "original_filename", "submission_id", "file_size", "content_type", "ocr_status", "created_at", ] list_filter = ["content_type", "ocr_status", "created_at"] search_fields = ["original_filename", "submission__id"] readonly_fields = ["file_size", "content_type", "created_at", "updated_at"] inlines = [ImageCropInline] def get_queryset(self, request): return super().get_queryset(request).select_related("submission") @admin.display(description="Submission ID") def submission_id(self, obj): return str(obj.submission.id)[:8] @admin.register(ImageCrop) class ImageCropAdmin(admin.ModelAdmin): list_display = [ "label_or_coords", "file_name", "ocr_status", "created_at", ] list_filter = ["ocr_status", "created_at"] search_fields = ["label", "submission_file__original_filename"] readonly_fields = ["created_at", "updated_at"] def get_queryset(self, request): return super().get_queryset(request).select_related("submission_file") @admin.display(description="Crop") def label_or_coords(self, obj): return obj.label or f"({obj.x1}, {obj.y1}, {obj.x2}, {obj.y2})" @admin.display(description="File") def file_name(self, obj): return obj.submission_file.original_filename