Files
CosScene/server/app/api/v1/endpoints/upload.py
T
2026-05-09 16:40:29 +08:00

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,
)