"""审计日志查询 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, } )