This commit is contained in:
2025-09-28 19:13:01 +02:00
parent 49edf780b5
commit 541ecb48f2
67 changed files with 5176 additions and 5008 deletions

View File

@@ -0,0 +1,73 @@
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()