import json import uuid from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_operator_role_label, get_current_user, get_db_session, require_api_permission from app.crud import audit as audit_crud from app.crud import study as study_crud from app.schemas.audit import AuditEventCreate, AuditLogRead router = APIRouter() async def _build_export_audit_detail(db: AsyncSession, study_id: uuid.UUID, action: str) -> str: study = await study_crud.get(db, study_id) if not study: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="项目不存在") scope = "system" if action == "AUDIT_EXPORT_SYSTEM" else "project" description = "导出了系统审计日志" if scope == "system" else f"导出了项目审计日志:{study.name}" return json.dumps( { "targetName": "系统审计日志" if scope == "system" else study.name, "scope": scope, "description": description, "result": "SUCCESS", }, ensure_ascii=False, ) @router.get( "/", response_model=list[AuditLogRead], dependencies=[Depends(require_api_permission("audit_logs:read"))], ) async def list_audit_logs( study_id: uuid.UUID, entity_type: str | None = None, entity_id: uuid.UUID | None = None, action: str | None = None, operator_id: uuid.UUID | None = None, skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db_session), ) -> list[AuditLogRead]: logs = await audit_crud.list_logs( db, study_id=study_id, entity_type=entity_type, entity_id=entity_id, action=action, operator_id=operator_id, skip=skip, limit=limit, ) return list(logs) @router.post( "/events", status_code=status.HTTP_201_CREATED, ) async def create_audit_event( study_id: uuid.UUID, payload: AuditEventCreate, _export_permission=Depends(require_api_permission("audit_logs:export")), db: AsyncSession = Depends(get_db_session), current_user=Depends(get_current_user), ): allowed_actions = {"AUDIT_EXPORT_SYSTEM", "AUDIT_EXPORT_PROJECT"} if payload.action not in allowed_actions: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="不支持的审计事件") await audit_crud.log_action( db, study_id=study_id, entity_type="audit_log", entity_id=None, action=payload.action, detail=await _build_export_audit_detail(db, study_id, payload.action), operator_id=current_user.id, operator_role=await get_operator_role_label(db, study_id, current_user), ) return {"ok": True}