import uuid from pathlib import Path from fastapi import APIRouter, Depends, HTTPException, Request, UploadFile, status from app.core.deps import get_current_active_user from app.core.rate_limit import RateLimiter from app.core.storage import S3StorageBackend from app.models.user import User from app.schemas.upload import PresignedUrlRequest, PresignedUrlResponse, UploadResponse router = APIRouter() ALLOWED_TYPES = {"image/jpeg", "image/png", "image/gif", "image/webp"} MAX_SIZE = 10 * 1024 * 1024 # 10MB @router.post( "/image", response_model=UploadResponse, dependencies=[Depends(RateLimiter(times=20, seconds=60))], ) async def upload_image( request: Request, file: UploadFile, current_user: User = Depends(get_current_active_user), ): if file.content_type not in ALLOWED_TYPES: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unsupported file type: {file.content_type}", ) data = await file.read() if len(data) > MAX_SIZE: raise HTTPException( status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail="File too large, max 10MB", ) storage = request.app.state.storage url = storage.upload(data, file.filename or "image.jpg", file.content_type or "") return UploadResponse(url=url, filename=file.filename or "image.jpg") @router.post("/presigned", response_model=PresignedUrlResponse) async def get_presigned_upload_url( request: Request, payload: PresignedUrlRequest, current_user: User = Depends(get_current_active_user), ): storage = request.app.state.storage if not isinstance(storage, S3StorageBackend): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Presigned URLs only available with S3 storage backend", ) ext = Path(payload.filename).suffix or ".jpg" file_key = f"images/{uuid.uuid4().hex}{ext}" upload_url = storage.generate_presigned_url( file_key, content_type=payload.content_type ) public_url = storage._get_url(file_key) return PresignedUrlResponse( upload_url=upload_url, file_key=file_key, public_url=public_url, )