fix anwser token and database issus

This commit is contained in:
tamakyi
2026-09-15 11:06:09 +08:00
parent e683e798aa
commit adcc42cc8c
33 changed files with 1011 additions and 802 deletions
+17 -30
View File
@@ -15,24 +15,17 @@ import (
"github.com/tamakyi/TamaBox/internal/i18n"
)
// returnTab 表单提交后回跳的账号设置面板:屏蔽词设置已分散展示在
// 提问/私聊/投票三个面板,action 携带 ?tab= 来源参数,保存后停留原面板。
// returnTab 表单提交后回跳的面板:action 携带 ?tab= 来源参数,保存后停留原面板。
func returnTab(ctx context.Context) string {
return profileURLWithTab(ProfileTab(ctx.Query("tab")))
}
// abortOnFormError 处理表单校验/反序列化失败:返回 true 表示已中止本次写入。
// abortOnFormError 处理表单校验/反序列化失败:返回 true 表示已中止本次写入,不触碰既有配置。
//
// 背景:form.Bind 在反序列化失败(如请求体超限、body 畸形)时只置位错误并继续执行
// handler 链(flamego 语义:响应未写即自动续链),零值结构体会照常进入业务动作——
// 对不检查 ctx.HasError() 的 handler,会把用户既有配置静默清空/关闭,例如:
// - UpdateHarassment:RegisterOnly="" → 防骚扰被改回 none(关闭"仅允许注册用户");
// - UpdateBlockWords:BlockWords="" → 全部屏蔽词被清空;
// - UpdateTags:Tags="" → 标签被清空、ShowInHome 被关;
// - UpdatePagePassword / UpdateAskPassword:Password="" → 访问/提问密码被解除。
//
// 错误信息已由 Bind 经 context.SetError 写入 Data["Error"](govalid 校验错误已按界面
// 语言翻译,解析错误为原文),此处转入 flash,保证 PRG 重定向后仍能向用户展示。
// ⚠️ form.Bind 反序列化失败(请求体超限、body 畸形)时只置位错误并继续走 handler 链
// (flamego 语义:响应未写即自动续链),零值结构体会进入业务动作,把用户既有配置静默清空:
// 防骚扰被改回 none、屏蔽词/标签被清空、访问与提问密码被解除。
// 错误信息已由 Bind 写入 Data["Error"],此处转入 flash 以便 PRG 重定向后仍可展示。
func abortOnFormError(ctx context.Context, redirectTo string) bool {
if !ctx.HasError() {
return false
@@ -44,12 +37,11 @@ func abortOnFormError(ctx context.Context, redirectTo string) bool {
return true
}
// UpdateHarassment 仅更新「防骚扰类型」(none / register_only,即"仅允许注册用户向我提问")。
// 只写 harassment_setting 列;全局屏蔽词已拆分为独立入口 UpdateBlockWords,
// 二者互不覆盖(此前同一个表单一次写两列,面板拆分后单侧保存会误清空另一侧)。
// UpdateHarassment 仅更新防骚扰类型(none / register_only)。只写 harassment_setting 列:
// 全局屏蔽词已拆分为 UpdateBlockWords,二者互不覆盖(同表单一次写两列时,
// 面板拆分后单侧保存会误清空另一侧)。
func UpdateHarassment(ctx context.Context, f form.UpdateHarassment) {
// 反序列化失败(如请求体超限)时零值 RegisterOnly="" 会把防骚扰静默改回 none
// (若此前为 register_only)——先中止,不触碰现有设置。
// 零值 RegisterOnly="" 会把防骚扰静默改回 none(见 abortOnFormError)。
if abortOnFormError(ctx, returnTab(ctx)) {
return
}
@@ -70,11 +62,10 @@ func UpdateHarassment(ctx context.Context, f form.UpdateHarassment) {
ctx.Redirect(returnTab(ctx))
}
// UpdateBlockWords 更新全局屏蔽词表:提问、私聊(对方发给我的消息)与投票
// 提交的开放文本共用同一份词表(users.block_words)。
// UpdateBlockWords 更新全局屏蔽词表:提问、私聊(对方发给我的消息)与投票提交的
// 开放文本共用同一份词表(users.block_words)。
func UpdateBlockWords(ctx context.Context, f form.UpdateBlockWords) {
// 反序列化失败(如请求体超限)时零值 BlockWords="" 会经 sanitizeBlockWords 得到
// 空词表,静默清空用户全部屏蔽词——先中止,不触碰现有词表。
// 零值 BlockWords="" 会经 sanitizeBlockWords 得到空词表,静默清空全部屏蔽词。
if abortOnFormError(ctx, returnTab(ctx)) {
return
}
@@ -101,12 +92,9 @@ func UpdateBlockWords(ctx context.Context, f form.UpdateBlockWords) {
ctx.Redirect(returnTab(ctx))
}
// sanitizeBlockWords 把输入的屏蔽词串规整为去重后的词表:
// - 全角逗号转半角;逐词 TrimSpace;跳过空词与重复词。
// - 单词长度按字符(rune)计数,超限(conf.Limits.MaxBlockWordLen)返回超长提示;
// - 词总数超限(conf.Limits.MaxBlockWords)返回数量提示。
//
// 成功时 errKey 为空,errWord 为触发超长的具体词(供 flash 展示)。
// sanitizeBlockWords 把输入词串规整为去重词表:全角逗号转半角、逐词 TrimSpace、
// 跳过空词与重复词;单词长度超限(conf.Limits.MaxBlockWordLen)或总数超限
// (conf.Limits.MaxBlockWords)返回对应提示。成功时 errKey 为空,errWord 为超长的具体词。
func sanitizeBlockWords(raw string) (words []string, errKey string, errWord string) {
blockWords := strings.ReplaceAll(raw, ",", ",")
blockWords = strings.TrimSpace(blockWords)
@@ -123,9 +111,8 @@ func sanitizeBlockWords(raw string) (words []string, errKey string, errWord stri
}
wordSet[word] = struct{}{}
// 按字符(rune)计数:早期用 len(word) 按字节计数,中文一词 3 字节,
// 按 rune 计数:早期用 len(word) 按字节算,中文一词 3 字节,
// 导致中文屏蔽词实际只能输 3 个字,与界面文案「最大长度为 10」不符。
// 上限取自 conf.Limits.MaxBlockWordLen([limits] 配置段)。
if len([]rune(word)) > conf.Limits.MaxBlockWordLen {
return nil, "admin.flash.blockWordTooLong", word
}