From d38e26ffff441c00f2052324f3cbc81551921e2f Mon Sep 17 00:00:00 2001 From: yumoqing Date: Fri, 14 Aug 2026 13:37:49 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AE=A1=E8=AE=A1=E8=A6=86=E7=9B=96=20+?= =?UTF-8?q?=20=E5=A4=87=E4=BB=BD=E8=BF=87=E6=BB=A4=20+=20unknown=20action?= =?UTF-8?q?=20=E4=BF=9D=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - unknown action 在 detail 保留原始值 - backup 支持过滤 + limit 上限(防大响应) - 提取 _build_filter 公共过滤函数 --- app_audit/audit_service.py | 25 +++++++++++++++++++------ wwwroot/api/audit.dspy | 10 +++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/app_audit/audit_service.py b/app_audit/audit_service.py index 0edc60e..e711f1e 100644 --- a/app_audit/audit_service.py +++ b/app_audit/audit_service.py @@ -41,6 +41,8 @@ async def audit_log(sor, user_id: str, username: str, action: str, 审计写入失败不应阻断主流程,返回 False 由调用方决定是否处理。 """ if action not in VALID_ACTIONS: + # 保留原始 action,避免排查时丢失是哪个模块拼错了 + detail = (detail or "") + " [原始action:" + str(action) + "]" action = "unknown" try: from appPublic.uniqueID import getID @@ -87,8 +89,8 @@ def _row_to_dict(row) -> dict: return d -async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = 60): - """查询审计日志(分页,DataGrid 兼容),返回 {rows, total}。""" +def _build_filter(filters: dict): + """构造 WHERE 子句 + 参数(list/backup/delete 共用)。返回 (wsql, ns)。""" filters = filters or {} where = [] ns = {} @@ -108,6 +110,12 @@ async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = where.append("created_at<=${t}$") ns["t"] = filters["to"] wsql = (" WHERE " + " AND ".join(where)) if where else "" + return wsql, ns + + +async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = 60): + """查询审计日志(分页,DataGrid 兼容),返回 {rows, total}。""" + wsql, ns = _build_filter(filters) try: page = max(1, int(page or 1)) except (ValueError, TypeError): @@ -127,11 +135,16 @@ async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = async def backup_audit_logs(sor, user_id: str, username: str, filters: dict = None, - client_ip: str = "") -> dict: - """导出审计日志(仅 owner.audit),返回 JSON 内容供下载。""" - # 查最近 10000 条(备份上限,避免一次拉全表拖垮内存) + limit: int = 10000, client_ip: str = "") -> dict: + """导出审计日志(仅 owner.audit),支持过滤 + 上限,返回 JSON 内容供下载。""" + wsql, ns = _build_filter(filters) + try: + limit = max(1, min(int(limit or 10000), 50000)) + except (ValueError, TypeError): + limit = 10000 recs = await sor.sqlExe( - "SELECT * FROM sd_audit_logs ORDER BY created_at DESC LIMIT 10000", {}) + "SELECT * FROM sd_audit_logs" + wsql + " ORDER BY created_at DESC LIMIT " + + str(limit), ns) rows = [_row_to_dict(r) for r in recs] # 备份操作本身也审计 await audit_log(sor, user_id, username, "audit_backup", diff --git a/wwwroot/api/audit.dspy b/wwwroot/api/audit.dspy index 173c3c6..458ae2f 100644 --- a/wwwroot/api/audit.dspy +++ b/wwwroot/api/audit.dspy @@ -51,9 +51,17 @@ if action == 'list': return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) elif action == 'backup': + bfilters = { + 'user_id': (params_kw or {}).get('user_id', ''), + 'username': (params_kw or {}).get('username', ''), + 'action': (params_kw or {}).get('act', ''), + 'from': (params_kw or {}).get('from', ''), + 'to': (params_kw or {}).get('to', ''), + } + blimit = (params_kw or {}).get('limit', 10000) try: async with get_sor_context(request._run_ns, 'pipeline') as sor: - r = await backup_audit_logs(sor, user_id, username, None, client_ip) + r = await backup_audit_logs(sor, user_id, username, bfilters, blimit, client_ip) return json.dumps(r, ensure_ascii=False) except Exception as e: return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)