Files
tamabox/internal/conf/limits.go
T
2026-09-08 10:10:44 +08:00

120 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2026 tamakyi. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package conf
// 各项上限的内置默认值(与旧版硬编码一致)。既是未配置 [limits] 段时的兜底,
// 也是 conf.Init 后归一化(sanitizeLimits)的回退基准。
const (
defaultMaxTags = 5
defaultMaxTagLen = 5
defaultMaxBlockWords = 10
defaultMaxBlockWordLen = 10
defaultCustomAnswerLen = 200
defaultVoteOptionLen = 300
defaultQuestionContentLen = 1000
defaultAnswerContentLen = 2000
defaultFollowUpContentLen = 2000
defaultChatMessageLen = 2000
defaultChatMaxMessages = 200
defaultDailyMessageLimitMax = 999
)
// LimitsConfig 全站内容 / 数量上限([limits] 配置段)的字段集合。
//
// 过去这些上限以常量形式散落在 internal/db(MaxTags / MaxCustomTextLen 等)与
// 路由层硬编码(私聊单条 2000 字、会话条数 clamp 5~200 等)中,调整需改代码重编译,
// 且前后端、i18n 文案各自携带一份数值容易漂移。统一收口到 [limits] 段后:
// - 后端校验、模板注入、前端提示全部引用 conf.Limits 的同一份值;
// - 调整仅需修改 conf/app.ini 并重启进程,无需改代码;
// - 长度类上限统一按字符(rune / Unicode 码点)计数。
type LimitsConfig struct {
// ── 标签与屏蔽词(账号设置页)──
// 标签个数上限
MaxTags int `ini:"max_tags"`
// 单个标签最大字符数
MaxTagLen int `ini:"max_tag_len"`
// 屏蔽词个数上限
MaxBlockWords int `ini:"max_block_words"`
// 单个屏蔽词最大字符数
MaxBlockWordLen int `ini:"max_block_word_len"`
// ── 投票 ──
// 参与者填写的「自定义补充选项」文本最大字符数。
// 覆盖两类入口:单选/多选/排序的全局补充选项,以及表单收集字段的
// 「其他/自定义选项」(field_{id}_custom)。
CustomAnswerLen int `ini:"custom_answer_len"`
// 站长创建投票时单个「选项」文本的最大字符数。
// 覆盖单选/多选/排序的预设选项,以及表单收集字段(select/radio/checkbox/rank)
// 的预置选项。与 CustomAnswerLen 是两条独立规则(站长侧预设刻意放宽),可各自调参。
VoteOptionLen int `ini:"vote_option_len"`
// ── 提问 / 回答 / 追问 ──
// 提问正文最大字符数(访客向提问箱提交的问题内容)。
// 旧实现依赖 govalid 的 maxlen 标签(编译期写死 2000),无法随配置调整,
// 且与前端 maxlength=1000 不一致,现已移到路由层按本值做 rune 校验。
QuestionContentLen int `ini:"question_content_len"`
// 回答正文最大字符数:箱主对提问的正式回答,以及箱主对追问的回复(共用)。
AnswerContentLen int `ini:"answer_content_len"`
// 追问正文最大字符数(提问者在问题被回答后继续追问的内容)。
FollowUpContentLen int `ini:"followup_content_len"`
// ── 私聊 ──
// 单条消息(发送 / 回复共用)最大字符数
ChatMessageLen int `ini:"chat_message_len"`
// 每个私聊会话的消息条数上限(系统硬顶)。用户只能在 1..该值 之间设置自己的
// chat_max_messages;新注册用户的默认值即该硬顶(而非固定 20)。
ChatMaxMessages int `ini:"chat_max_messages"`
// 单用户每日私信条数上限(用户可设范围 0..该值;0 表示不限制每日条数)。
// 该值只是「用户可设置的上限」,不是站点强制的每日配额。
DailyMessageLimitMax int `ini:"daily_message_limit_max"`
}
// Limits 保存运行时的全部上限配置。conf.Init 中会先 MapTo [limits] 段覆盖显式键,
// 再调用 sanitizeLimits 把 <1 的值回退到内置默认,因此:
// - 缺失 [limits] 段或个别键 → 使用内置默认;
// - ini 键留空(int 解析为 0)或误填 0/负数 → 自动回退默认,不会把上限静默置零。
var Limits = LimitsConfig{
MaxTags: defaultMaxTags,
MaxTagLen: defaultMaxTagLen,
MaxBlockWords: defaultMaxBlockWords,
MaxBlockWordLen: defaultMaxBlockWordLen,
CustomAnswerLen: defaultCustomAnswerLen,
VoteOptionLen: defaultVoteOptionLen,
QuestionContentLen: defaultQuestionContentLen,
AnswerContentLen: defaultAnswerContentLen,
FollowUpContentLen: defaultFollowUpContentLen,
ChatMessageLen: defaultChatMessageLen,
ChatMaxMessages: defaultChatMaxMessages,
DailyMessageLimitMax: defaultDailyMessageLimitMax,
}
// sanitizeLimits 归一化 [limits] 配置:所有上限最小为 1(0 / 负数说明未配置或手滑,
// 一律回退内置默认,避免「留空=0」把标签全拒、消息全超长等隐性灾难)。
// 注意 DailyMessageLimitMax 同样要求 >=1:0 会让用户侧永远只能设为 0(=不限制),
// 语义上等于关闭每日配额功能,需显式使用该字段其余语义时请另行设计。
func sanitizeLimits(l *LimitsConfig) {
clamp1 := func(p *int, def int) {
if *p < 1 {
*p = def
}
}
clamp1(&l.MaxTags, defaultMaxTags)
clamp1(&l.MaxTagLen, defaultMaxTagLen)
clamp1(&l.MaxBlockWords, defaultMaxBlockWords)
clamp1(&l.MaxBlockWordLen, defaultMaxBlockWordLen)
clamp1(&l.CustomAnswerLen, defaultCustomAnswerLen)
clamp1(&l.VoteOptionLen, defaultVoteOptionLen)
clamp1(&l.QuestionContentLen, defaultQuestionContentLen)
clamp1(&l.AnswerContentLen, defaultAnswerContentLen)
clamp1(&l.FollowUpContentLen, defaultFollowUpContentLen)
clamp1(&l.ChatMessageLen, defaultChatMessageLen)
clamp1(&l.ChatMaxMessages, defaultChatMaxMessages)
clamp1(&l.DailyMessageLimitMax, defaultDailyMessageLimitMax)
}