# 帖子被作者删除后，其完整正文仍保留在审核队列中，且无法清除

**URL:** <https://meta.discourse.org/t/a-queued-posts-full-body-stays-in-the-review-queue-after-its-author-deletes-the-post-with-no-way-to-scrub-it/413380>\
**Category:** Bug\
**Tags:** gdpr, review-queue\
**Created:** [2026 年9 月 26 日 06:24 UTC](https://meta.discourse.org/t/a-queued-posts-full-body-stays-in-the-review-queue-after-its-author-deletes-the-post-with-no-way-to-scrub-it/413380 "2026-09-26T06:24:35Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

作者： ![kio](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kio/32/579055_2.png) [@kio](https://meta.discourse.org/u/kio)\
发布日期： [2026 年9 月 26 日 06:24 UTC](https://meta.discourse.org/t/a-queued-posts-full-body-stays-in-the-review-queue-after-its-author-deletes-the-post-with-no-way-to-scrub-it/413380/1 "2026-09-26T06:24:36Z")

</div>

## 摘要

当帖子进入审批队列时，`ReviewableQueuedPost.payload["raw"]` 保存了提交内容的完整副本。帖子被批准并由 **作者删除** 后，公开帖子会被替换为“（帖子已被作者删除）”的占位符，但只要帖子记录仍然存在，审核对象（reviewable）就会一直保留原始内容——而在作者删除后，该记录会无限期保留——并持续在 `/review` 页面向工作人员展示该内容。

目前没有清理（scrub）路径：`Reviewable.scrubbable_types` 仅包含 `[ReviewableUser]`，因此 [#36556](https://github.com/discourse/discourse/pull/36556) 中新增的管理员清理操作（“版主现在可以使用‘清理’操作来移除用户的个人数据”）并不涵盖排队中的帖子。只有当有人永久销毁帖子记录时，该 payload 才会被移除，而作者删除操作并不会执行此动作，且 UI 也不允许对主题的首帖执行此操作。

已在 `v2026.7.1` 上复现。截至 2026-09-25，`main` 分支上的相关代码未发生变化。

## 版本

Discourse `v2026.7.1`（自托管，本地授权测试实例）。仅核心代码——未涉及任何插件。

## 复现步骤

1. 以管理员身份，设置普通用户的帖子需要审批，例如将 `approve post count` 设置为 5，并从 `approve unless allowed groups` 中移除 `trust_level_0`。
2. 以该普通用户身份，创建一个主题，并在正文中包含一个唯一标记。响应返回为 `{"action": "enqueued"}`。
3. 以工作人员身份批准该帖子：`PUT /review/<reviewable_id>/perform/approve_post?version=0`。帖子随即创建。
4. 以 **作者** 身份，通过正常的用户端操作删除该帖子——对于该主题的首帖，执行 `DELETE /t/<topic_id>.json`。
5. 以工作人员身份请求 `GET /review.json?status=all`。

> <https://github.com/Kioreo/oss-deletion-missing-pocs/blob/main/products/discourse/review-queue-retains-deleted-post-body/poc.py>

## 预期行为

一旦作者删除了内容，该文本的审核副本应遵循内容的生命周期：它应当被丢弃、清理（scrub），或者至少像被拒绝的 `ReviewableUser` 一样，允许管理员进行清理。

## 实际行为

步骤 5 仍然返回完整的原始正文。在复现运行中测量结果如下：

| 观察项 | 结果 |
| --- | --- |
| 作者删除后的 `posts` 记录 | `user_deleted = t`, `raw = '(topic deleted by author)'` |
| 作者删除后的 `reviewables.payload` | `{"raw":"Queued body DRLGQUEUEDfb08ab5b648f. padding …"}` — 未改变 |
| 工作人员 `GET /review.json?status=all` | 包含原始正文 |
| `Reviewable.scrubbable_types` | `["ReviewableUser"]` |
| 管理员 `PUT /review/<id>/scrub.json` | HTTP 404（非可清理类型） |
| 帖子记录被_永久_销毁后 | 审核对象记录消失（`dependent: :destroy`） |

最后一行是唯一能清除该数据的路径，且无法通过作者删除操作到达：作者删除会将帖子标记为 `user_deleted`，并在 `delete_removed_posts_after` 小时后将其移入回收站。回收站中的帖子记录仍然存在，因此 payload 也仍然存在。

## 原因分析

- `app/models/reviewable_queued_post.rb` 构建并读取 `payload['raw']`；没有任何地方说明其保留目的或生命周期。
- `lib/post_destroyer.rb:562` 中的 `resolve_reviewables_for_author_deletion` 仅处理 `Reviewable.where(target: @post, status: pending)`。 **已批准** 的排队帖子审核对象永远不会被转换或清理。
- `app/models/post.rb:71` 中的 `has_many :reviewables, as: :target, dependent: :destroy` — 这在记录销毁时触发，而作者删除产生的是软删除。
- `app/models/reviewable.rb:81` 中的 `scrubbable_types` 返回 `[ReviewableUser]`；`app/controllers/reviewables_controller.rb:191` 还额外要求 `status: rejected`。
- 没有针对审核对象的定期清理任务。`app/jobs/scheduled/` 包含用于草稿、邮件令牌、导出、上传、API 密钥等的 `clean_up_*` / `purge_*` 任务，但没有针对审核对象的任务。

## 影响

这不是公开泄露——审核队列仅对工作人员可见，我也并未声称它是公开的。这是一个数据保留缺口：用户从论坛移除的文本会无限期地保留在审核存储中，在审核队列 UI 中显示，且除非永久销毁帖子记录，否则没有任何管理员操作可以移除它。

这与 [#36556](https://github.com/discourse/discourse/pull/36556) 为被拒绝用户添加清理功能的原因相同：审核对象 payload 可能包含个人数据，而收到删除请求的网站没有受支持的方法来清除排队帖子的 payload。

## 建议修复方案

以下任一方案均可解决此问题；同时实施两者更佳：

1. 扩展 `resolve_reviewables_for_author_deletion`（以及回收站路径），以清理目标帖子已被作者删除或移入回收站的审核对象的 `payload['raw']`。
2. 将 `ReviewableQueuedPost` 添加到 `Reviewable.scrubbable_types` 中，并让现有的管理员清理操作在目标帖子不再包含内容时生效，以便运营人员拥有受支持的补救措施来处理修复前创建的 payload。

回归测试规格应断言：在作者删除已批准的排队帖子后，审核对象 payload 中不再包含提交的正文。

---

_[View the full topic](https://meta.discourse.org/t/a-queued-posts-full-body-stays-in-the-review-queue-after-its-author-deletes-the-post-with-no-way-to-scrub-it/413380)._
