#!/usr/bin/env python3 """ Web-MVP für PDF zu ICS Konverter """ import re import sys import tempfile from pathlib import Path import os from fastapi import FastAPI, File, Form, Request, UploadFile from fastapi.responses import FileResponse, HTMLResponse from fastapi.templating import Jinja2Templates from starlette.background import BackgroundTask PROJECT_ROOT = Path(__file__).resolve().parent.parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from pdf_to_ics import create_ics_from_dienstplan, extract_dienstplan_data app = FastAPI(title="PDF zu ICS Web") templates = Jinja2Templates(directory=str(Path(__file__).parent / "templates")) @app.get("/", response_class=HTMLResponse) def index(request: Request): return templates.TemplateResponse( "index.html", { "request": request, "error": None, }, ) @app.post("/convert") async def convert_pdf( request: Request, file: UploadFile = File(...), exclude_rest: bool = Form(False), exclude_vacation: bool = Form(False), ): filename = file.filename or "dienstplan.pdf" if not filename.lower().endswith(".pdf"): return templates.TemplateResponse( "index.html", { "request": request, "error": "Bitte eine PDF-Datei hochladen.", }, status_code=400, ) data = await file.read() if not data: return templates.TemplateResponse( "index.html", { "request": request, "error": "Die Datei ist leer.", }, status_code=400, ) with tempfile.TemporaryDirectory(prefix="pdf_to_ics_web_") as temp_dir: temp_dir_path = Path(temp_dir) pdf_path = temp_dir_path / "upload.pdf" pdf_path.write_bytes(data) dienstplan = extract_dienstplan_data(str(pdf_path)) if not dienstplan.get("events"): return templates.TemplateResponse( "index.html", { "request": request, "error": "Keine Dienstplan-Events in der PDF gefunden.", }, status_code=422, ) safe_name = re.sub(r"[^A-Za-z0-9._-]", "_", Path(filename).stem) ics_filename = f"{safe_name}.ics" ics_path = temp_dir_path / ics_filename create_ics_from_dienstplan( dienstplan, str(ics_path), exclude_rest=exclude_rest, exclude_vacation=exclude_vacation, ) content = ics_path.read_bytes() response_tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".ics", prefix="pdf_to_ics_out_") response_tmp.write(content) response_tmp.close() return FileResponse( path=response_tmp.name, media_type="text/calendar", filename=ics_filename, headers={"Cache-Control": "no-store"}, background=BackgroundTask(lambda path: os.remove(path) if os.path.exists(path) else None, response_tmp.name), ) @app.get("/health") def health(): return {"status": "ok"}