在现有邮件通知之外补两条广播/点对点通道: - 站级 Webhook([notify] webhook_url):新提问 / 新回答 / 新追问 / 新私聊 / 新投票回复统一 POST JSON 到通用 Webhook(Discord / Slack / 企业微信机器人等)。 消息体同时带 content(Discord 直接可用)与结构化 event/title/body/link 字段。 - 用户级 Telegram([notify] telegram_bot_token + users.telegram_chat_id):箱主 自填 Chat ID,新提问 / 新投票回复点对点推送。 设计约束:通知是「尽力而为」旁路 —— 任一通道发送失败只记日志、不向上抛错, 绝不影响提问/回答的主流程;通道未配置时静默跳过。发送放在 shared.SafeGo 异步 执行,与现有邮件通知同一条路径。 6 处业务触发点接入 notify;私聊消息保留仅邮件(已有 5 分钟节流,避免广播刷屏)。 profile 页新增 Telegram Chat ID 输入框 + 四语言字典。app.sample.ini 加 [notify] 段。 测试覆盖 webhook 的 JSON 结构与未配置时的静默跳过。
77 lines
4.2 KiB
Go
77 lines
4.2 KiB
Go
// Copyright 2022 E99p1ant. All rights reserved.
|
||
// Use of this source code is governed by a MIT-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
package form
|
||
|
||
type UpdateProfile struct {
|
||
Name string `valid:"required;maxlen:20" label:"昵称" msg:"form.profile.name"`
|
||
OldPassword string `label:"旧密码"`
|
||
NewPassword string `valid:"maxlen:30" label:"新密码" msg:"form.profile.passwordMax"`
|
||
Intro string `valid:"required;maxlen:100" label:"介绍" msg:"form.profile.intro"`
|
||
Usernamecolor string `valid:"required;minlen:7;maxlen:7" label:"用户名颜色" msg:"form.profile.colorHex"`
|
||
Introcolor string `valid:"required;minlen:7;maxlen:7" label:"个人说明颜色" msg:"form.profile.colorHex"`
|
||
Qrcodebackcolor string `valid:"required;minlen:7;maxlen:7" label:"二维码背景色" msg:"form.profile.colorHex"`
|
||
Qrcodecolor string `valid:"required;minlen:7;maxlen:7" label:"二维码前景色" msg:"form.profile.colorHex"`
|
||
Dotscale string `valid:"required" label:"二维码点大小" msg:"form.profile.dotscale"`
|
||
Backgroundimagealpha string `valid:"required" label:"二维码背景透明度" msg:"form.profile.backgroundimagealpha"`
|
||
Qrcodepdpcolor string `valid:"required;minlen:7;maxlen:7" label:"二维码探测图形颜色" msg:"form.profile.colorHex"`
|
||
NotifyEmail string `label:"开启邮箱通知"`
|
||
TelegramChatID string `form:"telegram_chat_id" valid:"maxlen:64" label:"Telegram Chat ID" msg:"form.profile.telegramChatId"`
|
||
Acfunlink string `valid:"maxlen:30" label:"AcFun主页" msg:"form.profile.linkMax"`
|
||
Bililink string `valid:"maxlen:30" label:"Bili主页" msg:"form.profile.linkMax"`
|
||
Weibolink string `valid:"maxlen:30" label:"微博主页" msg:"form.profile.linkMax"`
|
||
Bloglink string `valid:"maxlen:30" label:"博客主页" msg:"form.profile.linkMax"`
|
||
Xiaohongshulink string `valid:"maxlen:30" label:"小红书主页" msg:"form.profile.linkMax"`
|
||
UseCustomQRColor string `form:"use_custom_qr_color"`
|
||
Language string `form:"language"`
|
||
}
|
||
|
||
// UpdateProfileTheme 主题外观。空串表示跟随站点默认主题;
|
||
// 取值在白名单之外时保存被拒绝(见 route/user.UpdateTheme),
|
||
// 这样箱主不会「选了个不存在的主题,然后看起来什么都没变」。
|
||
type UpdateProfileTheme struct {
|
||
Theme string `valid:"maxlen:32" label:"主题" msg:"profile.theme.invalid"`
|
||
}
|
||
|
||
// UpdateHarassment 仅「允许注册用户向我提问」开关(防骚扰类型)。
|
||
// 全局屏蔽词为独立入口 UpdateBlockWords:二者分处不同设置面板保存,
|
||
// 若仍共用一个结构体会互相覆盖对方字段(见 route/user/harassment.go 注释)。
|
||
type UpdateHarassment struct {
|
||
RegisterOnly string `label:"仅允许注册用户"`
|
||
}
|
||
|
||
type UpdateBlockWords struct {
|
||
BlockWords string `label:"屏蔽词"`
|
||
}
|
||
|
||
// UpdateModerationStrictness 内容审核严格度(lax / standard / strict)。
|
||
// 与屏蔽词一样是独立的设置入口:两者分处不同的表单,必须分开写,
|
||
// 否则单侧保存会把另一侧的值清空(见 route/user/harassment.go 顶部注释)。
|
||
type UpdateModerationStrictness struct {
|
||
Strictness string `form:"strictness"`
|
||
}
|
||
|
||
type UpdateTags struct {
|
||
Tags string `form:"tags"`
|
||
ShowInHome string `form:"show_in_home"`
|
||
}
|
||
|
||
// 页面访问密码 / 提问密码的最小长度。
|
||
//
|
||
// P1-2:这两个字段此前只有 maxlen,箱主可以设成 1 位或 1234 —— 而页面密码正是产品
|
||
// 对外宣传的访问控制,提问密码是箱主过滤骚扰的唯一门槛。6 位是最低可接受值
|
||
// (纯数字 10^6,配合失败锁定后穷举不可行);留空仍然合法,表示关闭该密码
|
||
// (govalid 对空值跳过 minlen / maxlen)。
|
||
const PasswordMinLen = 6
|
||
|
||
// 新增:页面访问密码表单
|
||
type UpdatePagePassword struct {
|
||
Password string `valid:"minlen:6;maxlen:30" label:"页面访问密码" msg:"form.profile.passwordLen"` // 留空表示关闭
|
||
}
|
||
|
||
// 新增:提问密码表单
|
||
type UpdateAskPassword struct {
|
||
Password string `valid:"minlen:6;maxlen:30" label:"提问密码" msg:"form.profile.passwordLen"` // 留空表示关闭
|
||
}
|