"""Admin media library API - list & upload images (session-authenticated).""" import os import uuid from pathlib import Path from fastapi import APIRouter, HTTPException, Request, UploadFile from fastapi.responses import JSONResponse from app.core.config import settings router = APIRouter(prefix="/admin/api/media", tags=["admin-media"]) ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".webp"} MAX_SIZE = 10 * 1024 * 1024 def _check_admin_session(request: Request): uid = request.session.get("admin_user_id") if not uid: raise HTTPException(status_code=401, detail="未登录") @router.get("/list") async def list_media(request: Request): _check_admin_session(request) images = [] if settings.STORAGE_BACKEND == "local": upload_dir = Path(settings.LOCAL_STORAGE_PATH) if upload_dir.exists(): for f in sorted(upload_dir.iterdir(), key=lambda p: p.stat().st_mtime, reverse=True): if f.is_file() and f.suffix.lower() in ALLOWED_EXTENSIONS: images.append({ "url": f"/uploads/{f.name}", "name": f.name, "size": f.stat().st_size, }) else: storage = request.app.state.storage try: resp = storage.client.list_objects_v2(Bucket=storage.bucket, Prefix="images/", MaxKeys=200) for obj in resp.get("Contents", []): key = obj["Key"] ext = Path(key).suffix.lower() if ext in ALLOWED_EXTENSIONS: images.append({ "url": storage._get_url(key), "name": Path(key).name, "size": obj.get("Size", 0), }) except Exception: pass return JSONResponse({"images": images}) @router.post("/upload") async def upload_media(request: Request, file: UploadFile): _check_admin_session(request) if not file.filename: raise HTTPException(status_code=400, detail="缺少文件") ext = Path(file.filename).suffix.lower() if ext not in ALLOWED_EXTENSIONS: raise HTTPException(status_code=400, detail=f"不支持的文件类型: {ext}") data = await file.read() if len(data) > MAX_SIZE: raise HTTPException(status_code=413, detail="文件过大,最大10MB") storage = request.app.state.storage url = storage.upload(data, file.filename, file.content_type or "") return JSONResponse({"url": url, "name": file.filename})