Rescue Paperjet v1 implementation
This commit is contained in:
parent
7ff5c8130d
commit
db9e2ca51b
83 changed files with 6186 additions and 3894 deletions
94
backend/app/api/v1/export.py
Normal file
94
backend/app/api/v1/export.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
"""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}"'},
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue