Phase 6.5 Fix: DMS Download Endpoint fuer alle Dateitypen
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
- GET /api/v1/dms/files/{file_id}/download streamt alle Dateitypen
- FileResponse fuer LocalStorage (automatisches Streaming)
- StreamingResponse Fallback fuer S3
- Prueft dms:read Permission und entity access
This commit is contained in:
@@ -888,6 +888,56 @@ async def preview_file(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/files/{file_id}/download", dependencies=[Depends(require_permission("dms:read"))])
|
||||
async def download_file(
|
||||
file_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""Download any file type — streams directly from storage without loading into RAM."""
|
||||
tenant_id = uuid.UUID(current_user["tenant_id"])
|
||||
user_id = uuid.UUID(current_user["user_id"])
|
||||
is_admin = current_user.get("role") == "admin"
|
||||
fid = _parse_uuid(file_id, "file_id")
|
||||
|
||||
result = await db.execute(
|
||||
select(DmsFile).where(
|
||||
DmsFile.id == fid,
|
||||
DmsFile.tenant_id == tenant_id,
|
||||
DmsFile.deleted_at.is_(None),
|
||||
)
|
||||
)
|
||||
dms_file = result.scalar_one_or_none()
|
||||
if dms_file is None:
|
||||
raise HTTPException(404, detail={"detail": "File not found", "code": "not_found"})
|
||||
|
||||
if not await check_single_entity_access(db, "dms_file", fid, user_id, tenant_id, "read", is_admin):
|
||||
raise HTTPException(403, detail={"detail": "Access denied", "code": "forbidden"})
|
||||
|
||||
storage = get_storage_backend()
|
||||
if not await storage.exists(dms_file.storage_path):
|
||||
raise HTTPException(404, detail={"detail": "File not found on disk", "code": "file_missing"})
|
||||
|
||||
from fastapi.responses import FileResponse as FastApiFileResponse
|
||||
|
||||
if isinstance(storage, LocalStorage):
|
||||
full_path = storage._full_path(dms_file.storage_path)
|
||||
return FastApiFileResponse(
|
||||
path=full_path,
|
||||
media_type=dms_file.mime_type or "application/octet-stream",
|
||||
filename=dms_file.name,
|
||||
)
|
||||
else:
|
||||
content = await storage.read(dms_file.storage_path)
|
||||
def _stream():
|
||||
yield content
|
||||
return StreamingResponse(
|
||||
_stream(),
|
||||
media_type=dms_file.mime_type or "application/octet-stream",
|
||||
headers={"Content-Disposition": f'attachment; filename="{dms_file.name}"'},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/files/{file_id}/edit-session", dependencies=[Depends(require_permission("dms:write"))])
|
||||
async def create_edit_session(
|
||||
file_id: str,
|
||||
|
||||
Reference in New Issue
Block a user