prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Facedetection admin resubmit action
  Sometimes the facedetection lambda can fail randomly. Photos are resubmitted nightly if that happens, but it may be nice to have an alternative for that to do it sooner, without SSHing into the server.
  
  
  </issue>
  <code>
  [start of website/facedetection/admin.py]
  1 from django.contrib import admin
  2 from django.db.models.query import Prefetch
  3 from django.urls import reverse
  4 from django.utils.html import format_html
  5 from django.utils.safestring import mark_safe
  6 
  7 from .models import (
  8     FaceDetectionPhoto,
  9     PhotoFaceEncoding,
  10     ReferenceFace,
  11     ReferenceFaceEncoding,
  12 )
  13 
  14 
  15 class ReferenceFaceEncodingInline(admin.TabularInline):
  16     model = ReferenceFaceEncoding
  17     readonly_fields = ["num_matches"]
  18     fields = ["num_matches"]
  19     can_delete = False
  20     extra = 0
  21 
  22     def has_add_permission(self, request, obj=None):
  23         return False  # Encodings should not be created manually.
  24 
  25     def get_queryset(self, request):
  26         return super().get_queryset(request).only("reference")
  27 
  28 
  29 @admin.register(ReferenceFace)
  30 class ReferenceFaceAdmin(admin.ModelAdmin):
  31     list_display = [
  32         "user",
  33         "status",
  34         "created_at",
  35         "marked_for_deletion_at",
  36     ]
  37 
  38     search_fields = [
  39         "user__username",
  40         "user__first_name",
  41         "user__last_name",
  42     ]
  43 
  44     list_filter = ["status", "marked_for_deletion_at"]
  45     inlines = [ReferenceFaceEncodingInline]
  46 
  47     def get_readonly_fields(self, request, obj=None):
  48         if obj is None:
  49             return ["created_at", "submitted_at", "status"]
  50         return ["file", "user", "created_at", "submitted_at", "status"]
  51 
  52 
  53 class PhotoFaceEncodingInline(admin.TabularInline):
  54     model = PhotoFaceEncoding
  55     readonly_fields = ["view_matches"]
  56     fields = ["view_matches"]
  57     can_delete = False
  58     extra = 0
  59 
  60     @admin.display(description="Matches")
  61     def view_matches(self, obj):
  62         reference_faces = [match.reference for match in obj.matches.all()]
  63         if not reference_faces:
  64             return "-"
  65 
  66         links = [
  67             format_html(
  68                 '<a href="{url}">{text}</a>',
  69                 url=reverse(
  70                     "admin:facedetection_referenceface_change",
  71                     kwargs={"object_id": rf.pk},
  72                 ),
  73                 text=str(rf),
  74             )
  75             for rf in reference_faces
  76         ]
  77         return mark_safe(", ".join(links))
  78 
  79     def has_add_permission(self, request, obj=None):
  80         return False  # Encodings should not be created manually.
  81 
  82     def get_queryset(self, request):
  83         return (
  84             super()
  85             .get_queryset(request)
  86             .only("photo")  # Don't select the 128 encoding fields.
  87             .prefetch_related(
  88                 "photo__photo__album",
  89                 Prefetch(
  90                     "matches",
  91                     queryset=ReferenceFaceEncoding.objects.select_related(
  92                         "reference", "reference__user"
  93                     ).only("reference"),
  94                 ),
  95             )
  96         )
  97 
  98 
  99 @admin.register(FaceDetectionPhoto)
  100 class FaceDetectionPhotoAdmin(admin.ModelAdmin):
  101     list_display = [
  102         "__str__",
  103         "status",
  104         "submitted_at",
  105         "num_faces",
  106     ]
  107 
  108     readonly_fields = [
  109         "photo",
  110         "submitted_at",
  111         "status",
  112     ]
  113 
  114     search_fields = [
  115         "photo__album__title",
  116         "photo__album__date",
  117         "photo__file",
  118     ]
  119 
  120     list_filter = ["status", "submitted_at"]
  121     inlines = [PhotoFaceEncodingInline]
  122 
  123     def get_queryset(self, request):
  124         return (
  125             super()
  126             .get_queryset(request)
  127             .select_related("photo")
  128             .prefetch_related("photo__album")
  129             .select_properties("num_faces")
  130         )
  131 
  132     def has_add_permission(self, request):
  133         return False
  134
  [end of website/facedetection/admin.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/website/facedetection/admin.py b/website/facedetection/admin.py
  --- a/website/facedetection/admin.py
  +++ b/website/facedetection/admin.py
  @@ -1,9 +1,11 @@
  -from django.contrib import admin
  +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,
  @@ -44,11 +46,25 @@
       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
  @@ -120,6 +136,8 @@
       list_filter = ["status", "submitted_at"]
       inlines = [PhotoFaceEncodingInline]
   
  +    actions = ["resubmit_face_detection_photos"]
  +
       def get_queryset(self, request):
           return (
               super()
  @@ -131,3 +149,17 @@
   
       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
  
verification_info: {"golden_diff": "diff --git a/website/facedetection/admin.py b/website/facedetection/admin.py\n--- a/website/facedetection/admin.py\n+++ b/website/facedetection/admin.py\n@@ -1,9 +1,11 @@\n-from django.contrib import admin\n+from django.contrib import admin, messages\n from django.db.models.query import Prefetch\n from django.urls import reverse\n from django.utils.html import format_html\n from django.utils.safestring import mark_safe\n \n+from facedetection.services import trigger_facedetection_lambda\n+\n from .models import (\n     FaceDetectionPhoto,\n     PhotoFaceEncoding,\n@@ -44,11 +46,25 @@\n     list_filter = [\"status\", \"marked_for_deletion_at\"]\n     inlines = [ReferenceFaceEncodingInline]\n \n+    actions = [\"resubmit_reference_faces\"]\n+\n     def get_readonly_fields(self, request, obj=None):\n         if obj is None:\n             return [\"created_at\", \"submitted_at\", \"status\"]\n         return [\"file\", \"user\", \"created_at\", \"submitted_at\", \"status\"]\n \n+    @admin.action(description=\"Resubmit reference faces for analysis.\")\n+    def resubmit_reference_faces(self, request, queryset) -> list[ReferenceFace]:\n+        querylist = list(\n+            queryset.filter(\n+                status=FaceDetectionPhoto.Status.PROCESSING,\n+            )\n+        )\n+        if querylist:\n+            trigger_facedetection_lambda(querylist)\n+            messages.success(request, \"Resubmit successful.\")\n+        return querylist\n+\n \n class PhotoFaceEncodingInline(admin.TabularInline):\n     model = PhotoFaceEncoding\n@@ -120,6 +136,8 @@\n     list_filter = [\"status\", \"submitted_at\"]\n     inlines = [PhotoFaceEncodingInline]\n \n+    actions = [\"resubmit_face_detection_photos\"]\n+\n     def get_queryset(self, request):\n         return (\n             super()\n@@ -131,3 +149,17 @@\n \n     def has_add_permission(self, request):\n         return False\n+\n+    @admin.action(description=\"Resubmits face detection photos for analysis.\")\n+    def resubmit_face_detection_photos(\n+        self, request, queryset\n+    ) -> list[FaceDetectionPhoto]:\n+        querylist = list(\n+            queryset.filter(\n+                status=FaceDetectionPhoto.Status.PROCESSING,\n+            )\n+        )\n+        if querylist:\n+            trigger_facedetection_lambda(querylist)\n+            messages.success(request, \"Resubmit successful.\")\n+        return querylist\n", "issue": "Facedetection admin resubmit action\nSometimes the facedetection lambda can fail randomly. Photos are resubmitted nightly if that happens, but it may be nice to have an alternative for that to do it sooner, without SSHing into the server.\r\n\n", "before_files": [{"content": "from django.contrib import admin\nfrom django.db.models.query import Prefetch\nfrom django.urls import reverse\nfrom django.utils.html import format_html\nfrom django.utils.safestring import mark_safe\n\nfrom .models import (\n    FaceDetectionPhoto,\n    PhotoFaceEncoding,\n    ReferenceFace,\n    ReferenceFaceEncoding,\n)\n\n\nclass ReferenceFaceEncodingInline(admin.TabularInline):\n    model = ReferenceFaceEncoding\n    readonly_fields = [\"num_matches\"]\n    fields = [\"num_matches\"]\n    can_delete = False\n    extra = 0\n\n    def has_add_permission(self, request, obj=None):\n        return False  # Encodings should not be created manually.\n\n    def get_queryset(self, request):\n        return super().get_queryset(request).only(\"reference\")\n\n\n@admin.register(ReferenceFace)\nclass ReferenceFaceAdmin(admin.ModelAdmin):\n    list_display = [\n        \"user\",\n        \"status\",\n        \"created_at\",\n        \"marked_for_deletion_at\",\n    ]\n\n    search_fields = [\n        \"user__username\",\n        \"user__first_name\",\n        \"user__last_name\",\n    ]\n\n    list_filter = [\"status\", \"marked_for_deletion_at\"]\n    inlines = [ReferenceFaceEncodingInline]\n\n    def get_readonly_fields(self, request, obj=None):\n        if obj is None:\n            return [\"created_at\", \"submitted_at\", \"status\"]\n        return [\"file\", \"user\", \"created_at\", \"submitted_at\", \"status\"]\n\n\nclass PhotoFaceEncodingInline(admin.TabularInline):\n    model = PhotoFaceEncoding\n    readonly_fields = [\"view_matches\"]\n    fields = [\"view_matches\"]\n    can_delete = False\n    extra = 0\n\n    @admin.display(description=\"Matches\")\n    def view_matches(self, obj):\n        reference_faces = [match.reference for match in obj.matches.all()]\n        if not reference_faces:\n            return \"-\"\n\n        links = [\n            format_html(\n                '<a href=\"{url}\">{text}</a>',\n                url=reverse(\n                    \"admin:facedetection_referenceface_change\",\n                    kwargs={\"object_id\": rf.pk},\n                ),\n                text=str(rf),\n            )\n            for rf in reference_faces\n        ]\n        return mark_safe(\", \".join(links))\n\n    def has_add_permission(self, request, obj=None):\n        return False  # Encodings should not be created manually.\n\n    def get_queryset(self, request):\n        return (\n            super()\n            .get_queryset(request)\n            .only(\"photo\")  # Don't select the 128 encoding fields.\n            .prefetch_related(\n                \"photo__photo__album\",\n                Prefetch(\n                    \"matches\",\n                    queryset=ReferenceFaceEncoding.objects.select_related(\n                        \"reference\", \"reference__user\"\n                    ).only(\"reference\"),\n                ),\n            )\n        )\n\n\n@admin.register(FaceDetectionPhoto)\nclass FaceDetectionPhotoAdmin(admin.ModelAdmin):\n    list_display = [\n        \"__str__\",\n        \"status\",\n        \"submitted_at\",\n        \"num_faces\",\n    ]\n\n    readonly_fields = [\n        \"photo\",\n        \"submitted_at\",\n        \"status\",\n    ]\n\n    search_fields = [\n        \"photo__album__title\",\n        \"photo__album__date\",\n        \"photo__file\",\n    ]\n\n    list_filter = [\"status\", \"submitted_at\"]\n    inlines = [PhotoFaceEncodingInline]\n\n    def get_queryset(self, request):\n        return (\n            super()\n            .get_queryset(request)\n            .select_related(\"photo\")\n            .prefetch_related(\"photo__album\")\n            .select_properties(\"num_faces\")\n        )\n\n    def has_add_permission(self, request):\n        return False\n", "path": "website/facedetection/admin.py"}]}