Phase 6.5 Fix: DMS Download Endpoint fuer alle Dateitypen
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:
Agent Zero
2026-08-03 15:02:39 +02:00
parent 29d55cb187
commit 8b683c7da7
+50
View File
@@ -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,