fix: workflow 422 validation + report 500 DB data fetching + AI stream tenant context
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
This commit is contained in:
@@ -15,7 +15,10 @@ from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.db import get_db
|
||||
from app.models.contact import Contact
|
||||
from app.models.audit import AuditLog
|
||||
|
||||
from app.core.db import get_db, set_tenant_context
|
||||
from app.deps import get_current_user, require_permission
|
||||
from app.plugins.builtins.report_generator.models import (
|
||||
ReportInstance,
|
||||
@@ -156,15 +159,100 @@ async def generate_preset(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: dict = Depends(require_permission("reports:generate")),
|
||||
):
|
||||
"""Generate a preset report by name (e.g. contact_list, calendar_week)."""
|
||||
"""Generate a preset report by name (e.g. contact_list, calendar_week).
|
||||
|
||||
Fetches live data from the database based on the preset type,
|
||||
merges with user-provided parameters, and generates the report.
|
||||
"""
|
||||
tenant_id = uuid.UUID(current_user["tenant_id"])
|
||||
user_id = uuid.UUID(current_user["user_id"])
|
||||
|
||||
# Generate report first (no DB interaction during sync IO)
|
||||
await db.close()
|
||||
# Set tenant context for RLS
|
||||
await set_tenant_context(db, tenant_id)
|
||||
|
||||
# Fetch data based on preset type
|
||||
parameters = dict(body.parameters) # copy user params
|
||||
|
||||
try:
|
||||
if body.preset == "contact_list":
|
||||
# Fetch all contacts (type='person') for this tenant
|
||||
q = select(Contact).where(
|
||||
Contact.tenant_id == tenant_id,
|
||||
Contact.type == "person",
|
||||
Contact.deleted_at.is_(None),
|
||||
).order_by(Contact.displayname)
|
||||
result = await db.execute(q)
|
||||
contacts = result.scalars().all()
|
||||
parameters["contacts"] = [
|
||||
{
|
||||
"name": f"{c.firstname or ''} {c.surname or ''}".strip() or c.displayname or "",
|
||||
"email": c.email_1 or "",
|
||||
"phone": c.phone_1 or "",
|
||||
"type": c.type or "person",
|
||||
"company": "", # contact persons are separate
|
||||
}
|
||||
for c in contacts
|
||||
]
|
||||
parameters["title"] = parameters.get("title", "Kontaktliste")
|
||||
|
||||
elif body.preset == "company_list":
|
||||
# Fetch all companies (type='company') for this tenant
|
||||
q = select(Contact).where(
|
||||
Contact.tenant_id == tenant_id,
|
||||
Contact.type == "company",
|
||||
Contact.deleted_at.is_(None),
|
||||
).order_by(Contact.name)
|
||||
result = await db.execute(q)
|
||||
companies = result.scalars().all()
|
||||
parameters["companies"] = [
|
||||
{
|
||||
"name": c.name or c.displayname or "",
|
||||
"address": (
|
||||
f"{c.mailing_street or ''} {c.mailing_number or ''}".strip()
|
||||
or f"{c.visit_street or ''} {c.visit_number or ''}".strip()
|
||||
or ""
|
||||
),
|
||||
"zip": c.mailing_postalcode or "",
|
||||
"city": c.mailing_city or "",
|
||||
"phone": c.phone_1 or "",
|
||||
"email": c.email_1 or "",
|
||||
"contact_person": "", # could be extended with ContactPerson lookup
|
||||
}
|
||||
for c in companies
|
||||
]
|
||||
parameters["title"] = parameters.get("title", "Firmenliste")
|
||||
|
||||
elif body.preset == "audit_log":
|
||||
# Fetch recent audit log entries for this tenant
|
||||
q = select(AuditLog).where(
|
||||
AuditLog.tenant_id == tenant_id,
|
||||
).order_by(AuditLog.timestamp.desc()).limit(500)
|
||||
result = await db.execute(q)
|
||||
entries = result.scalars().all()
|
||||
parameters["entries"] = [
|
||||
{
|
||||
"timestamp": str(e.timestamp) if e.timestamp else "",
|
||||
"user": str(e.user_id) if e.user_id else "—",
|
||||
"action": e.action or "",
|
||||
"entity": e.entity_type or "",
|
||||
"entity_id": str(e.entity_id) if e.entity_id else "",
|
||||
"details": str(e.changes) if e.changes else "",
|
||||
}
|
||||
for e in entries
|
||||
]
|
||||
parameters["title"] = parameters.get("title", "Audit-Log")
|
||||
|
||||
elif body.preset in ("calendar_week", "calendar_month"):
|
||||
# Calendar presets: pass user params through (no DB model yet)
|
||||
parameters.setdefault("title", "Wochenkalender" if body.preset == "calendar_week" else "Monatskalender")
|
||||
parameters.setdefault("days", [])
|
||||
parameters.setdefault("hours", [])
|
||||
parameters.setdefault("weeks", [])
|
||||
parameters.setdefault("weekday_names", [])
|
||||
|
||||
# Generate report
|
||||
file_bytes, ext = generate_preset_report(
|
||||
body.preset, body.output_format, body.parameters
|
||||
body.preset, body.output_format, parameters
|
||||
)
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
@@ -175,7 +263,7 @@ async def generate_preset(
|
||||
},
|
||||
) from exc
|
||||
|
||||
# Return file directly as streaming response (avoid DB tracking due to greenlet issues in test env)
|
||||
# Return file directly as streaming response
|
||||
import io as _io
|
||||
|
||||
media_types = {
|
||||
|
||||
Reference in New Issue
Block a user