svthalia/concrexit

View on GitHub
website/facedetection/admin.py

Summary

Maintainability
A
0 mins
Test Coverage
from django.contrib import admin, messages
from django.db.models.query import Prefetch
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe

from facedetection.services import trigger_facedetection_lambda

from .models import (
    FaceDetectionPhoto,
    PhotoFaceEncoding,
    ReferenceFace,
    ReferenceFaceEncoding,
)


class ReferenceFaceEncodingInline(admin.TabularInline):
    model = ReferenceFaceEncoding
    readonly_fields = ["num_matches"]
    fields = ["num_matches"]
    can_delete = False
    extra = 0

    def has_add_permission(self, request, obj=None):
        return False  # Encodings should not be created manually.

    def get_queryset(self, request):
        return super().get_queryset(request).only("reference")


@admin.register(ReferenceFace)
class ReferenceFaceAdmin(admin.ModelAdmin):
    list_display = [
        "user",
        "status",
        "created_at",
        "marked_for_deletion_at",
    ]

    search_fields = [
        "user__username",
        "user__first_name",
        "user__last_name",
    ]

    list_filter = ["status", "marked_for_deletion_at"]
    inlines = [ReferenceFaceEncodingInline]

    actions = ["resubmit_reference_faces"]

    def get_readonly_fields(self, request, obj=None):
        if obj is None:
            return ["created_at", "submitted_at", "status"]
        return ["file", "user", "created_at", "submitted_at", "status"]

    @admin.action(description="Resubmit reference faces for analysis.")
    def resubmit_reference_faces(self, request, queryset) -> list[ReferenceFace]:
        querylist = list(
            queryset.filter(
                status=FaceDetectionPhoto.Status.PROCESSING,
            )
        )
        if querylist:
            trigger_facedetection_lambda(querylist)
            messages.success(request, "Resubmit successful.")
        return querylist


class PhotoFaceEncodingInline(admin.TabularInline):
    model = PhotoFaceEncoding
    readonly_fields = ["view_matches"]
    fields = ["view_matches"]
    can_delete = False
    extra = 0

    @admin.display(description="Matches")
    def view_matches(self, obj):
        reference_faces = [match.reference for match in obj.matches.all()]
        if not reference_faces:
            return "-"

        links = [
            format_html(
                '<a href="{url}">{text}</a>',
                url=reverse(
                    "admin:facedetection_referenceface_change",
                    kwargs={"object_id": rf.pk},
                ),
                text=str(rf),
            )
            for rf in reference_faces
        ]
        return mark_safe(", ".join(links))

    def has_add_permission(self, request, obj=None):
        return False  # Encodings should not be created manually.

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .only("photo")  # Don't select the 128 encoding fields.
            .prefetch_related(
                "photo__photo__album",
                Prefetch(
                    "matches",
                    queryset=ReferenceFaceEncoding.objects.select_related(
                        "reference", "reference__user"
                    ).only("reference"),
                ),
            )
        )


@admin.register(FaceDetectionPhoto)
class FaceDetectionPhotoAdmin(admin.ModelAdmin):
    list_display = [
        "__str__",
        "status",
        "submitted_at",
        "num_faces",
    ]

    readonly_fields = [
        "photo",
        "submitted_at",
        "status",
    ]

    search_fields = [
        "photo__album__title",
        "photo__album__date",
        "photo__file",
    ]

    list_filter = ["status", "submitted_at"]
    inlines = [PhotoFaceEncodingInline]

    actions = ["resubmit_face_detection_photos"]

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("photo")
            .prefetch_related("photo__album")
            .select_properties("num_faces")
        )

    def has_add_permission(self, request):
        return False

    @admin.action(description="Resubmits face detection photos for analysis.")
    def resubmit_face_detection_photos(
        self, request, queryset
    ) -> list[FaceDetectionPhoto]:
        querylist = list(
            queryset.filter(
                status=FaceDetectionPhoto.Status.PROCESSING,
            )
        )
        if querylist:
            trigger_facedetection_lambda(querylist)
            messages.success(request, "Resubmit successful.")
        return querylist