From d14d26df1776342f5945fac30244e2ce047a3aaf Mon Sep 17 00:00:00 2001 From: tamakyi Date: Sun, 18 Oct 2026 21:59:12 +0800 Subject: [PATCH] restrict v5 --- .workbuddy/memory/2026-10-18.md | 12 ++++++++++++ .workbuddy/memory/MEMORY.md | 9 +++++++++ route/question/follow_up.go | 6 ++++-- route/question/question.go | 8 ++++++-- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/.workbuddy/memory/2026-10-18.md b/.workbuddy/memory/2026-10-18.md index 50aa0ac..4a49047 100644 --- a/.workbuddy/memory/2026-10-18.md +++ b/.workbuddy/memory/2026-10-18.md @@ -213,3 +213,15 @@ L2/L3 的手测断言(比看 flash 可靠): - **L2 服务端生效**:回答保存成功,但该题变私密 —— 匿名访问 302 到首页,公开页只有 73; - **flash 仍是旧文案**「回答发布成功」→ 服务器跑的是 21:22 部署的二进制,我 21:45 的 flash 修复未部署。 - 88(用户手测)与 89(我自检)都是测试数据,均已被 L2 强制转私密,测完需在后台清理或保持私密。 + +### L3 验证(重新部署 + 切 L3 后) + +qid=90:发提问成功(L3 允许收信 ✔);`POST /answer` **没有重定向**、URL 停在 `/answer`、 +重新加载单题页仍有回答表单 → **发布确实被拒绝、内容未写入**。 +但响应里**没有任何提示文案**(`uk-alert` 只出现在 CSS 里)→ 又一个 bug: + +⚠️ **同请求渲染不能用 `SetErrorFlash`**。`ctx.Success("question/item")` 是直接出页面(没有 302), +而 `SetErrorFlash` 写的是 session、要等下一次请求才读 → 提示静默消失,箱主看到的是「点了没反应」。 +已把 3 处(PublishAnswer L3 / SetPublic L2 / AnswerFollowUp L2)改成 `ctx.SetError(...)`, +并顺手修了 `follow_up.go` 里同类的 moderation 失败分支(既有缺陷)。编译 EXIT=0。 +**该修复需再部署一次**;部署后当前仍是 L3,可直接验提示是否出现。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 883401e..b86c784 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -90,6 +90,15 @@ 替代:迁 `green-cip`(2.0,标签体系不同、需改代码)或退回 `auto`/`qiniu`。RAM 需 `AliyunYundunGreenWebFullAccess`。 - `data[].code != 200` 仍 fail-closed 置 block,但现在会打 Warn(区分「审核失败」与「真违规」)。 +## 提示与 Flash(route 层) + +- ⚠️ **同请求渲染必须用 `ctx.SetError` / `ctx.SetSuccess`,不能用 `*Flash`**:`ctx.Success("...")` 直接出页面时, + `SetErrorFlash` 写的是 session、要等**下一次请求**才会被读取,提示会静默丢失(表现为「点了没反应」)。 + `*Flash` 只适用于 `Redirect` 之后再渲染的页面。 + 2026-10-18 实测:L3 拒绝发布时箱主完全看不到提示,改 `SetError` 后正常显示。 +- 项目里仍有若干 `SetErrorFlash + Success("question/item")` 的既有组合(`follow_up.go` 的 errNotFound、 + `question.go` 的上传图片过大等),同属该缺陷,遇到时顺手改成 `SetError`。 + ## 表单校验 - 长度/必填由 `valid:"required;maxlen:N"` 标签在 `Bind()` 阶段执行(`internal/form/form.go:131` govalid.Check), diff --git a/route/question/follow_up.go b/route/question/follow_up.go index 873d3c0..e9a18e4 100644 --- a/route/question/follow_up.go +++ b/route/question/follow_up.go @@ -167,7 +167,8 @@ func AnswerFollowUp(ctx context.Context, pageUser *db.User, question *db.Questio return } if db.RestrictionAtLeast(restrictionLevel, db.RestrictionL2) { - ctx.SetErrorFlash(i18n.T(ctx.Lang(), "question.errRestrictedPublish")) + // 同请求渲染,用 SetError(SetErrorFlash 要等下一次请求才显示)。 + ctx.SetError(errors.New(i18n.T(ctx.Lang(), "question.errRestrictedPublish")), f) ctx.Success("question/item") return } @@ -176,7 +177,8 @@ func AnswerFollowUp(ctx context.Context, pageUser *db.User, question *db.Questio // 内容安全检测:统一守卫,箱主本人回复同样按自己的审核严格度裁决。 if _, err := moderation.Check(ctx.Request().Context(), moderation.StrictnessFor(pageUser.ModerationStrictness), ctx.Lang(), f.Answer); err != nil { - ctx.SetErrorFlash(err.Error()) + // 同请求渲染,用 SetError;原先的 SetErrorFlash 在这里不会显示出来(既有缺陷)。 + ctx.SetError(err, f) ctx.Success("question/item") return } diff --git a/route/question/question.go b/route/question/question.go index ca77920..ed40d74 100644 --- a/route/question/question.go +++ b/route/question/question.go @@ -174,7 +174,10 @@ func PublishAnswer(ctx context.Context, pageUser *db.User, question *db.Question return } if db.RestrictionAtLeast(restrictionLevel, db.RestrictionL3) { - ctx.SetErrorFlash(i18n.T(ctx.Lang(), "question.errRestrictedPublish")) + // 这里是**同请求渲染**(Success 直接出页面,没有重定向),必须用 SetError 写 + // Data["Error"];SetErrorFlash 依赖下一次请求读取,用在这里提示会静默丢失 + // (线上实测:箱主点提交后页面毫无反应,以为没生效)。 + ctx.SetError(errors.New(i18n.T(ctx.Lang(), "question.errRestrictedPublish")), f) ctx.Success("question/item") return } @@ -303,7 +306,8 @@ func SetPublic(ctx context.Context, pageUser *db.User, question *db.Question, ca return } if db.RestrictionAtLeast(restrictionLevel, db.RestrictionL2) { - ctx.SetErrorFlash(i18n.T(ctx.Lang(), "question.errRestrictedPublic")) + // 同请求渲染,用 SetError(原因见 PublishAnswer 的 L3 分支)。 + ctx.SetError(errors.New(i18n.T(ctx.Lang(), "question.errRestrictedPublic"))) ctx.Success("question/item") return }