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

153 lines
4.5 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
from .schemas import SubmissionOut, ImageCropIn, ImageCropOut
from .tasks import process_submission_file, process_crop
router = Router()
PREFIX = "/events/{event_path}/submissions"
@router.post(f"{PREFIX}/submission/create", response=SubmissionOut)
def create_submission(
request: HttpRequest,
event_path: str,
game_path: str,
files: List[UploadedFile] = File(...),
notes: Optional[str] = Form(None),
):
game = get_object_or_404(
Game.objects.enabled_for_event(request.event), path=game_path
)
submission = Submission.objects.create(
event=request.event,
game=game,
user=request.user if request.user.is_authenticated else None,
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=list[SubmissionOut])
def list_user_submissions(request: HttpRequest, event_path: str, game_path: str):
game = get_object_or_404(Game, path=game_path)
if not request.user.is_authenticated:
return 403, {"detail": "Authentication required"}
submissions = Submission.for_event.filter(game=game, 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(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"}