Add API endpoint to upload images

This commit is contained in:
Antoine Bartuccio 2025-02-26 23:15:26 +01:00
parent 6a17e4480e
commit 6ec79966b1
3 changed files with 79 additions and 2 deletions

View File

@ -1,23 +1,30 @@
from io import BytesIO
from pathlib import Path
from typing import Annotated from typing import Annotated
from uuid import uuid4
import annotated_types import annotated_types
from django.conf import settings from django.conf import settings
from django.core.files.base import ContentFile
from django.db import transaction
from django.db.models import F from django.db.models import F
from django.http import HttpResponse from django.http import HttpResponse
from ninja import Query from ninja import Query, UploadedFile
from ninja_extra import ControllerBase, api_controller, paginate, route from ninja_extra import ControllerBase, api_controller, paginate, route
from ninja_extra.exceptions import PermissionDenied from ninja_extra.exceptions import PermissionDenied
from ninja_extra.pagination import PageNumberPaginationExtra from ninja_extra.pagination import PageNumberPaginationExtra
from ninja_extra.schemas import PaginatedResponseSchema from ninja_extra.schemas import PaginatedResponseSchema
from PIL import Image, UnidentifiedImageError
from club.models import Mailing from club.models import Mailing
from core.auth.api_permissions import CanAccessLookup, CanView from core.auth.api_permissions import CanAccessLookup, CanView, IsOldSubscriber
from core.models import Group, SithFile, User from core.models import Group, SithFile, User
from core.schemas import ( from core.schemas import (
FamilyGodfatherSchema, FamilyGodfatherSchema,
GroupSchema, GroupSchema,
MarkdownSchema, MarkdownSchema,
SithFileSchema, SithFileSchema,
UploadedFileSchema,
UserFamilySchema, UserFamilySchema,
UserFilterSchema, UserFilterSchema,
UserProfileSchema, UserProfileSchema,
@ -33,6 +40,59 @@ class MarkdownController(ControllerBase):
return HttpResponse(markdown(body.text), content_type="text/html") return HttpResponse(markdown(body.text), content_type="text/html")
@api_controller("/upload")
class UploadController(ControllerBase):
@route.post("/images", response=UploadedFileSchema, permissions=[IsOldSubscriber])
def upload_assets(self, file: UploadedFile):
if file.content_type.split("/")[0] != "image":
return self.create_response(
message=f"{file.name} isn't a file image", status_code=400
)
def convert_image(file: UploadedFile) -> ContentFile:
content = BytesIO()
Image.open(BytesIO(file.read())).save(
fp=content, format="webp", optimize=True
)
return ContentFile(content.getvalue())
try:
converted = convert_image(file)
except UnidentifiedImageError:
return self.create_response(
message=f"{file.name} can't be processed", status_code=400
)
with transaction.atomic():
parent = SithFile.objects.filter(parent=None, name="upload").first()
if parent is None:
root = User.objects.get(id=settings.SITH_ROOT_USER_ID)
parent = SithFile.objects.create(
parent=None,
name="upload",
owner=root,
)
image = SithFile(
parent=parent,
name=f"{Path(file.name).stem}_{uuid4()}.webp",
file=converted,
owner=self.context.request.user,
is_folder=False,
mime_type="img/webp",
size=converted.size,
moderator=self.context.request.user,
is_moderated=True,
)
image.file.name = image.name
image.clean()
image.save()
image.view_groups.add(
Group.objects.filter(id=settings.SITH_GROUP_PUBLIC_ID).first()
)
image.save()
return image
@api_controller("/mailings") @api_controller("/mailings")
class MailingListController(ControllerBase): class MailingListController(ControllerBase):
@route.get("", response=str) @route.get("", response=str)

View File

@ -856,6 +856,10 @@ Welcome to the wiki page!
] ]
) )
# Upload folder
SithFile.objects.create(name="upload", owner=root)
(settings.MEDIA_ROOT / "upload").mkdir(parents=True, exist_ok=True)
def _create_profile_pict(self, user: User): def _create_profile_pict(self, user: User):
path = self.SAS_FIXTURE_PATH / "Family" / f"{user.username}.jpg" path = self.SAS_FIXTURE_PATH / "Family" / f"{user.username}.jpg"
file = resize_image(Image.open(path), 400, "WEBP") file = resize_image(Image.open(path), 400, "WEBP")

View File

@ -9,6 +9,7 @@ from django.utils.text import slugify
from haystack.query import SearchQuerySet from haystack.query import SearchQuerySet
from ninja import FilterSchema, ModelSchema, Schema from ninja import FilterSchema, ModelSchema, Schema
from pydantic import AliasChoices, Field from pydantic import AliasChoices, Field
from pydantic_core import Url
from core.models import Group, SithFile, User from core.models import Group, SithFile, User
@ -47,6 +48,18 @@ class UserProfileSchema(ModelSchema):
return reverse("core:download", kwargs={"file_id": obj.profile_pict_id}) return reverse("core:download", kwargs={"file_id": obj.profile_pict_id})
class UploadedFileSchema(ModelSchema):
class Meta:
model = SithFile
fields = ["id", "name", "mime_type", "size"]
href: str
@staticmethod
def resolve_href(obj: SithFile) -> Url:
return reverse("core:download", kwargs={"file_id": obj.id})
class SithFileSchema(ModelSchema): class SithFileSchema(ModelSchema):
class Meta: class Meta:
model = SithFile model = SithFile