Files
mokeeText/backend/routes/upload.py
2026-07-15 16:08:17 +08:00

102 lines
3.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""文件上传/读取 — 数据库存储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)):
"""读取图片 — 公开访问(不走网关,供编辑器 <img> 标签和分享页加载)
优先从 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}