Avinashnalla7 commited on
Commit
eaeeb44
·
1 Parent(s): 5b492d5

api: accept PDF uploads + serve PDFs locally

Browse files
Files changed (1) hide show
  1. backend/api.py +39 -21
backend/api.py CHANGED
@@ -1,6 +1,7 @@
1
  from __future__ import annotations
2
 
3
  import json
 
4
  import os
5
  import socket
6
  import paramiko
@@ -13,8 +14,6 @@ from dotenv import load_dotenv
13
  from fastapi import FastAPI, HTTPException, Response
14
  from fastapi.middleware.cors import CORSMiddleware
15
  from fastapi.responses import FileResponse
16
- from backend.sftp_store import download_bytes
17
- from backend.sftp_store import download_bytes
18
 
19
 
20
  # ------------------------------------------------------------------
@@ -106,27 +105,46 @@ def root() -> Dict[str, str]:
106
  # API endpoints
107
  # ------------------------------------------------------------------
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  @app.get("/api/pdf/{pdf_id}")
110
  def get_pdf(pdf_id: str):
111
- # Read from SFTP path: /inserio/pdfs/<pdf_id>.pdf (SFTP_ROOT handles /inserio)
112
- name = pdf_id
113
- if not name.lower().endswith(".pdf"):
114
- remote_path = f"pdfs/{name}.pdf"
115
- else:
116
- remote_path = f"pdfs/{name}"
117
-
118
- # Hard timeout so requests never hang
119
- with concurrent.futures.ThreadPoolExecutor(max_workers=1) as ex:
120
- fut = ex.submit(download_bytes, remote_path)
121
- try:
122
- data = fut.result(timeout=10)
123
- except concurrent.futures.TimeoutError:
124
- from fastapi import HTTPException
125
- raise HTTPException(status_code=504, detail="SFTP timeout reading PDF")
126
-
127
- # Return raw bytes
128
- from fastapi.responses import Response
129
- return Response(content=data, media_type="application/pdf")
130
  return Response(content=data, media_type="application/pdf")
131
 
132
  @app.post("/api/send-config")
 
1
  from __future__ import annotations
2
 
3
  import json
4
+ import re
5
  import os
6
  import socket
7
  import paramiko
 
14
  from fastapi import FastAPI, HTTPException, Response
15
  from fastapi.middleware.cors import CORSMiddleware
16
  from fastapi.responses import FileResponse
 
 
17
 
18
 
19
  # ------------------------------------------------------------------
 
105
  # API endpoints
106
  # ------------------------------------------------------------------
107
 
108
+ # ------------------------------------------------------------------
109
+ # PDF storage (local to API container)
110
+ # Worker uploads PDFs here. UI fetches from here.
111
+ # ------------------------------------------------------------------
112
+
113
+ PDF_STORE_DIR = Path(os.getenv("PDF_STORE_DIR", "/app/data/pdfs")).resolve()
114
+ PDF_STORE_DIR.mkdir(parents=True, exist_ok=True)
115
+
116
+ def _require_worker_token(x_worker_token: Optional[str]):
117
+ # reuse global WORKER_TOKEN if you already have it later in the file
118
+ token = os.getenv("WORKER_TOKEN", "").strip()
119
+ if not token:
120
+ raise HTTPException(status_code=500, detail="Server missing WORKER_TOKEN")
121
+ if not x_worker_token or x_worker_token != token:
122
+ raise HTTPException(status_code=401, detail="Unauthorized worker")
123
+
124
+ def _safe_id(s: str) -> str:
125
+ # keep it simple: allow only safe filename chars
126
+ return re.sub(r"[^a-zA-Z0-9_.-]+", "_", s)
127
+
128
+ @app.post("/api/pdf/{pdf_id}")
129
+ async def put_pdf(pdf_id: str, request: Request, x_worker_token: Optional[str] = Header(default=None)):
130
+ _require_worker_token(x_worker_token)
131
+ pid = _safe_id(pdf_id)
132
+ data = await request.body()
133
+ if not data:
134
+ raise HTTPException(status_code=400, detail="Empty body")
135
+ if len(data) > 50 * 1024 * 1024:
136
+ raise HTTPException(status_code=413, detail="PDF too large")
137
+ out = PDF_STORE_DIR / (pid if pid.lower().endswith(".pdf") else pid + ".pdf")
138
+ out.write_bytes(data)
139
+ return {"ok": True, "pdf_id": pid, "bytes": len(data)}
140
+
141
  @app.get("/api/pdf/{pdf_id}")
142
  def get_pdf(pdf_id: str):
143
+ pid = _safe_id(pdf_id)
144
+ f = PDF_STORE_DIR / (pid if pid.lower().endswith(".pdf") else pid + ".pdf")
145
+ if not f.exists():
146
+ raise HTTPException(status_code=404, detail="PDF not found")
147
+ data = f.read_bytes()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  return Response(content=data, media_type="application/pdf")
149
 
150
  @app.post("/api/send-config")