from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from typing import Optional from datetime import datetime from app.core.database import get_db from app.core.security import get_current_user, require_permission from app.models.auth import User from app.models.audit import AuditAction, AuditResource from app.services.audit_service import AuditService router = APIRouter(prefix="/audit", tags=["审计日志"]) @router.get("/logs", summary="获取审计日志列表") def get_audit_logs( user_id: Optional[int] = None, action: Optional[AuditAction] = None, resource: Optional[AuditResource] = None, success: Optional[bool] = None, start_time: Optional[datetime] = None, end_time: Optional[datetime] = None, skip: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=500), current_user: User = Depends(require_permission("audit:view")), db: Session = Depends(get_db) ): """ 获取审计日志列表(需要管理员权限) - **user_id**: 按用户ID过滤 - **action**: 按操作类型过滤 (create/read/update/delete/login/logout/scan/export) - **resource**: 按资源类型过滤 - **success**: 按操作结果过滤 - **start_time**: 开始时间 - **end_time**: 结束时间 """ total, items = AuditService.get_logs( db, user_id=user_id, action=action, resource=resource, success=success, start_time=start_time, end_time=end_time, skip=skip, limit=limit ) # 格式化返回 result_items = [] for item in items: changed = item.changed_fields.split(',') if item.changed_fields else [] result_items.append({ "id": item.id, "user_id": item.user_id, "username": item.username, "real_name": item.real_name, "user_ip": item.user_ip, "action": item.action.value, "resource": item.resource.value, "resource_id": item.resource_id, "description": item.description, "changed_fields": changed, "request_method": item.request_method, "request_path": item.request_path, "success": bool(item.success), "error_message": item.error_message, "created_at": item.created_at }) return {"total": total, "items": result_items} @router.get("/logs/my", summary="获取当前用户的操作日志") def get_my_logs( skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=200), current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """获取当前登录用户的操作日志""" total, items = AuditService.get_logs( db, user_id=current_user.id, skip=skip, limit=limit ) result_items = [] for item in items: result_items.append({ "id": item.id, "action": item.action.value, "resource": item.resource.value, "resource_id": item.resource_id, "description": item.description, "success": bool(item.success), "created_at": item.created_at }) return {"total": total, "items": result_items} @router.get("/logs/resource/{resource_type}/{resource_id}", summary="获取资源操作历史") def get_resource_logs( resource_type: str, resource_id: str, limit: int = Query(50, ge=1, le=200), current_user: User = Depends(require_permission("audit:view")), db: Session = Depends(get_db) ): """获取指定资源的操作历史""" try: resource_enum = AuditResource(resource_type) except ValueError: return {"total": 0, "items": [], "error": "无效的资源类型"} items = AuditService.get_resource_logs(db, resource_enum, resource_id, limit=limit) result_items = [] for item in items: changed = item.changed_fields.split(',') if item.changed_fields else [] result_items.append({ "id": item.id, "username": item.username, "real_name": item.real_name, "action": item.action.value, "description": item.description, "changed_fields": changed, "success": bool(item.success), "created_at": item.created_at }) return {"total": len(items), "items": result_items} @router.get("/statistics", summary="获取审计统计信息") def get_audit_statistics( days: int = Query(30, ge=1, le=365), current_user: User = Depends(require_permission("audit:view")), db: Session = Depends(get_db) ): """获取审计统计信息""" stats = AuditService.get_statistics(db, days=days) return stats @router.delete("/clean", summary="清理旧日志") def clean_old_logs( days: int = Query(90, ge=7, le=3650, description="保留天数"), current_user: User = Depends(require_permission("system:admin")), db: Session = Depends(get_db) ): """ 清理指定天数之前的审计日志(需要超级管理员权限) - **days**: 保留日志的天数,默认90天 """ deleted_count = AuditService.clean_old_logs(db, days=days) return { "message": f"清理完成,已删除 {deleted_count} 条旧日志", "deleted_count": deleted_count, "kept_days": days }