Files
bacchus/apps/backend/app/api/audit_logs.py
2025-09-28 19:13:01 +02:00

74 lines
2.1 KiB
Python

from typing import Optional, List
from datetime import datetime
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.core.database import SessionLocal
from app.core.auth import get_current_user, requires_role
from app.models.user import User
from app.models.audit_log import AuditLog
from app.schemas.audit_log import AuditLogOut
router = APIRouter(prefix="/audit-logs", tags=["audit-logs"])
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def _ts_col():
# vorhandene Zeitspalte wählen, sonst Fallback auf id
return (
getattr(AuditLog, "created_at", None)
or getattr(AuditLog, "timestamp", None)
or getattr(AuditLog, "created", None)
or AuditLog.id
)
@router.get("/", response_model=List[AuditLogOut], dependencies=[Depends(requires_role("admin"))])
def list_audit_logs(
limit: int = Query(100, ge=1, le=1000),
offset: int = Query(0, ge=0),
user_id: Optional[int] = Query(None, ge=1),
action: Optional[str] = Query(None),
q: Optional[str] = Query(None),
date_from: Optional[str] = Query(None),
date_to: Optional[str] = Query(None),
db: Session = Depends(get_db),
_: User = Depends(get_current_user),
):
qs = db.query(AuditLog)
if user_id is not None:
qs = qs.filter(AuditLog.user_id == user_id)
if action:
qs = qs.filter(AuditLog.action == action)
if q and hasattr(AuditLog, "info"):
like = f"%{q}%"
qs = qs.filter(AuditLog.info.ilike(like))
ts = _ts_col()
# ISO-Zeiten robust parsen
def _parse_iso(s: Optional[str]) -> Optional[datetime]:
if not s:
return None
try:
return datetime.fromisoformat(s.replace("Z", "+00:00"))
except Exception:
return None
dtf = _parse_iso(date_from)
dtt = _parse_iso(date_to)
if dtf is not None and ts is not AuditLog.id:
qs = qs.filter(ts >= dtf)
if dtt is not None and ts is not AuditLog.id:
qs = qs.filter(ts <= dtt)
qs = qs.order_by(ts.desc(), AuditLog.id.desc()).limit(limit).offset(offset)
return qs.all()