Bug 描述
当用户选择需要自定义消息的旗帜类型(例如 notify_moderators、notify_user,或任何在后台启用“需要消息”选项的管理员自定义旗帜),填写消息并提交时,浏览器会抛出未捕获的 TypeError,且旗帜从未被提交。
复现步骤
- 访问任意主题帖子
- 点击旗帜按钮以打开旗帜弹窗
- 选择一个需要消息的旗帜类型(例如“其他事项”/
notify_moderators,或在 管理 → 旗帜 中创建的任何启用“需要消息”的自定义旗帜) - 在文本区域中输入消息(长度需满足最低要求)
- 点击提交按钮
预期行为
旗帜成功提交。
实际行为
旗帜弹窗关闭,但旗帜未被提交。浏览器控制台显示:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'act')
at n.create (flag.js:24:8)
at S.createFlag (flag.gjs:205:32)
at S.takeAction (flag.gjs:196:12)
at m.perform (reviewable-bundled-action.gjs:47:17)
at ej._boundaryActionHandler (select-kit.js:685:34)
...
根本原因分析
崩溃起源于 Flag#create(flag.js:24):
create(flagModal, opts) {
const postAction = this.postActionFor(flagModal); // 返回 undefined
// ...
postAction.act(...) // ← TypeError: Cannot read properties of undefined
}
PostFlag 中的 postActionFor 方法在 actions_summary 中通过数字 id 查找所选旗帜:
// post-flag.js
postActionFor(flagModal) {
return flagModal.args.model.flagModel.actions_summary.find(
(item) => item.id === flagModal.selected.id
);
}
后端 PostSerializer 仅在 can_act、count 或 acted 中至少有一个为真值时,才会在 actions_summary 中包含旗帜条目:
result << summary if summary[:can_act] || summary[:count] || summary[:acted]
对于 require_message: true 的旗帜(均为 notify_type: true),当 already_did_flagging 为真(即用户之前已在该帖子提交过任何通知类旗帜)时,post_can_act? 会将 can_act 设置为 false。此时该条目不会出现在 actions_summary 中,导致 postActionFor 返回 undefined,进而引发崩溃。
与此同时,控制用户在 UI 中可选择内容的 Post#flagsAvailable 使用的是页面加载时构建的 actionByName 映射,因此即使 actions_summary 中不再包含该条目,旗帜仍可能显示为可选。
次要 Bug
flag.gjs 中还存在一个错误的比较:
const NOTIFY_MODERATORS_KEY = "notify_moderators"; // 字符串
get notifyModeratorsFlag() {
return this.flagsAvailable.find((f) => f.id === NOTIFY_MODERATORS_KEY);
// ^ 数字 ^ 字符串 — 始终为 false
}
f.id 是数字,而 NOTIFY_MODERATORS_KEY 是字符串,因此 === 始终返回 false,导致 notifyModeratorsFlag 始终为 undefined。这破坏了 flagForReview() 中“标记以供审查”按钮的逻辑。
建议修复方案
PostFlag#postActionFor 应使用 actionByName 映射(以 name_key 为键),而不是通过 id 搜索 actions_summary,这与 TopicFlag#postActionFor 的现有实现方式保持一致:
// post-flag.js
postActionFor(flagModal) {
return flagModal.args.model.flagModel.actionByName[
flagModal.selected.name_key
];
}
同时,notifyModeratorsFlag 应改为通过 name_key 进行比较:
get notifyModeratorsFlag() {
return this.flagsAvailable.find((f) => f.name_key === NOTIFY_MODERATORS_KEY);
}
Discourse 版本
2026.5.0-latest
可复现于
- 最新的
main分支