feat: Phase 6-8 — PDF export, recurring scans, multi-website compare
Phase 6: PDF export via WeasyPrint — POST /agent/scans/pdf generates printable compliance report with findings table, service comparison, risk badge, and legal disclaimer. Phase 7: Recurring scans — POST /agent/monitored-urls to add URLs, POST /agent/run-scheduled triggers all enabled scans (cron/ZeroClaw). In-memory storage with DB upgrade path. Phase 8: Multi-website compare — POST /agent/compare with 2-5 URLs, parallel scanning, comparison table (risk, findings, services, compliance features per site). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,11 @@ import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Query
|
||||
from fastapi.responses import Response
|
||||
from pydantic import BaseModel
|
||||
|
||||
from compliance.services.agent_pdf_export import generate_scan_pdf
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/compliance/agent", tags=["agent"])
|
||||
@@ -195,3 +198,23 @@ async def get_scan(scan_id: str):
|
||||
return ScanDetail(id=scan_id, url="", scan_type="", analysis_mode="", result={}, created_at="")
|
||||
finally:
|
||||
await pool.close()
|
||||
|
||||
|
||||
@router.post("/scans/pdf")
|
||||
async def export_scan_pdf(req: SaveScanRequest):
|
||||
"""Generate a PDF report from scan results (no DB required)."""
|
||||
try:
|
||||
pdf_bytes = generate_scan_pdf({
|
||||
"url": req.url,
|
||||
"scan_type": req.scan_type,
|
||||
"analysis_mode": req.analysis_mode,
|
||||
**req.result,
|
||||
})
|
||||
return Response(
|
||||
content=pdf_bytes,
|
||||
media_type="application/pdf",
|
||||
headers={"Content-Disposition": f'attachment; filename="compliance-report-{req.url.split("/")[2][:30]}.pdf"'},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("PDF generation failed: %s", e)
|
||||
return {"error": str(e)}
|
||||
|
||||
Reference in New Issue
Block a user