Skip to content

Commit

Permalink
more REST-y image upload
Browse files Browse the repository at this point in the history
  • Loading branch information
dimbleby committed Jul 1, 2023
1 parent 30a4816 commit e26e180
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 75 deletions.
40 changes: 28 additions & 12 deletions hunt/apiviews.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from __future__ import annotations

import json
from typing import TYPE_CHECKING, Generic, TypeVar
from uuid import uuid4

from rest_framework import serializers, status, viewsets
from rest_framework.decorators import action
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.parsers import MultiPartParser
from rest_framework.response import Response

from hunt.constants import HINTS_PER_LEVEL
from hunt.models import Hint, Level
from hunt.third_party.apimixin import AllowPUTAsCreateMixin

T = TypeVar("T", bound="Model")
if TYPE_CHECKING:
Expand Down Expand Up @@ -51,27 +51,43 @@ class Meta:
]


class LevelViewSet(AllowPUTAsCreateMixin, ModelViewSet[Level]):
class LevelViewSet(ModelViewSet[Level]):
queryset = Level.objects.all().order_by("number")
serializer_class = LevelSerializer
http_method_names = ["delete", "get", "head", "patch", "put"] # noqa: RUF012
http_method_names = [ # noqa: RUF012
"delete",
"get",
"head",
"patch",
"post",
"put",
]

@action(
detail=True,
methods=["put"],
url_path="hints/(?P<number>\\d+)",
parser_classes=[FormParser, MultiPartParser],
methods=["post"],
url_path="hint",
parser_classes=[MultiPartParser],
)
def save_hint(self, request: Request, pk: str, number: str) -> Response:
# Check that it's a sensible hint.
if int(number) >= HINTS_PER_LEVEL:
def save_hint(self, request: Request, pk: str) -> Response:
try:
data = request.data["data"]
details = json.loads(data)
number = details["number"]
except (KeyError, ValueError):
return Response(
"hint number not provided", status=status.HTTP_400_BAD_REQUEST
)

if number >= HINTS_PER_LEVEL:
return Response(
f"Hint {number} is too high", status=status.HTTP_400_BAD_REQUEST
)

# Check that we have a file, and that it seems to be an image.
upload = next(iter(request.data.values()), None)
if upload is None:
try:
upload = request.data["file"]
except KeyError:
return Response("no file attached", status=status.HTTP_400_BAD_REQUEST)

extension = EXTENSIONS.get(upload.content_type)
Expand Down
Empty file removed hunt/third_party/__init__.py
Empty file.
59 changes: 0 additions & 59 deletions hunt/third_party/apimixin.py

This file was deleted.

12 changes: 8 additions & 4 deletions upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,24 @@ def upload_hint(level: int, hint: int, image: Path) -> None:
Upload a hint.
:param level: The level that the hint belongs to. The level must already exist.
:param number: The hint number. Zero-indexed.
:param hint: The hint number. Zero-indexed.
:param image: The file containing the hint.
"""
suffix = image.suffix
content_type = CONTENT_TYPES.get(suffix.lower())
if content_type is None:
raise RuntimeError(f"unrecognized suffix: {suffix}")

url = f"{SERVER}/api/levels/{level}/hints/{hint}"
url = f"{SERVER}/api/levels/{level}/hint"
payload = {"number": hint}
with image.open("rb") as f:
r = requests.put(
r = requests.post(
url,
auth=(USERNAME, PASSWORD),
files={"hint": (image.name, f, content_type)},
files={ # type: ignore[arg-type]
"file": (image.name, f, content_type),
"data": (None, json.dumps(payload), "application/json"),
},
timeout=5,
)

Expand Down

0 comments on commit e26e180

Please sign in to comment.