sam
(Sam Saffron)
1
允许社区成员建议对帖子进行编辑,使审阅者对接受哪些更改拥有精细的控制权——而无需授予完全的编辑权限。
此插件目前处于实验阶段,可能会有很大变动,尚不适用于生产环境。
GitHub - discourse/discourse-suggested-edits: EXPERIMENTAL suggested edits plugin · GitHub
安装
按照标准插件安装指南,使用以下仓库 URL:
https://github.com/discourse/discourse-suggested-edits.git
为什么要使用建议编辑?
许多社区希望成员帮助保持内容准确和最新,但授予每个人编辑权限并不总是可行的。建议编辑弥合了这一差距——成员可以提议改进帖子,受信任的审阅者决定采纳哪些内容。可以将其视为将类似维基百科的贡献模式带到您的 Discourse 社区。
这对于以下情况特别有用:
- 知识库和文档类别,其中准确性很重要,并且多双眼睛有帮助
- 新成员较多的社区,他们有好的贡献但尚未获得完全的编辑信任
- 协作内容,如常见问题解答、指南或社区维护的参考资料
- 自动化编辑,有时人工智能系统可能会建议修复拼写错误和语调问题,并且需要有人工参与批准
工作原理
建议编辑
在配置的建议组中的成员将在符合条件的帖子上有“建议编辑”按钮。点击该按钮会打开预先填充了帖子内容的编辑器。他们进行更改,可以选择添加原因,然后提交。

审阅建议
审阅者会在有待处理建议的帖子旁看到一个计数徽章。点击“审阅”会打开一个模态框,将建议分解为单个更改——每个更改都显示为带有周围上下文的高亮差异。
审阅者可以:
- 独立接受或拒绝每项更改——无需全盘接受或拒绝
- 在应用前编辑建议的文本——在保留意图的同时微调措辞
- 在行内和并排差异视图之间切换
- 在多个建议之间导航(如果有多个待处理)
应用更改
当审阅者点击“应用接受的更改”时,所选的更改将作为归属于建议者的修订应用于帖子,编辑原因会注明批准人。建议者和任何其他受影响的用户都会收到通知。
停滞处理
如果原始帖子在创建建议后被编辑,该建议将自动标记为停滞(stale)且无法应用。这可以防止冲突,并确保建议始终基于当前内容。建议者会收到通知,以便在需要时重新提交。
配置
在管理 > 设置下启用插件并配置访问权限,搜索“suggested edits”:
| 设置 |
描述 |
suggested_edits_enabled |
插件的主开关 |
suggested_edits_suggest_groups |
可以建议编辑的组成员所属的组 |
suggested_edits_review_groups |
可以审阅和应用建议的组成员所属的组。帖子作者始终可以审阅其自己帖子的建议。 |
suggested_edits_included_categories |
启用了建议编辑的类别 |
suggested_edits_included_tags |
在其中启用了建议编辑的主题的标签 |
suggested_edits_max_creates_per_minute |
创建建议的速率限制(默认:5) |
suggested_edits_max_revisions_per_minute |
审阅建议的速率限制(默认:10) |
典型设置
- 启用插件
- 将建议组设置为应该能够提议编辑的信任级别或组(例如
trust_level_1)
- 将审阅组设置为您的版主或策展人(例如
staff)
- 选择您希望启用此功能的类别或标签——您不必在所有地方都启用它
帖子作者始终可以审阅其自己帖子的建议,无论审阅组设置如何。
范围和限制
- 仅限首帖——建议编辑目前仅适用于主题的首帖(OP),不适用于回复
- 每个帖子每个用户只能有一个待处理的建议——成员必须等待他们当前的建议得到解决,才能在同一帖子中提交另一个建议
- 建议基于文本——差异是根据帖子的原始 Markdown 内容计算的
搜索
审阅者可以使用搜索过滤器 with:suggested-edits 来查找论坛中所有有待处理建议的主题。
17 个赞
嗯……当有人建议编辑帖子时,会通知该帖子的原作者(OP)吗?我查看了代码,但没有发现任何相关迹象。
2 个赞
您好,好主意!在选择分类时,能否只选择一级分类,同时自动选中其子分类?谢谢。
1 个赞
Lilly
(Lillian )
6
供参考,此插件抛出错误:
plugin-api.gjs:234 [PLUGIN discourse-suggested-edits] 尝试修改 "service:composer",但它已在引导过程的更早阶段初始化(例如通过 lookup())。请移除该 lookup,或将 modifyClass 调用移至引导过程的更早阶段以使更改生效。https://meta.discourse.org/t/262064
_resolveClass @ plugin-api.gjs:234
看起来初始化器在调用 api.modifyClass("service:composer", {...}) 之前调用了 api.customizeComposerText()。我认为代码需要重新排序,使 api.modifyClass 在 api.customizeComposerText 之前运行:
或许应该这样?
// 先修改 composer 类
api.modifyClass("service:composer", {
pluginId: "discourse-suggested-edits",
async open(opts) {
if (isSuggestedEditAction(opts.action) && this.model) {
this.model.set("disableDrafts", true);
this.skipAutoSave = true;
this.close();
this.skipAutoSave = false;
}
setSuggestEditActive(
isSuggestedEditAction(opts.action),
opts.metaData?.originalRaw
);
await this._super(opts);
if (isSuggestedEditModel(this.model)) {
this.model.setProperties({
disableDrafts: true,
draftStatus: null,
draftConflictUser: null,
});
}
},
cancelComposer(opts) {
if (isSuggestedEditModel(this.model)) {
setSuggestEditActive(false);
this.skipAutoSave = true;
this.close();
this.appEvents.trigger("composer:cancelled");
this.skipAutoSave = false;
return Promise.resolve();
}
return this._super(opts);
},
destroyDraft() {
if (isSuggestedEditModel(this.model)) {
return Promise.resolve();
}
return this._super();
},
_saveDraft(showToast = false) {
if (isSuggestedEditModel(this.model)) {
return Promise.resolve();
}
return this._super(showToast);
},
save(force, options = {}) {
if (isSuggestedEditModel(this.model)) {
return this._saveSuggestedEdit();
}
return this._super(force, options);
},
async _saveSuggestedEdit() {
const model = this.model;
const meta = model.metaData || {};
if (model.reply?.trim() === meta.originalRaw?.trim()) {
this.toasts.error({
data: {
message: i18n("discourse_suggested_edits.composer.no_changes"),
},
duration: "short",
});
return;
}
try {
if (meta.existingSuggestionId) {
await updateSuggestedEdit(meta.existingSuggestionId, {
raw: model.reply,
reason: meta.reason,
});
this.toasts.success({
data: {
message: i18n("discourse_suggested_edits.toast.updated"),
},
duration: "short",
});
} else {
const result = await createSuggestedEdit({
postId: meta.postId,
raw: model.reply,
reason: meta.reason,
});
if (model.topic) {
model.topic.set(
"own_pending_suggested_edit_id",
result.suggested_edit.id
);
}
this.toasts.success({
data: {
message: i18n("discourse_suggested_edits.toast.created"),
},
duration: "short",
});
}
setSuggestEditActive(false);
this.close();
} catch (e) {
popupAjaxError(e);
}
},
});
// 在类被修改后再添加自定义
api.customizeComposerText({
actionTitle(model) {
if (model.action === SUGGEST_EDIT_ACTION) {
return i18n("discourse_suggested_edits.composer.action_title");
}
},
saveLabel(model) {
if (model.action === SUGGEST_EDIT_ACTION) {
return "discourse_suggested_edits.composer.save_label";
}
},
});
1 个赞
sam
(Sam Saffron)
7
我们可能需要将其移至预初始化阶段……我会看看的,感谢尝试 @Lilly
1 个赞