"""Flattened PDF export endpoint.""" import json from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import Response from sqlalchemy import select from sqlalchemy.orm import Session from app.auth.dependencies import get_current_user, verify_csrf from app.config import settings from app.db import get_db from app.models.annotation_state import AnnotationState from app.models.document import Document from app.models.version import Version from app.schemas.export import ExportRequest from app.services.export.renderer import export_annotations from app.services.storage import safe_filename router = APIRouter( prefix="/documents", tags=["export"], dependencies=[Depends(get_current_user)], ) def _document_or_404(document_id: str, db: Session) -> Document: document = db.scalar( select(Document).where(Document.id == document_id, Document.deleted_at.is_(None)) ) if not document: raise HTTPException(status_code=404, detail="Document not found") return document def _state_data(document_id: str, db: Session) -> list[dict[str, object]]: state = db.scalar(select(AnnotationState).where(AnnotationState.document_id == document_id)) if not state: return [] try: data = json.loads(state.data) except json.JSONDecodeError: return [] return data if isinstance(data, list) else [] @router.post("/{document_id}/export", dependencies=[Depends(verify_csrf)]) def export_document( document_id: str, request: ExportRequest, db: Session = Depends(get_db), ) -> Response: """Export the working layer or a selected version as a downloadable PDF.""" document = _document_or_404(document_id, db) pdf_path = settings.PDF_STORAGE_PATH / f"{document.id}.pdf" if not pdf_path.is_file(): raise HTTPException(status_code=404, detail="Original PDF is missing") if not request.flatten: content = pdf_path.read_bytes() elif request.versionId: version = db.scalar( select(Version).where( Version.id == request.versionId, Version.document_id == document_id, ) ) if not version: raise HTTPException(status_code=404, detail="Version not found") try: version_data = json.loads(version.data) except json.JSONDecodeError: version_data = [] content = export_annotations( pdf_path, version_data if isinstance(version_data, list) else [], settings.PDF_STORAGE_PATH / "assets" / document.id, ) else: content = export_annotations( pdf_path, _state_data(document_id, db), settings.PDF_STORAGE_PATH / "assets" / document.id, ) filename = safe_filename(document.original_filename) if not filename.lower().endswith(".pdf"): filename = f"{filename}.pdf" filename = filename.replace('"', "'").replace("\r", "").replace("\n", "") return Response( content=content, media_type="application/pdf", headers={"Content-Disposition": f'attachment; filename="{filename}"'}, )