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/upload.py

94 lines
2.7 KiB
Python

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