Files
polylan-submitter/polylan_submitter/submissions/api.py
T

178 lines
5.3 KiB
Python

from typing import List, Optional
from uuid import UUID
from django.http import HttpRequest
from ninja import Router, File, Form
from ninja.files import UploadedFile
from django.shortcuts import get_object_or_404
from games.models import Game
from .models import Submission, SubmissionFile, ImageCrop, OCRStatus, Scope
from .schemas import SubmissionOut, ImageCropIn, ImageCropOut, ScopeOut
from .tasks import process_submission_file, process_crop
router = Router()
PREFIX = "/events/{event_path}/submissions"
@router.get(f"{PREFIX}/scopes/mine", response={200: list[ScopeOut], 403: dict})
def list_my_scopes(request: HttpRequest, event_path: str, game_path: str):
if not request.user.is_authenticated:
return 403, {"detail": "Authentication required"}
game = get_object_or_404(
Game.objects.enabled_for_event(request.event), path=game_path
)
return Scope.objects.filter(
event_game__event=request.event,
event_game__game=game,
assigned_users=request.user,
)
@router.post(f"{PREFIX}/submission/create", response={200: SubmissionOut, 403: dict})
def create_submission(
request: HttpRequest,
event_path: str,
scope_id: UUID,
files: List[UploadedFile] = File(...),
notes: Optional[str] = Form(None),
):
if not request.user.is_authenticated:
return 403, {"detail": "Authentication required"}
scope = get_object_or_404(
Scope, id=scope_id, event_game__event=request.event, is_active=True
)
if (
not request.user.is_staff
and not scope.assigned_users.filter(pk=request.user.pk).exists()
):
return 403, {"detail": "You are not assigned to this scope"}
submission = Submission.objects.create(
event=request.event,
scope=scope,
user=request.user,
notes=notes or None,
)
for file in files:
SubmissionFile.objects.create(
submission=submission,
file=file,
original_filename=file.name,
content_type=file.content_type or "application/octet-stream",
)
return submission
@router.get(
f"{PREFIX}/submission/by/user", response={200: list[SubmissionOut], 403: dict}
)
def list_user_submissions(request: HttpRequest, event_path: str, scope_id: UUID):
if not request.user.is_authenticated:
return 403, {"detail": "Authentication required"}
submissions = Submission.for_event.filter(
scope_id=scope_id, user=request.user
).order_by("-created_at")
return submissions
@router.get(f"{PREFIX}/submission/by/game", response=list[SubmissionOut])
def list_submissions_by_game(request: HttpRequest, event_path: str, game_path: str):
game = get_object_or_404(Game, path=game_path)
if not request.user.is_staff:
return 403, {"detail": "Admin access required"}
return Submission.for_event.filter(scope__event_game__game=game)
@router.get(f"{PREFIX}/submission/{{submission_id}}", response=SubmissionOut)
def get_submission(request: HttpRequest, event_path: str, submission_id: UUID):
submission = get_object_or_404(Submission.for_event, id=submission_id)
if submission.user != request.user and not request.user.is_staff:
return 403, {"detail": "Not authorized"}
return submission
@router.post(f"{PREFIX}/crops/s/{{submission_file_id}}", response=ImageCropOut)
def create_image_crop(
request: HttpRequest,
event_path: str,
submission_file_id: UUID,
data: ImageCropIn,
):
if not request.user.is_staff:
return 403, {"detail": "Admin access required"}
submission_file = get_object_or_404(
SubmissionFile, id=submission_file_id, submission__event=request.event
)
crop = ImageCrop.objects.create(
submission_file=submission_file,
x1=data.x1,
y1=data.y1,
x2=data.x2,
y2=data.y2,
label=data.label or "",
ocr_status=OCRStatus.TO_PROCESS,
)
return crop
@router.delete(f"{PREFIX}/crops/{{crop_id}}", response=dict)
def delete_image_crop(request: HttpRequest, event_path: str, crop_id: UUID):
if not request.user.is_staff:
return 403, {"detail": "Admin access required"}
crop = get_object_or_404(
ImageCrop, id=crop_id, submission_file__submission__event=request.event
)
crop.delete()
return {"status": "deleted"}
@router.post(f"{PREFIX}/files/{{file_id}}/process-ocr", response=dict)
def process_file_ocr(request: HttpRequest, event_path: str, file_id: UUID):
if not request.user.is_staff:
return 403, {"detail": "Admin access required"}
submission_file = get_object_or_404(
SubmissionFile, id=file_id, submission__event=request.event
)
submission_file.ocr_status = OCRStatus.TO_PROCESS
submission_file.save()
# Enqueue the OCR processing task
process_submission_file.enqueue(str(file_id))
return {"status": "queued"}
@router.post(f"{PREFIX}/crops/{{crop_id}}/process-ocr", response=dict)
def process_crop_ocr(request: HttpRequest, event_path: str, crop_id: UUID):
if not request.user.is_staff:
return 403, {"detail": "Admin access required"}
crop = get_object_or_404(
ImageCrop, id=crop_id, submission_file__submission__event=request.event
)
crop.ocr_status = OCRStatus.TO_PROCESS
crop.save()
# Enqueue the OCR processing task
process_crop.enqueue(str(crop_id))
return {"status": "queued"}