feat(notify): 通知接线检查 + 修 F-101~F-111(模板对自动通知生效 / 催报真的会发 / 该发的通知都发了)
起点:F-1/F-31/F-50/F-52 是同一个形状 —— 每处单看都对,编译/lint/review 全不红,只有从入口走一遍才暴露。先把这一类固化成命令,再按输出逐条修。
新增 scripts/check-wiring.py:权限码有没有地方校验、错误码有没有被引用、站内信模板有没有发送点、bizType 有没有被用过、菜单键 ↔ PC 端 XtMenu 双向核对。有意不接线的写进脚本上方例外表(带理由)。进 verify-all(第 5 项)与 CI 的 check 阶段。检查器自身修了三次假阳性:只数 @RequirePerm 漏掉服务层校验、按标识符数引用被同名常量骗过、注释里的提及被当成接线(改为先去 Java 注释再数)。
F-101 自动通知改走可配置模板(FR-1002 原来只兑现了手工发送那一半):新增 NotifyTextResolver(单向依赖避开循环注入),库里改过的 > 内置;模板停用 = 这类通知不发且如实回 notifySent=false。F-102 加入申请三处通知(提交→审批人、通过/驳回→学生)。F-103 导出完成/失败通知发起人,正文不放签名 URL(模板里原本写着 {下载链接},一并改掉)。F-104 自动催报从来没发出过任何一条(end_time = date::date 与库里的 23:59:59 永不相等,测试夹具用 SQL 摆的日期型恰好能匹配)+ 补 FR-1003 的「截止当日」。F-105 驳回达上限通知管理员(契约与注释都写了,代码只有一行日志)。F-106 字典/通知记录两个菜单没有任何角色持有(手册还写着去那里办)。F-107 6 个权限码挂到自己的接口。F-109 Map.of 不接受 null → 通知被吞成一行 warn。F-110/F-111 测试自身的两个坑。
验证:新增 e2e-m5-notify-wiring.py 43 条(改模板→真驳回→断言学生收到改过的那句、停用→一条不发、申请/审批/导出/催报/升级/菜单/权限各一节);verify-all --with-e2e → 9 项全过 0 跳过,38 个脚本 / 1620 条断言 / 0 失败。
This commit is contained in:
+21
-10
@@ -292,11 +292,21 @@ def main():
|
||||
# ── 4. 审核超时提醒 ──
|
||||
print("\n[4] 审核超时提醒(时效与 §11.6 同口径)")
|
||||
# 乙的填报单刚提交 → 还没超时,先跑一次证明不发
|
||||
#
|
||||
# ⚠️ 断言必须**限定到本次夹具的收件人**,不能数全库的"审核超时"消息:
|
||||
# 超时扫描是跨租户的,库里只要存在**别的**老填报单(几天前别的脚本留下的、
|
||||
# 或者上一轮跑到一半留下的),它就会照样提醒 —— 于是这条断言会在
|
||||
# **几天之后突然变红**(那些单子的 submit_time 终于超过 48 小时了),
|
||||
# 而代码一行都没改。第一版就是这么写的,它在本轮真的红了。
|
||||
# 判据改成"这次涉及的两个人有没有收到",就与库里的历史数据无关了。
|
||||
def timeout_msgs_to(uid: int) -> str:
|
||||
return sql("select count(*) from collect_message where user_id=%d and biz_type=2 "
|
||||
"and title like '%%审核超时%%';" % uid)
|
||||
|
||||
body_of("POST", "/api/v1/schedules/run", ops_token, {"job": "timeout"})
|
||||
check("⭐ 刚提交的**不该**被提醒(否则每小时骚扰一次)",
|
||||
sql("select count(*) from collect_message where biz_type=2 "
|
||||
"and title like '%%审核超时%%';") == "0",
|
||||
sql("select count(*) from collect_message where biz_type=2;"))
|
||||
timeout_msgs_to(STU2) == "0",
|
||||
"乙收到的审核超时提醒 = " + timeout_msgs_to(STU2))
|
||||
# 把提交时间改到 5 天前(> 48 小时)→ 应该提醒
|
||||
st = one("select status from collect_submission where task_id=%d and submitter_id=%d;"
|
||||
% (urge_task, STU2))
|
||||
@@ -304,20 +314,21 @@ def main():
|
||||
"submission.status = " + st)
|
||||
R.sql("update collect_submission set submit_time = NOW() - INTERVAL '5 days' "
|
||||
"where task_id=%d and submitter_id=%d;" % (urge_task, STU2))
|
||||
R.sql("delete from collect_message where biz_type=2 and title like '%%审核超时%%';")
|
||||
body_of("POST", "/api/v1/schedules/run", ops_token, {"job": "timeout"})
|
||||
n = sql("select count(*) from collect_message where biz_type=2 "
|
||||
"and title like '%%审核超时%%';")
|
||||
check("⭐ 超时 5 天的被提醒了", n != "0", "提醒条数 = " + n)
|
||||
"and title like '%%审核超时%%' and content like '%%E2E 自动催报%%';")
|
||||
check("⭐ 超时 5 天的被提醒了", n != "0", "本次夹具的提醒条数 = " + n)
|
||||
check("⭐ 文案里带**等了多久**与**时效是多少**(审核员才知道超了多少)",
|
||||
"48" in sql("select content from collect_message where biz_type=2 "
|
||||
"and title like '%%审核超时%%' order by id desc limit 1;"),
|
||||
sql("select content from collect_message where biz_type=2 order by id desc limit 1;"))
|
||||
"and title like '%%审核超时%%' and content like '%%E2E 自动催报%%' "
|
||||
"order by id desc limit 1;"),
|
||||
sql("select content from collect_message where biz_type=2 "
|
||||
"and content like '%%E2E 自动催报%%' order by id desc limit 1;"))
|
||||
check("⭐ 提醒只发给**该动手的人**(班里没配负责人时不该发给所有人)",
|
||||
sql("select count(distinct user_id) from collect_message where biz_type=2 "
|
||||
"and title like '%%审核超时%%';") != "0",
|
||||
"and title like '%%审核超时%%' and content like '%%E2E 自动催报%%';") != "0",
|
||||
sql("select user_id, count(*) from collect_message where biz_type=2 "
|
||||
"group by user_id;").replace("\n", " | "))
|
||||
"and content like '%%E2E 自动催报%%' group by user_id;").replace("\n", " | "))
|
||||
|
||||
# ── 5. 原始件清理 ──
|
||||
print("\n[5] 原始件清理(raw_expire_time 到期)")
|
||||
|
||||
Reference in New Issue
Block a user