from __future__ import annotations import hashlib from pathlib import Path from fastapi import APIRouter, Depends, File, Request, UploadFile from sqlalchemy.orm import Session from iti.auth import require_user from iti.db import get_db from iti.responses import ok from iti.storage import StorageManager from iti_system.models import SysFile from iti_system.services import dump_file, new_id router = APIRouter(prefix="/upload", tags=["common.upload"]) @router.post("", dependencies=[Depends(require_user)]) def upload_file( request: Request, file: UploadFile = File(...), db: Session = Depends(get_db), ): file_id = new_id() suffix = Path(file.filename or "").suffix key = f"{file_id}{suffix}" content = file.file.read() storage = StorageManager.get_storage( config=request.app.state.config.file_storage, base_dir=request.app.state.config.base_dir, ) storage_info = storage.upload(_BytesReader(content), key, file.content_type) item = SysFile( id=file_id, filename=file.filename or key, file_key=key, file_hash=hashlib.sha256(content).hexdigest(), mime_type=file.content_type, file_size=len(content), extension=suffix.lstrip(".") or None, storage_type=storage.storage_type, storage_info=storage_info, ) db.add(item) db.commit() db.refresh(item) return ok(dump_file(item)) @router.post("/chunk/init", dependencies=[Depends(require_user)]) def init_chunk_upload(filename: str): return ok({"uploadId": new_id(), "filename": filename}) @router.post("/chunk/upload", dependencies=[Depends(require_user)]) def upload_chunk(upload_id: str, chunk_index: int): return ok({"uploadId": upload_id, "chunkIndex": chunk_index}) @router.post("/chunk/merge", dependencies=[Depends(require_user)]) def merge_chunk(upload_id: str): return ok({"uploadId": upload_id, "status": "merged"}) @router.delete("/chunk/{upload_id}", dependencies=[Depends(require_user)]) def cancel_chunk(upload_id: str): return ok({"uploadId": upload_id}) @router.get("/chunk/{upload_id}/progress", dependencies=[Depends(require_user)]) def chunk_progress(upload_id: str): return ok({"uploadId": upload_id, "uploadedChunks": []}) @router.post("/chunk/cleanup", dependencies=[Depends(require_user)]) def cleanup_chunk(days: int = 7): return ok({"days": days}) class _BytesReader: def __init__(self, value: bytes) -> None: self._value = value self._offset = 0 def read(self, size: int = -1) -> bytes: if size is None or size < 0: size = len(self._value) - self._offset chunk = self._value[self._offset : self._offset + size] self._offset += len(chunk) return chunk