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()