refactor(core): 重构核心模块结构并更新导入路径 - 将配置相关的设置从 app.core.config 移除 - 将常量定义从 app.core.constants 移除 - 将数据库相关功能从 app.core.database 移除 - 将基础数据库模型从 app.core.db_base 移除 - 将敏感信息掩码功能从 app.core.masking 移除 - 将中间件定义从 app.core.middleware 移除 - 将操作保护功能从 app.core.operation_guard 移除 - 将分页工具从 app.core.pagination 移除 - 将请求上下文管理从 app.core.request_context 移除 - 将调度器功能从 app.core.scheduler 移除 - 将安全认证逻辑从 app.core.security 移除 - 将任务队列相关功能从 app.core.task_queue 移除 - 将时间工具从 app.core.time 移除 - 更新 alembic 配置中的 Base 模型导入路径 - 更新各模块中对重构后组件的引用路径 ```
68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
import json
|
|
from typing import Any
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.http.pagination import bounded_limit
|
|
from app.core.http.request_context import get_request_id
|
|
from app.modules.audit.constants import AUDIT_REDACTED_VALUE, AUDIT_SENSITIVE_KEYS
|
|
from app.modules.audit.models import AuditLog
|
|
from app.modules.audit.schemas import AuditLogCreate
|
|
|
|
|
|
def _redact(value: Any) -> Any:
|
|
if isinstance(value, dict):
|
|
safe: dict[str, Any] = {}
|
|
for key, item in value.items():
|
|
key_text = str(key)
|
|
if key_text.lower() in AUDIT_SENSITIVE_KEYS:
|
|
safe[key_text] = AUDIT_REDACTED_VALUE
|
|
else:
|
|
safe[key_text] = _redact(item)
|
|
return safe
|
|
if isinstance(value, list):
|
|
return [_redact(item) for item in value]
|
|
if isinstance(value, tuple):
|
|
return [_redact(item) for item in value]
|
|
return value
|
|
|
|
|
|
def _dump(value: Any | None) -> str | None:
|
|
"""Serialize audit payloads while preserving existing strings."""
|
|
|
|
if value is None:
|
|
return None
|
|
if isinstance(value, str):
|
|
return value
|
|
return json.dumps(_redact(value), ensure_ascii=False, default=str)
|
|
|
|
|
|
class AuditService:
|
|
"""Persist and query audit log entries."""
|
|
|
|
def __init__(self, db: Session):
|
|
self.db = db
|
|
|
|
def log(self, payload: AuditLogCreate) -> AuditLog:
|
|
record = AuditLog(
|
|
actor=payload.actor,
|
|
source=payload.source,
|
|
action=payload.action,
|
|
target_type=payload.target_type,
|
|
target_id=payload.target_id,
|
|
risk_level=payload.risk_level,
|
|
request_payload=_dump(payload.request_payload),
|
|
response_payload=_dump(payload.response_payload),
|
|
status=payload.status,
|
|
request_id=payload.request_id or get_request_id(),
|
|
)
|
|
self.db.add(record)
|
|
self.db.commit()
|
|
self.db.refresh(record)
|
|
return record
|
|
|
|
def list_logs(self, limit: int = 100) -> list[AuditLog]:
|
|
stmt = select(AuditLog).order_by(AuditLog.id.desc()).limit(bounded_limit(limit))
|
|
return list(self.db.execute(stmt).scalars())
|