"""文件上传/读取 — 数据库存储(file_service.py 为可选备用方案,保留不删)""" from fastapi import APIRouter, UploadFile, File, Depends, HTTPException, Request from fastapi.responses import Response from sqlalchemy.orm import Session from logger import logger from models import get_db, Upload from middleware.user_context import UserContext # 文件服务模块保留备用(不删除),如需切换取消下面注释即可 # from file_service import upload_file, download_file, delete_file router = APIRouter(tags=["上传"]) ALLOWED = {"image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"} MAX_SIZE = 20 * 1024 * 1024 # 20MB @router.post("/api/upload/image") async def upload_image(file: UploadFile = File(...), db: Session = Depends(get_db), request: Request = None): """上传图片 — 存入数据库 LONGBLOB""" user_id = UserContext.get_user_id(request) try: if file.content_type not in ALLOWED: raise HTTPException(400, f"不支持的图片格式: {file.content_type}") data = await file.read() if len(data) > MAX_SIZE: raise HTTPException(400, f"图片不能超过 20MB,当前 {len(data)} 字节") filename = file.filename or "img" logger.info(f"上传图片: {filename}, {len(data)} bytes, {file.content_type}, user={user_id}") upload = Upload( filename=filename, content_type=file.content_type, data=data, size=len(data), created_by=user_id, ) db.add(upload) db.commit() db.refresh(upload) logger.info(f"图片已存入 DB, id={upload.id}") return {"url": f"/api/file/{upload.id}"} except HTTPException: raise except Exception as e: logger.error(f"上传失败: {e}") raise HTTPException(500, f"上传失败: {str(e)}") @router.get("/api/file/{file_id}") def get_file(file_id: int, db: Session = Depends(get_db)): """读取图片 — 公开访问(不走网关,供编辑器 标签和分享页加载) 优先从 DB blob 读取;如为文件服务存储则代理下载 """ upload = db.query(Upload).filter_by(id=file_id).first() if not upload: raise HTTPException(404, "文件不存在") # DB blob(主存储方式) if upload.data: return Response(content=upload.data, media_type=upload.content_type) # 文件服务存储(兼容之前上传的文件) if upload.file_id: from file_service import download_file try: data, content_type, _ = download_file(upload.file_id) return Response(content=data, media_type=content_type) except FileNotFoundError: raise HTTPException(404, "文件在文件服务中不存在") except Exception as e: logger.error(f"从文件服务下载失败: {e}") raise HTTPException(500, f"下载文件失败: {str(e)}") raise HTTPException(404, "文件数据不存在") @router.delete("/api/file/{file_id}") def delete_file_api(file_id: int, db: Session = Depends(get_db), request: Request = None): """删除图片 — 从 DB 和文件服务中删除""" user_id = UserContext.get_user_id(request) upload = db.query(Upload).filter_by(id=file_id).first() if not upload: raise HTTPException(404, "文件不存在") # 如果存在文件服务记录,同步删除 if upload.file_id: from file_service import delete_file try: delete_file(upload.file_id) logger.info(f"文件服务删除成功, fileId={upload.file_id}") except Exception as e: logger.error(f"文件服务删除失败: {e}") db.delete(upload) db.commit() logger.info(f"图片记录已删除, db_id={file_id}, user={user_id}") return {"ok": True}