|
# retoor <retoor@molodetz.nl>
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from fastapi import APIRouter, Request
|
|
from fastapi.responses import FileResponse, JSONResponse
|
|
|
|
from devplacepy.services.jobs import queue
|
|
from devplacepy.services.jobs.zip_service import ZIPS_DIR
|
|
from devplacepy.schemas import ZipJobOut
|
|
from devplacepy.utils import not_found
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
RETENTION_EXTEND_SECONDS = 7 * 24 * 60 * 60
|
|
|
|
|
|
def _status_payload(job: dict) -> dict:
|
|
result = job.get("result", {})
|
|
done = job.get("status") == queue.DONE
|
|
return {
|
|
"uid": job.get("uid", ""),
|
|
"kind": job.get("kind", ""),
|
|
"status": job.get("status", ""),
|
|
"preferred_name": job.get("preferred_name"),
|
|
"download_url": result.get("download_url") if done else None,
|
|
"error": job.get("error") or None,
|
|
"bytes_in": int(job.get("bytes_in") or 0),
|
|
"bytes_out": int(job.get("bytes_out") or 0),
|
|
"item_count": int(job.get("item_count") or 0),
|
|
"file_count": int(result.get("file_count") or 0),
|
|
"dir_count": int(result.get("dir_count") or 0),
|
|
"created_at": job.get("created_at"),
|
|
"completed_at": job.get("completed_at") or None,
|
|
}
|
|
|
|
|
|
@router.get("/{uid}")
|
|
async def zip_status(request: Request, uid: str):
|
|
job = queue.get_job(uid)
|
|
if not job or job.get("kind") != "zip":
|
|
raise not_found("Job not found")
|
|
return JSONResponse(ZipJobOut.model_validate(_status_payload(job)).model_dump(mode="json"))
|
|
|
|
|
|
@router.get("/{uid}/download")
|
|
async def zip_download(request: Request, uid: str):
|
|
job = queue.get_job(uid)
|
|
if not job or job.get("kind") != "zip" or job.get("status") != queue.DONE:
|
|
raise not_found("Archive not available")
|
|
result = job.get("result", {})
|
|
local_path = result.get("local_path", "")
|
|
resolved = Path(local_path).resolve()
|
|
if not local_path or not resolved.is_relative_to(ZIPS_DIR.resolve()) or not resolved.is_file():
|
|
raise not_found("Archive not available")
|
|
queue.touch_job(uid, RETENTION_EXTEND_SECONDS)
|
|
return FileResponse(resolved, filename=result.get("final_name", "download.zip"), media_type="application/zip")
|