Spaces:
Sleeping
Sleeping
Commit ·
d82d83b
1
Parent(s): e4e485d
Auto-bundle config+pdf to SFTP on send-config or pdf upload
Browse files- backend/api.py +46 -2
backend/api.py
CHANGED
|
@@ -38,6 +38,41 @@ BACKEND_DIR = REPO_ROOT / "backend"
|
|
| 38 |
UPLOADS_DIR = Path(os.environ.get("PDF_TRAINER_UPLOADS_DIR") or "/data/uploads")
|
| 39 |
CONFIGS_DIR = UPLOADS_DIR / "configs"
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
# Load backend/.env explicitly ONCE for this process
|
| 43 |
load_dotenv(BACKEND_DIR / ".env", override=True)
|
|
@@ -73,6 +108,15 @@ async def put_pdf(pdf_id: str, file: UploadFile = File(...), pdf_name: str = For
|
|
| 73 |
(UPLOADS_DIR / f"{pdf_id}.pdf").write_bytes(data)
|
| 74 |
if pdf_name:
|
| 75 |
(UPLOADS_DIR / f"{pdf_id}.name.txt").write_text(pdf_name.strip(), encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
return {"ok": True}
|
| 77 |
|
| 78 |
@app.post("/api/send-config")
|
|
@@ -130,8 +174,8 @@ async def send_config(request: Request):
|
|
| 130 |
except Exception as e:
|
| 131 |
print(f"[SFTP] store failed: {e}")
|
| 132 |
pdf_path = UPLOADS_DIR / f"{pdf_id}.pdf"
|
| 133 |
-
|
| 134 |
-
|
| 135 |
@app.get("/api/config/{pdf_id}/{template_id}")
|
| 136 |
def get_config(pdf_id: str, template_id: str):
|
| 137 |
path = CONFIGS_DIR / f"{pdf_id}__{template_id}.json"
|
|
|
|
| 38 |
UPLOADS_DIR = Path(os.environ.get("PDF_TRAINER_UPLOADS_DIR") or "/data/uploads")
|
| 39 |
CONFIGS_DIR = UPLOADS_DIR / "configs"
|
| 40 |
|
| 41 |
+
def _maybe_bundle_to_sftp(pdf_id: str, template_id: str) -> dict:
|
| 42 |
+
"""
|
| 43 |
+
If both config + PDF exist locally in this API container AND SFTP env vars exist,
|
| 44 |
+
push JSON + PDF to SFTP. Otherwise no-op.
|
| 45 |
+
Returns small status dict.
|
| 46 |
+
"""
|
| 47 |
+
try:
|
| 48 |
+
# only attempt if env looks configured
|
| 49 |
+
if not (os.environ.get("SFTP_HOST") and os.environ.get("SFTP_USER") and os.environ.get("SFTP_PASS")):
|
| 50 |
+
return {"sftp": "skipped_not_configured"}
|
| 51 |
+
|
| 52 |
+
cfg_path = CONFIGS_DIR / f"{pdf_id}__{template_id}.json"
|
| 53 |
+
pdf_path = UPLOADS_DIR / f"{pdf_id}.pdf"
|
| 54 |
+
name_path = UPLOADS_DIR / f"{pdf_id}.name.txt"
|
| 55 |
+
|
| 56 |
+
if not cfg_path.exists():
|
| 57 |
+
return {"sftp": "skipped_no_config"}
|
| 58 |
+
if not pdf_path.exists():
|
| 59 |
+
return {"sftp": "skipped_no_pdf"}
|
| 60 |
+
|
| 61 |
+
cfg_bytes = cfg_path.read_bytes()
|
| 62 |
+
pdf_bytes = pdf_path.read_bytes()
|
| 63 |
+
pdf_name = (name_path.read_text(encoding="utf-8").strip() if name_path.exists() else f"{pdf_id}.pdf") or f"{pdf_id}.pdf"
|
| 64 |
+
|
| 65 |
+
remote_dir = store_to_sftp(
|
| 66 |
+
pdf_id=pdf_id,
|
| 67 |
+
template_id=template_id,
|
| 68 |
+
cfg_json_bytes=cfg_bytes,
|
| 69 |
+
pdf_bytes=pdf_bytes,
|
| 70 |
+
pdf_name=pdf_name,
|
| 71 |
+
)
|
| 72 |
+
return {"sftp": "ok", "remote_dir": remote_dir}
|
| 73 |
+
except Exception as e:
|
| 74 |
+
return {"sftp": "error", "error": str(e)}
|
| 75 |
+
|
| 76 |
|
| 77 |
# Load backend/.env explicitly ONCE for this process
|
| 78 |
load_dotenv(BACKEND_DIR / ".env", override=True)
|
|
|
|
| 108 |
(UPLOADS_DIR / f"{pdf_id}.pdf").write_bytes(data)
|
| 109 |
if pdf_name:
|
| 110 |
(UPLOADS_DIR / f"{pdf_id}.name.txt").write_text(pdf_name.strip(), encoding="utf-8")
|
| 111 |
+
# If any configs already exist for this pdf_id, bundle now.
|
| 112 |
+
sftp_results = []
|
| 113 |
+
try:
|
| 114 |
+
for cfg in CONFIGS_DIR.glob(f"{pdf_id}__*.json"):
|
| 115 |
+
tid = cfg.name.split("__", 1)[1].rsplit(".json", 1)[0]
|
| 116 |
+
sftp_results.append(_maybe_bundle_to_sftp(pdf_id, tid))
|
| 117 |
+
except Exception:
|
| 118 |
+
pass
|
| 119 |
+
|
| 120 |
return {"ok": True}
|
| 121 |
|
| 122 |
@app.post("/api/send-config")
|
|
|
|
| 174 |
except Exception as e:
|
| 175 |
print(f"[SFTP] store failed: {e}")
|
| 176 |
pdf_path = UPLOADS_DIR / f"{pdf_id}.pdf"
|
| 177 |
+
sftp_status = _maybe_bundle_to_sftp(pdf_id, template_id)
|
| 178 |
+
return {"ok": True, "stored": str(out_path), "pdf_exists": pdf_path.exists(), **sftp_status}
|
| 179 |
@app.get("/api/config/{pdf_id}/{template_id}")
|
| 180 |
def get_config(pdf_id: str, template_id: str):
|
| 181 |
path = CONFIGS_DIR / f"{pdf_id}__{template_id}.json"
|