fix: enhance folder download endpoint with zip file support (#4706)
* expanding download folder to zip file * run formatter * Update src/backend/base/langflow/api/v1/folders.py Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> * changing model to flowRead * run formatter --------- Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
parent
25a0d7674a
commit
9e8715cf4c
4 changed files with 80 additions and 30 deletions
|
|
@ -1,16 +1,22 @@
|
|||
import io
|
||||
import json
|
||||
import zipfile
|
||||
from datetime import datetime, timezone
|
||||
from typing import Annotated
|
||||
|
||||
import orjson
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi_pagination import Params
|
||||
from fastapi_pagination.ext.sqlmodel import paginate
|
||||
from sqlalchemy import or_, update
|
||||
from sqlalchemy.orm import selectinload
|
||||
from sqlmodel import select
|
||||
|
||||
from langflow.api.utils import AsyncDbSession, CurrentActiveUser, cascade_delete_flow, custom_params
|
||||
from langflow.api.utils import AsyncDbSession, CurrentActiveUser, cascade_delete_flow, custom_params, remove_api_keys
|
||||
from langflow.api.v1.flows import create_flows
|
||||
from langflow.api.v1.schemas import FlowListCreate, FlowListReadWithFolderName
|
||||
from langflow.api.v1.schemas import FlowListCreate
|
||||
from langflow.helpers.flow import generate_unique_flow_name
|
||||
from langflow.helpers.folders import generate_unique_folder_name
|
||||
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
|
||||
|
|
@ -248,28 +254,53 @@ async def delete_folder(
|
|||
raise HTTPException(status_code=500, detail=str(e)) from e
|
||||
|
||||
|
||||
@router.get("/download/{folder_id}", response_model=FlowListReadWithFolderName, status_code=200)
|
||||
@router.get("/download/{folder_id}", status_code=200)
|
||||
async def download_file(
|
||||
*,
|
||||
session: AsyncDbSession,
|
||||
folder_id: str,
|
||||
current_user: CurrentActiveUser,
|
||||
):
|
||||
"""Download all flows from folder."""
|
||||
"""Download all flows from folder as a zip file."""
|
||||
try:
|
||||
folder = (
|
||||
await session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id))
|
||||
).first()
|
||||
query = select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)
|
||||
result = await session.exec(query)
|
||||
folder = result.first()
|
||||
|
||||
if not folder:
|
||||
raise HTTPException(status_code=404, detail="Folder not found")
|
||||
|
||||
flows_query = select(Flow).where(Flow.folder_id == folder_id)
|
||||
flows_result = await session.exec(flows_query)
|
||||
flows = [FlowRead.model_validate(flow, from_attributes=True) for flow in flows_result.all()]
|
||||
|
||||
if not flows:
|
||||
raise HTTPException(status_code=404, detail="No flows found in folder")
|
||||
|
||||
flows_without_api_keys = [remove_api_keys(flow.model_dump()) for flow in flows]
|
||||
zip_stream = io.BytesIO()
|
||||
|
||||
with zipfile.ZipFile(zip_stream, "w") as zip_file:
|
||||
for flow in flows_without_api_keys:
|
||||
flow_json = json.dumps(jsonable_encoder(flow))
|
||||
zip_file.writestr(f"{flow['name']}.json", flow_json)
|
||||
|
||||
zip_stream.seek(0)
|
||||
|
||||
current_time = datetime.now(tz=timezone.utc).astimezone().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"{current_time}_{folder.name}_flows.zip"
|
||||
|
||||
return StreamingResponse(
|
||||
zip_stream,
|
||||
media_type="application/x-zip-compressed",
|
||||
headers={"Content-Disposition": f"attachment; filename={filename}"},
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
if "No result found" in str(e):
|
||||
raise HTTPException(status_code=404, detail="Folder not found") from e
|
||||
raise HTTPException(status_code=500, detail=str(e)) from e
|
||||
|
||||
if not folder:
|
||||
raise HTTPException(status_code=404, detail="Folder not found")
|
||||
|
||||
return folder
|
||||
|
||||
|
||||
@router.post("/upload/", response_model=list[FlowRead], status_code=201)
|
||||
async def upload_file(
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class FlowListRead(BaseModel):
|
|||
|
||||
class FlowListReadWithFolderName(BaseModel):
|
||||
flows: list[FlowRead]
|
||||
name: str
|
||||
folder_name: str
|
||||
description: str
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue