start
This commit is contained in:
62
backend/app/services/photos.py
Normal file
62
backend/app/services/photos.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import uuid
|
||||
from mimetypes import guess_extension
|
||||
|
||||
from fastapi import UploadFile
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.models.object_photo import ObjectPhoto
|
||||
from app.schemas.photo import PhotoRead
|
||||
|
||||
ALLOWED_CONTENT_TYPES = {"image/jpeg", "image/png", "image/webp", "image/heic"}
|
||||
|
||||
|
||||
def build_photo_read(photo: ObjectPhoto) -> PhotoRead:
|
||||
settings = get_settings()
|
||||
url = f"{settings.minio_public_url}/{settings.minio_bucket}/{photo.storage_key}"
|
||||
return PhotoRead(id=photo.id, url=url, content_type=photo.content_type, position=photo.position)
|
||||
|
||||
|
||||
async def upload_photo(
|
||||
db: AsyncSession, minio_client, object_id: uuid.UUID, upload_file: UploadFile
|
||||
) -> ObjectPhoto:
|
||||
if upload_file.content_type not in ALLOWED_CONTENT_TYPES:
|
||||
raise ValueError(f"Unsupported content type: {upload_file.content_type}")
|
||||
|
||||
settings = get_settings()
|
||||
extension = guess_extension(upload_file.content_type) or ""
|
||||
photo_id = uuid.uuid4()
|
||||
storage_key = f"objects/{object_id}/{photo_id}{extension}"
|
||||
|
||||
body = await upload_file.read()
|
||||
await run_in_threadpool(
|
||||
minio_client.put_object,
|
||||
Bucket=settings.minio_bucket,
|
||||
Key=storage_key,
|
||||
Body=body,
|
||||
ContentType=upload_file.content_type,
|
||||
)
|
||||
|
||||
max_position = await db.scalar(
|
||||
select(func.coalesce(func.max(ObjectPhoto.position), -1)).where(ObjectPhoto.object_id == object_id)
|
||||
)
|
||||
photo = ObjectPhoto(
|
||||
id=photo_id,
|
||||
object_id=object_id,
|
||||
storage_key=storage_key,
|
||||
content_type=upload_file.content_type,
|
||||
position=max_position + 1,
|
||||
)
|
||||
db.add(photo)
|
||||
await db.commit()
|
||||
await db.refresh(photo)
|
||||
return photo
|
||||
|
||||
|
||||
async def delete_photo(db: AsyncSession, minio_client, photo: ObjectPhoto) -> None:
|
||||
settings = get_settings()
|
||||
await run_in_threadpool(minio_client.delete_object, Bucket=settings.minio_bucket, Key=photo.storage_key)
|
||||
await db.delete(photo)
|
||||
await db.commit()
|
||||
Reference in New Issue
Block a user