fix: 审批流修复 + 通知KeyError修复

审批流修复:
- 提交阶段(step_type=submit)自动approved,不再创建pending记录
- 审批权限添加auditor角色(require_role admin/dba/auditor)
- 审批完成判断排除execute步骤(step_type!=execute才计入has_next)
- review_ticket中加载workflow_steps用于step_type判断
- Ticket字段名修正: creator_id -> applicant_id

通知修复:
- send()中自动补充sql_preview字段(sql_content前100字符)
- 飞书/钉钉模板format改为format_map+安全fallback(缺失字段不报KeyError)
- DB中auditor用户role从developer修正为auditor

测试: 1182 passed, 0 failed
审批流全链路验证通过: 提交->DBA审核->审计员审核->admin执行->success
This commit is contained in:
logan committed 2026-05-25 11:41:03 +08:00
1 parent da3ed85295
commit 0576b253e4
2 files changed
+72 -18

No files matched your search

+23 -4
View File
@@ -125,6 +125,11 @@ class NotificationSender:
# 通知脱敏:隐藏 SQL 中的敏感内容
data = self._mask_sensitive_data(data)
# 自动补充 sql_preview(取 sql_content 前100字符)
if "sql_preview" not in data and "sql_content" in data:
sql = data["sql_content"]
data["sql_preview"] = sql[:100] + ("..." if len(sql) > 100 else "")
try:
if channel_type == "dingtalk":
return await self._send_dingtalk(config, event_type, data)
@@ -158,8 +163,15 @@ class NotificationSender:
webhook_url = f"{webhook_url}?timestamp={timestamp}&sign={sign}"
template = self.TEMPLATES.get(event_type, self.TEMPLATES["ticket_created"])
title = template["title"].format(**data)
body = template["body"].format(**data)
# 安全格式化
safe_data = {**data}
for key in ["applicant", "ticket_id", "title", "db_type", "instance_name",
"target_database", "sql_content", "sql_preview", "approver",
"comment", "result", "duration", "affected_rows", "error",
"operator", "database", "size", "drift_count", "drift_details"]:
safe_data.setdefault(key, "")
title = template["title"].format_map(safe_data)
body = template["body"].format_map(safe_data)
tag = self.DINGTALK_TAGS.get(event_type, "📌")
# 钉钉 markdown 单个 \n 视为空格,需要 \n\n 才能换行
@@ -191,8 +203,15 @@ class NotificationSender:
return {"success": False, "message": "缺少 webhook_url 配置"}
template = self.TEMPLATES.get(event_type, self.TEMPLATES["ticket_created"])
title = template["title"].format(**data)
body = template["body"].format(**data)
# 安全格式化:缺失字段用空字符串代替,避免 KeyError
safe_data = {**data}
for key in ["applicant", "ticket_id", "title", "db_type", "instance_name",
"target_database", "sql_content", "sql_preview", "approver",
"comment", "result", "duration", "affected_rows", "error",
"operator", "database", "size", "drift_count", "drift_details"]:
safe_data.setdefault(key, "")
title = template["title"].format_map(safe_data)
body = template["body"].format_map(safe_data)
color = self.FEISHU_COLORS.get(event_type, "blue")
payload = {