""" 審計日誌裝飾器和工具函數 """ from functools import wraps from typing import Callable, Optional from fastapi import Request from sqlalchemy.orm import Session def get_current_username() -> str: """ 獲取當前用戶名稱 TODO: 實作後從 JWT Token 獲取 目前返回系統用戶 """ # TODO: 從 Keycloak JWT Token 解析用戶名 return "system@porscheworld.tw" def audit_log_decorator( action: str, resource_type: str, get_resource_id: Optional[Callable] = None, get_details: Optional[Callable] = None, ): """ 審計日誌裝飾器 使用範例: @audit_log_decorator( action="create", resource_type="employee", get_resource_id=lambda result: result.id, get_details=lambda result: {"employee_id": result.employee_id} ) def create_employee(...): pass Args: action: 操作類型 resource_type: 資源類型 get_resource_id: 從返回結果獲取資源 ID 的函數 get_details: 從返回結果獲取詳細資訊的函數 """ def decorator(func: Callable): @wraps(func) async def async_wrapper(*args, **kwargs): # 執行原函數 result = await func(*args, **kwargs) # 獲取 DB Session db: Optional[Session] = kwargs.get("db") if not db: return result # 獲取 Request (用於 IP) request: Optional[Request] = kwargs.get("request") ip_address = None if request: from app.services.audit_service import audit_service ip_address = audit_service.get_client_ip(request) # 獲取資源 ID resource_id = None if get_resource_id and result: resource_id = get_resource_id(result) # 獲取詳細資訊 details = None if get_details and result: details = get_details(result) # 記錄審計日誌 from app.services.audit_service import audit_service audit_service.log( db=db, action=action, resource_type=resource_type, resource_id=resource_id, performed_by=get_current_username(), details=details, ip_address=ip_address, ) return result @wraps(func) def sync_wrapper(*args, **kwargs): # 執行原函數 result = func(*args, **kwargs) # 獲取 DB Session db: Optional[Session] = kwargs.get("db") if not db: return result # 獲取 Request (用於 IP) request: Optional[Request] = kwargs.get("request") ip_address = None if request: from app.services.audit_service import audit_service ip_address = audit_service.get_client_ip(request) # 獲取資源 ID resource_id = None if get_resource_id and result: resource_id = get_resource_id(result) # 獲取詳細資訊 details = None if get_details and result: details = get_details(result) # 記錄審計日誌 from app.services.audit_service import audit_service audit_service.log( db=db, action=action, resource_type=resource_type, resource_id=resource_id, performed_by=get_current_username(), details=details, ip_address=ip_address, ) return result # 檢查是否為異步函數 import asyncio if asyncio.iscoroutinefunction(func): return async_wrapper else: return sync_wrapper return decorator