fix: DSR export type-cast bug + session rollback on partial failures

- tenant_id kept as string (PostgreSQL handles UUID cast)
- Einwilligungen query uses CAST(:tid AS VARCHAR) for compatibility
- Each data source query wrapped with rollback on failure to prevent
  cascading "transaction aborted" errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-03 23:15:25 +02:00
parent 02468c94c0
commit c55d0ab12a
@@ -40,7 +40,7 @@ class DSRExportService:
def aggregate_user_data(self, tenant_id: str, email: str) -> dict[str, Any]: def aggregate_user_data(self, tenant_id: str, email: str) -> dict[str, Any]:
"""Collect ALL data about a user from all CMP sources.""" """Collect ALL data about a user from all CMP sources."""
now = datetime.now(timezone.utc) now = datetime.now(timezone.utc)
tid = uuid.UUID(tenant_id) if len(tenant_id) > 20 else tenant_id tid = tenant_id # Keep as string — let PostgreSQL cast
# 1. Banner consents + audit trail # 1. Banner consents + audit trail
banner_data: dict[str, Any] = {"banner_consents": [], "audit_trail": []} banner_data: dict[str, Any] = {"banner_consents": [], "audit_trail": []}
@@ -49,6 +49,10 @@ class DSRExportService:
banner_data = banner_svc.export_for_dsr(tenant_id, email) banner_data = banner_svc.export_for_dsr(tenant_id, email)
except Exception as e: except Exception as e:
logger.warning("Banner DSR export failed: %s", e) logger.warning("Banner DSR export failed: %s", e)
try:
self.db.rollback()
except Exception:
pass
# 2. Einwilligungen (user-based consents) # 2. Einwilligungen (user-based consents)
einwilligungen: list[dict] = [] einwilligungen: list[dict] = []
@@ -57,7 +61,7 @@ class DSRExportService:
SELECT c.id, c.data_point_id, c.granted, c.granted_at, c.revoked_at, SELECT c.id, c.data_point_id, c.granted, c.granted_at, c.revoked_at,
c.consent_version, c.source, c.ip_address, c.user_agent, c.created_at c.consent_version, c.source, c.ip_address, c.user_agent, c.created_at
FROM compliance_einwilligungen_consents c FROM compliance_einwilligungen_consents c
WHERE c.tenant_id = :tid AND c.user_id = :email WHERE c.tenant_id = CAST(:tid AS VARCHAR) AND c.user_id = :email
ORDER BY c.created_at DESC ORDER BY c.created_at DESC
""") """)
rows = self.db.execute(q, {"tid": tid, "email": email}).fetchall() rows = self.db.execute(q, {"tid": tid, "email": email}).fetchall()
@@ -83,6 +87,10 @@ class DSRExportService:
einwilligungen.append(entry) einwilligungen.append(entry)
except Exception as e: except Exception as e:
logger.warning("Einwilligungen export failed: %s", e) logger.warning("Einwilligungen export failed: %s", e)
try:
self.db.rollback()
except Exception:
pass
# 3. DSR requests by this user # 3. DSR requests by this user
dsr_requests: list[dict] = [] dsr_requests: list[dict] = []
@@ -104,6 +112,10 @@ class DSRExportService:
dsr_requests.append(entry) dsr_requests.append(entry)
except Exception as e: except Exception as e:
logger.warning("DSR requests export failed: %s", e) logger.warning("DSR requests export failed: %s", e)
try:
self.db.rollback()
except Exception:
pass
return { return {
"export_date": now.isoformat(), "export_date": now.isoformat(),