94a35da86e
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
41 lines
1.3 KiB
Python
41 lines
1.3 KiB
Python
"""roundtable/core/audit.py
|
|
|
|
Helpers for writing audit log entries. Each call opens its own DB
|
|
session so audit events are committed independently of the calling
|
|
route's transaction (audit is only written after the main action
|
|
succeeds, by calling this after the main `async with db.begin()` block).
|
|
"""
|
|
from __future__ import annotations
|
|
import json
|
|
import logging
|
|
from datetime import datetime, timezone
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def log_audit(
|
|
app,
|
|
user_id: str | None,
|
|
username: str,
|
|
action: str,
|
|
entity_type: str | None = None,
|
|
entity_id: str | None = None,
|
|
detail: dict | None = None,
|
|
) -> None:
|
|
"""Write one audit event. Never raises — failures are logged and swallowed."""
|
|
from roundtable.models.audit import AuditEvent
|
|
try:
|
|
async with app.db_sessionmaker() as db:
|
|
async with db.begin():
|
|
db.add(AuditEvent(
|
|
user_id=user_id,
|
|
username=username or "unknown",
|
|
action=action,
|
|
entity_type=entity_type,
|
|
entity_id=entity_id,
|
|
detail_json=json.dumps(detail) if detail else None,
|
|
timestamp=datetime.now(timezone.utc),
|
|
))
|
|
except Exception:
|
|
logger.exception("Failed to write audit event action=%r", action)
|