Files
companion-assistant/backend/app/api/files.py
T

91 lines
3.1 KiB
Python

"""文件路由:上传 / 列表 / 下载 / 删除。"""
import hashlib
import uuid
from pathlib import Path
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from ..config import settings
from ..core.deps import get_current_user
from ..core.response import ok
from ..database import get_db
from ..models import FileEntry, User
router = APIRouter(prefix="/files", tags=["文件"])
def _file_out(f: FileEntry) -> dict:
return {"id": f.id, "project_id": f.project_id, "filename": f.filename, "size": f.size,
"mime": f.mime, "created_at": f.created_at.isoformat()}
@router.post("/upload")
async def upload_file(
file: UploadFile = File(...),
project_id: int | None = Form(None),
user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
data = await file.read()
if len(data) > settings.MAX_UPLOAD_MB * 1024 * 1024:
raise HTTPException(status_code=413, detail=f"文件超过 {settings.MAX_UPLOAD_MB}MB 限制")
stored_name = f"{uuid.uuid4().hex}_{file.filename}"
target = settings.UPLOAD_DIR / stored_name
target.write_bytes(data)
entry = FileEntry(
user_id=user.id, project_id=project_id, filename=file.filename,
stored_path=str(target), size=len(data), mime=file.content_type or "",
sha256=hashlib.sha256(data).hexdigest(),
)
db.add(entry)
db.commit()
db.refresh(entry)
return ok(_file_out(entry))
@router.get("")
def list_files(user: User = Depends(get_current_user), db: Session = Depends(get_db)):
files = db.query(FileEntry).filter(FileEntry.user_id == user.id).order_by(FileEntry.id.desc()).all()
return ok([_file_out(f) for f in files])
def _get_owned(db: Session, user: User, file_id: int) -> FileEntry:
f = db.get(FileEntry, file_id)
if not f or f.user_id != user.id:
raise HTTPException(status_code=404, detail="文件不存在")
return f
@router.get("/{file_id}/content")
def file_content(file_id: int, user: User = Depends(get_current_user), db: Session = Depends(get_db)):
"""内联内容(图片预览等,鉴权)。"""
f = _get_owned(db, user, file_id)
path = Path(f.stored_path)
if not path.exists():
raise HTTPException(status_code=404, detail="文件已丢失")
return FileResponse(path, media_type=f.mime or "application/octet-stream")
@router.get("/{file_id}/download")
def download_file(file_id: int, user: User = Depends(get_current_user), db: Session = Depends(get_db)):
f = _get_owned(db, user, file_id)
path = Path(f.stored_path)
if not path.exists():
raise HTTPException(status_code=404, detail="文件已丢失")
return FileResponse(path, filename=f.filename, media_type=f.mime or "application/octet-stream")
@router.delete("/{file_id}")
def delete_file(file_id: int, user: User = Depends(get_current_user), db: Session = Depends(get_db)):
f = _get_owned(db, user, file_id)
path = Path(f.stored_path)
if path.exists():
path.unlink()
db.delete(f)
db.commit()
return ok(message="已删除")