| 1 | from __future__ import annotations |
| 2 | |
| 3 | from fastapi import APIRouter, Depends, HTTPException, Response |
| 4 | from sqlalchemy import select |
| 5 | from sqlalchemy.orm import Session |
| 6 | |
| 7 | from app.api.deps import Perm, get_db, require |
| 8 | from app.models import AuditLog, Report, User |
| 9 | from app.schemas import ReportRequest |
| 10 | from app.services.reporting import ( |
| 11 | build_report, render_csv_timeline, render_json, render_markdown, |
| 12 | ) |
| 13 | |
| 14 | router = APIRouter(tags=["reports"]) |
| 15 | |
| 16 | |
| 17 | @router.post("/investigations/{inv_id}/reports") |
| 18 | def create_report(inv_id: str, payload: ReportRequest, db: Session = Depends(get_db), |
| 19 | user: User = Depends(require(Perm.EXPORT))): |
| 20 | try: |
| 21 | report = build_report(db, inv_id, payload.sections) |
| 22 | except ValueError as e: |
| 23 | raise HTTPException(404, str(e)) |
| 24 | rec = Report(investigation_id=inv_id, title=payload.title or report["title"], |
| 25 | format=payload.format, sections=report["sections"], created_by=user.id) |
| 26 | db.add(rec) |
| 27 | db.flush() |
| 28 | db.add(AuditLog(actor_user_id=user.id, action="report.create", |
| 29 | entity_type="report", entity_id=rec.id, meta={"format": payload.format})) |
| 30 | db.commit() |
| 31 | db.refresh(rec) |
| 32 | return {"report_id": rec.id, "format": payload.format, "report": report} |
| 33 | |
| 34 | |
| 35 | @router.get("/reports/{report_id}/download") |
| 36 | def download_report(report_id: str, format: str = "markdown", db: Session = Depends(get_db), |
| 37 | _: User = Depends(require(Perm.EXPORT))): |
| 38 | rec = db.get(Report, report_id) |
| 39 | if not rec: |
| 40 | raise HTTPException(404, "report not found") |
| 41 | report = {"title": rec.title, "investigation_id": rec.investigation_id, "sections": rec.sections} |
| 42 | if format == "json": |
| 43 | return Response(render_json(report), media_type="application/json") |
| 44 | if format == "csv": |
| 45 | return Response(render_csv_timeline(report), media_type="text/csv", |
| 46 | headers={"Content-Disposition": f"attachment; filename=report_{report_id}.csv"}) |
| 47 | if format == "pdf": |
| 48 | from app.services.report_pdf import render_pdf |
| 49 | return Response(render_pdf(report), media_type="application/pdf", |
| 50 | headers={"Content-Disposition": f"attachment; filename=report_{report_id}.pdf"}) |
| 51 | return Response(render_markdown(report), media_type="text/markdown") |