You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-System/iti_system/routes/common/file_access.py

72 lines
2.7 KiB
Python

from __future__ import annotations
from fastapi import APIRouter, Depends, Query, Request
from fastapi.responses import StreamingResponse
from sqlalchemy import select
from sqlalchemy.orm import Session
from iti.auth import require_user
from iti.db import get_db
from iti.exceptions import BizError
from iti.responses import ok
from iti.storage import StorageManager
from iti_system.models import SysFile
from iti_system.services import dump_file, get_or_404
router = APIRouter(prefix="/file", tags=["common.file"])
@router.get("/share/{share_code}")
def share_file(share_code: str, password: str | None = Query(default=None), db: Session = Depends(get_db)):
item = db.scalar(select(SysFile).where(SysFile.share_code == share_code))
if item is None:
raise BizError("分享不存在", code=404)
if item.share_password and item.share_password != password:
raise BizError("分享密码错误", code=403)
item.share_count += 1
db.commit()
return ok(dump_file(item))
@router.get("/share/{share_code}/download")
def share_download(share_code: str, password: str | None = Query(default=None), db: Session = Depends(get_db)):
item = db.scalar(select(SysFile).where(SysFile.share_code == share_code))
if item is None:
raise BizError("分享不存在", code=404)
if item.share_password and item.share_password != password:
raise BizError("分享密码错误", code=403)
item.share_count += 1
db.commit()
return ok(dump_file(item))
@router.get("/{file_id}/download", dependencies=[Depends(require_user)])
def download_file(file_id: str, request: Request, db: Session = Depends(get_db)):
item = get_or_404(db, SysFile, file_id, "文件不存在")
storage = StorageManager.get_storage(
item.storage_type,
config=request.app.state.config.file_storage,
base_dir=request.app.state.config.base_dir,
)
stream = storage.download(item.file_key)
return StreamingResponse(
stream,
media_type=item.mime_type or "application/octet-stream",
headers={"Content-Disposition": f'attachment; filename="{item.filename}"'},
)
@router.get("/{file_id}/preview", dependencies=[Depends(require_user)])
def preview_file(file_id: str, db: Session = Depends(get_db)):
return ok(dump_file(get_or_404(db, SysFile, file_id, "文件不存在")))
@router.get("/{file_id}/thumbnail", dependencies=[Depends(require_user)])
def thumbnail_file(file_id: str, w: int = 200, h: int = 200, mode: str = "fit", db: Session = Depends(get_db)):
item = get_or_404(db, SysFile, file_id, "文件不存在")
data = dump_file(item)
data.update({"width": w, "height": h, "mode": mode})
return ok(data)