restrict v8

This commit is contained in:
tamakyi
2026-10-18 23:32:38 +08:00
parent 317c96ca17
commit 7a6417c33d
21 changed files with 626 additions and 21 deletions
+42
View File
@@ -322,3 +322,45 @@ admin6 当前处于 L2(到期次日),必要时 `unrestrict` 解除。
验证:`go build ./...` EXIT=0;`go run ./dev/checktpl` → all templates syntax OK;
`go test ./internal/i18n/` 通过。**未部署**,且加了验证码之后原来的 curl 测试方式要改成先算题再提交。
### 部署后验证:4/4 通过
- 无验证码提交 → 302、**未写库**、提示「验证码不能为空」(i18n key `captcha.errEmpty`,非硬编码);
- 带正确算数验证码 → 302 + 「已收到举报,感谢反馈」;
- 同 IP 重复(换新验证码)→ 同样成功提示(幂等,未新增记录);
- 筛选:全部页 `73, 88, 89, 90`,`?reported=reported` 只剩 `73`,下拉 `option value="reported" selected`。
测试遗留:73 号题有 1 条举报(我的测试),需 `DELETE FROM content_reports WHERE question_id = 73;` 清理。
## 新增 `TamaBox hide-public`(存量批量处置)
`internal/cmd/hide_public.go` + 两个入口注册。默认只动「公开且已回答」的题;
`--only-reported` 只处理有 pending 举报的(推荐);`--since N` 限时间窗。
编译 EXIT=0,gofmt 干净。**未在服务器验证**(需部署)。
## 待办与建议(已告知用户,按优先级)
- P0 举报状态闭环:箱主删除/设私密后,该题 pending 举报应置 `accepted`,否则告警阈值会被已处理的旧举报
不断推高(狼来了),且无法统计「成立率」。当前 status 永远停留在 pending。
- P0 箱主侧处置可见性:`/user/questions` 顶部常驻条幅(读 restrictions),避免像今天这样 L2 生效但箱主不知情。
- P1 箱主侧举报通知(某条 ≥3 次时告知箱主自查)、`reports --stats` 全站视图(发现恶意刷举报)。
- P2 社区规则页 `/rules`,处置时引用条款。
- 明确不建议:举报数达标自动处置(武器化)、箱主申诉后台(违背无后台约束)。
## 建议落地(P0/P1/P2 全部完成,编译 + 单测 + 模板检查通过,未部署)
- **P0 举报闭环**:`ReportsStore.MarkAcceptedByQuestion`,在箱主 `Delete` / `SetPrivate` 成功后调用
(失败只记日志,不回滚用户操作);`hide-public` CLI 批量后同样标记。新增 `reportPendingTTL = 30d`:
`QuestionIDsByUser` / `CountByUserSince` / `CountByQuestion` 都按时间窗过滤,**超期 pending 视为过期**,
用查询过滤而不是定时任务(无后台项目不需要调度器)。
- **P0 处置期条幅**:`/user/questions` 顶部读 `Restrictions.ActiveLevel` 渲染常驻 warning
(`qlist.restrictionBanner`,四语言,带级别与到期日)。解决「L2 生效但箱主不知情」。
- **P1 箱主自查提醒**:单条内容待处理举报**恰好等于 3** 时给箱主发邮件
(`mail/question-reported.html`),用「恰好等于」避免每条举报都发;箱主 `Notify=none` 时不发。
邮件明确写「不代表平台已判定违规」。
- **P1 `reports --stats`**:全站 Top 被举报箱主 + Top 举报 IP,用于识别「举报被武器化」。
- **P2 `/rules` 社区规则页**:公开页 + `templates/rules.html` + 四语言 10 个键。
内容含「明确禁止的 4 类」「处置梯度 5 级」「被举报怎么办」「被攻击怎么办」,是处置的引用依据。
⚠️ 文案由我起草,**需用户过目**(尤其对外承诺的措辞)。
验证:`go build ./...` EXIT=0;`checktpl` OK;`TestReports`/`TestRestrictions` 全绿。
+6 -1
View File
@@ -184,8 +184,13 @@
- `restrict --domain|--email --level L1|L2|L3|L4 --days N --reason "..." [--yes]` → 写 `user_restrictions`,
**替换语义**(先撤销该用户所有生效中记录再写新的),到期靠 `expires_at` 比较时间自动失效,无 cron。
- `reports --domain|--email [--days N]` 出证据包(被举报条目 / 公开回答条数 / 占比 / 历史处置);
`reports --pending` 列全站待处理。两者只读。
`reports --pending` 列全站待处理;`reports --stats --days N` 出全站 Top 被举报箱主 + Top 举报 IP
(识别「举报被武器化」)。三者只读。
- `unrestrict --domain|--email` 撤销全部生效中处置。
- `hide-public --domain|--email [--only-reported] [--since N] [--yes]` → 把该箱主「公开且已回答」的题
批量置为私密。`--only-reported` 是推荐用法(只收被投诉的,保留正常内容);`--since N` 限最近 N 天。
⚠️ GORM 链式对象在 Count/Find 后带 Statement 状态,**统计/预览/更新必须各自重新 build query**,
复用一个实例会条件污染。
- `ban --email|--domain [--yes]` → 物理删除用户+内容(不可恢复,邮箱释放)。
- `restore --email|--domain [--password <新密码>] [--yes]` → 恢复已停用账号(清 deleted_at)。
`--password` 必须在恢复之后执行(`UpdatePassword` 走普通作用域)。