69 lines
2.4 KiB
Python
69 lines
2.4 KiB
Python
"""审计日志查询 API。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ..core.response import success_response
|
|
from ..core.database import get_db
|
|
from ..dependencies.auth import get_optional_current_user
|
|
from ..dependencies.tenant import get_tenant_id
|
|
from ..models import User
|
|
from ..services.audit_query_service import AuditQueryService
|
|
from ..services.auth import has_any_role
|
|
|
|
router = APIRouter(prefix="/audit", tags=["Audit"])
|
|
|
|
|
|
def _effective_tenant_id(current_user: User, header_tenant_id: int) -> int:
|
|
try:
|
|
return int(getattr(current_user, "tenant_id") or header_tenant_id or 1)
|
|
except Exception:
|
|
return int(header_tenant_id or 1)
|
|
|
|
|
|
def _user_role(user: User) -> str:
|
|
role = getattr(user, "role", "")
|
|
return str(getattr(role, "value", role) or "").strip()
|
|
|
|
|
|
@router.get("/operations")
|
|
async def list_audit_operations(
|
|
tenant_id: Optional[int] = Query(default=None, ge=1),
|
|
entity_type: Optional[str] = Query(default=None),
|
|
start_time: Optional[datetime] = Query(default=None),
|
|
end_time: Optional[datetime] = Query(default=None),
|
|
limit: int = Query(default=100, ge=1, le=100),
|
|
current_user: Optional[User] = Depends(get_optional_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
header_tenant_id: int = Depends(get_tenant_id),
|
|
):
|
|
if current_user is not None and not has_any_role(_user_role(current_user), ["BOSS", "ADMIN"]):
|
|
raise HTTPException(status_code=403, detail="Access denied. Required roles: BOSS, ADMIN")
|
|
if current_user is None:
|
|
effective_tenant_id = int(header_tenant_id or 1)
|
|
else:
|
|
effective_tenant_id = _effective_tenant_id(current_user, header_tenant_id)
|
|
if tenant_id is not None and int(tenant_id) != effective_tenant_id:
|
|
raise HTTPException(status_code=403, detail="cross-tenant query is forbidden")
|
|
scoped_tenant_id = int(tenant_id or effective_tenant_id)
|
|
|
|
items = await AuditQueryService(db).list_operations(
|
|
tenant_id=scoped_tenant_id,
|
|
entity_type=entity_type,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
limit=limit,
|
|
)
|
|
return success_response(
|
|
{
|
|
"items": items,
|
|
"count": len(items),
|
|
"tenant_id": scoped_tenant_id,
|
|
}
|
|
)
|