72 lines
2.2 KiB
Python
72 lines
2.2 KiB
Python
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,
|
|
)
|