feat folder download as zip
This commit is contained in:
parent
d63a41fbc8
commit
6296b79ad0
1 changed files with 66 additions and 0 deletions
|
|
@ -441,6 +441,72 @@ def move_folder(
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/folders/{folderId}/download")
|
||||||
|
@limiter.limit("10/minute")
|
||||||
|
def download_folder(
|
||||||
|
request: Request,
|
||||||
|
folderId: str = Path(..., description="ID of the folder to download as ZIP"),
|
||||||
|
currentUser: User = Depends(getCurrentUser),
|
||||||
|
context: RequestContext = Depends(getRequestContext)
|
||||||
|
) -> Response:
|
||||||
|
"""Download a folder (including subfolders) as a ZIP archive."""
|
||||||
|
import io
|
||||||
|
import zipfile
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
try:
|
||||||
|
mgmt = interfaceDbManagement.getInterface(
|
||||||
|
currentUser,
|
||||||
|
mandateId=str(context.mandateId) if context.mandateId else None,
|
||||||
|
featureInstanceId=str(context.featureInstanceId) if context.featureInstanceId else None,
|
||||||
|
)
|
||||||
|
|
||||||
|
folder = mgmt.getFolder(folderId)
|
||||||
|
if not folder:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Folder {folderId} not found")
|
||||||
|
|
||||||
|
folderName = folder.get("name", "download")
|
||||||
|
|
||||||
|
def _collectFiles(parentId: str, pathPrefix: str):
|
||||||
|
"""Recursively collect (zipPath, fileId) tuples."""
|
||||||
|
entries = []
|
||||||
|
for f in mgmt._getFilesByCurrentUser(recordFilter={"folderId": parentId}):
|
||||||
|
fname = f.get("fileName") or f.get("name") or f.get("id", "file")
|
||||||
|
entries.append((f"{pathPrefix}{fname}", f["id"]))
|
||||||
|
for sub in mgmt.listFolders(parentId=parentId):
|
||||||
|
subName = sub.get("name", sub["id"])
|
||||||
|
entries.extend(_collectFiles(sub["id"], f"{pathPrefix}{subName}/"))
|
||||||
|
return entries
|
||||||
|
|
||||||
|
fileEntries = _collectFiles(folderId, "")
|
||||||
|
if not fileEntries:
|
||||||
|
raise HTTPException(status_code=404, detail="Folder is empty")
|
||||||
|
|
||||||
|
buf = io.BytesIO()
|
||||||
|
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||||
|
for zipPath, fileId in fileEntries:
|
||||||
|
data = mgmt.getFileData(fileId)
|
||||||
|
if data:
|
||||||
|
zf.writestr(zipPath, data)
|
||||||
|
|
||||||
|
buf.seek(0)
|
||||||
|
zipBytes = buf.getvalue()
|
||||||
|
encodedName = urllib.parse.quote(f"{folderName}.zip")
|
||||||
|
|
||||||
|
return Response(
|
||||||
|
content=zipBytes,
|
||||||
|
media_type="application/zip",
|
||||||
|
headers={
|
||||||
|
"Content-Disposition": f"attachment; filename*=UTF-8''{encodedName}"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error downloading folder as ZIP: {e}")
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error downloading folder: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/batch-delete")
|
@router.post("/batch-delete")
|
||||||
@limiter.limit("10/minute")
|
@limiter.limit("10/minute")
|
||||||
def batch_delete_items(
|
def batch_delete_items(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue