- Fix API path: frontend now calls /audit/logs (was /audit) - Backend eagerly loads User relationship for audit entries - Backend response includes user_name field instead of just user_id - Frontend logs page fetches real data with pagination - Derive INFO/WARN/ERROR levels from action type - Format details JSON into readable descriptions - Add loading state and empty state handling Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
from datetime import datetime
|
|
from typing import Any
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.dependencies import get_db, require_role
|
|
from app.services.audit_service import AuditService
|
|
|
|
router = APIRouter(prefix="/audit", tags=["audit"])
|
|
audit_service = AuditService()
|
|
|
|
|
|
@router.get("/logs")
|
|
async def list_audit_logs(
|
|
user_id: UUID | None = Query(None),
|
|
action: str | None = Query(None),
|
|
entity_type: str | None = Query(None),
|
|
entity_id: str | None = Query(None),
|
|
date_from: datetime | None = Query(None),
|
|
date_to: datetime | None = Query(None),
|
|
page: int = Query(1, ge=1),
|
|
page_size: int = Query(50, ge=1, le=200),
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: dict = Depends(require_role(["admin"])),
|
|
) -> dict[str, Any]:
|
|
"""List audit logs with filters (admin only)."""
|
|
logs, total = await audit_service.list_logs(
|
|
db,
|
|
user_id=user_id,
|
|
action=action,
|
|
entity_type=entity_type,
|
|
entity_id=entity_id,
|
|
date_from=date_from,
|
|
date_to=date_to,
|
|
page=page,
|
|
page_size=page_size,
|
|
)
|
|
|
|
pages = (total + page_size - 1) // page_size if total > 0 else 1
|
|
return {
|
|
"items": [
|
|
{
|
|
"id": str(log.id),
|
|
"user_id": str(log.user_id) if log.user_id else None,
|
|
"user_name": log.user.name if log.user else "System",
|
|
"action": log.action,
|
|
"entity_type": log.entity_type,
|
|
"entity_id": log.entity_id,
|
|
"details": log.details,
|
|
"timestamp": log.timestamp.isoformat(),
|
|
"ip_address": log.ip_address,
|
|
}
|
|
for log in logs
|
|
],
|
|
"total": total,
|
|
"page": page,
|
|
"page_size": page_size,
|
|
"pages": pages,
|
|
}
|