42 lines
1.5 KiB
Python
42 lines
1.5 KiB
Python
"""Audit-log read API — admins only (users.is_admin, granted via `manage.py set-admin`)."""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, Request
|
|
from sqlalchemy.orm import Session as OrmSession
|
|
|
|
from ...db import models
|
|
from ..auth import require_admin
|
|
from ..deps import db_dep
|
|
|
|
router = APIRouter(prefix="/api/audit", tags=["audit"])
|
|
|
|
|
|
@router.get("")
|
|
def list_audit(request: Request, limit: int = 100, offset: int = 0,
|
|
session_id: int | None = None, action: str = "",
|
|
db: OrmSession = Depends(db_dep)) -> dict:
|
|
"""Newest first. Filter by closing and/or action; page with limit/offset."""
|
|
require_admin(request, db)
|
|
limit = max(1, min(limit, 500))
|
|
q = db.query(models.AuditLog)
|
|
if session_id is not None:
|
|
q = q.filter(models.AuditLog.session_id == session_id)
|
|
if action:
|
|
q = q.filter(models.AuditLog.action == action)
|
|
total = q.count()
|
|
rows = (q.order_by(models.AuditLog.at.desc(), models.AuditLog.id.desc())
|
|
.offset(offset).limit(limit).all())
|
|
return {
|
|
"total": total,
|
|
"entries": [{
|
|
"id": r.id,
|
|
"at": r.at.isoformat() if r.at else None,
|
|
"username": r.username or "",
|
|
"display_name": r.display_name or "",
|
|
"action": r.action,
|
|
"session_id": r.session_id,
|
|
"session_name": r.session_name or "",
|
|
"detail": r.detail or "",
|
|
} for r in rows],
|
|
}
|