26.9:版本号统一 + CI 精简 + 前端产物重建
CI 测试 / go vet + go test (push) Successful in 49s

- 全项目版本号统一:v3.x 迭代号(26.9/26.9/26.9/26.9 及裸 v2/v3)→ 26.9,
  覆盖 Go 注释 / 文档 / openapi.yaml / README×4 / 前端源码(80+ 处)
- v31_test.go 更名 custom_code_test.go;TestV2AccessorDefaults → TestKVAccessorDefaults
- docs/api/00-overview.md 更新日志合并为单条 26.9 条目(修复错位拼接)
- .goreleaser.yaml 头部注释与实际一致(Pro 2.18.1 / GITEA_TOKEN / semver tag 要求)
- CI:release-image.yml → ci.yml,仅保留 vet+test 门禁;
  镜像发布移交 GoReleaser Pro(原 build-push 的 tag 校验与 26.9 版本方案冲突,历史 9 次失败)
- 前端重建:server/web/dist 与 web-embed 同步(docs 文案嵌入更新)
This commit is contained in:
2026-09-08 03:16:51 +08:00
parent 27432218c4
commit 84df9996cb
122 changed files with 247 additions and 12268 deletions
+15 -15
View File
@@ -78,7 +78,7 @@ func registerAdmin(r *gin.Engine, d *Deps) {
authed.PATCH("/settings/password", d.adminChangePassword)
authed.POST("/settings/password", d.adminChangePassword)
// v3 存储引擎:运行时热切换(健康检查通过才生效,失败保持原引擎)
// 26.9 存储引擎:运行时热切换(健康检查通过才生效,失败保持原引擎)
authed.POST("/storage/switch", d.adminStorageSwitch)
// 审计日志查询(需求 ③;logs 为 list 的别名)
@@ -404,7 +404,7 @@ func buildAdminFileItem(fc *model.FileCodes, now time.Time) gin.H {
"hasDownloadLimit": fc.ExpiredCount >= 0, "has_download_limit": fc.ExpiredCount >= 0,
"isPermanent": fc.ExpiredAt == nil && fc.ExpiredCount < 0, "is_permanent": fc.ExpiredAt == nil && fc.ExpiredCount < 0,
"remainingDownloads": remaining, "remaining_downloads": remaining,
"engine": fc.Engine, // v3:归属引擎(管理端展示/排查用)
"engine": fc.Engine, // 26.9:归属引擎(管理端展示/排查用)
}
if fc.FileHash != nil {
item["fileHash"] = *fc.FileHash
@@ -784,7 +784,7 @@ func (d *Deps) adminFilePreview(c *gin.Context) {
// ============ 配置 ============
// configKeys 管理端可见/可改的配置键(不含 jwt_secretadmin_token 屏蔽展示)。
// v2 新增键(需求 ①②③④⑩):背景图、页脚、通知开关、保存/存储策略、频率限制。
// 26.9 新增键(需求 ①②③④⑩):背景图、页脚、通知开关、保存/存储策略、频率限制。
var configKeys = []string{
"site_name", "name", "description", "page_explain", "keywords",
"notify_title", "notify_content", "notify_enabled", "logo_url", "favicon_url",
@@ -794,11 +794,11 @@ var configKeys = []string{
"code_generate_type", "enableChunk",
"uploadMinute", "uploadCount", "errorMinute", "errorCount",
"loginCount", "loginMinute",
"opacity", "background", "showAdminAddr", "robotsText", "site_domain", // v3.1:站点对外域名
"upload_rate", "download_rate", // v3.2:上下行带宽字节/秒(0=不限速)
"opacity", "background", "showAdminAddr", "robotsText", "site_domain", // 26.9:站点对外域名
"upload_rate", "download_rate", // 26.9:上下行带宽字节/秒(0=不限速)
"adminSessionExpire", "storage_path", "local_storage_path",
"file_storage",
// v3 存储引擎与引擎参数(热切换;凭据为敏感键,get 掩码/update 空跳过)
// 26.9 存储引擎与引擎参数(热切换;凭据为敏感键,get 掩码/update 空跳过)
"storage_engine",
"local_storage_path",
"webdav_url", "webdav_root_path", "webdav_username", "webdav_password",
@@ -807,7 +807,7 @@ var configKeys = []string{
}
// intConfigKeys 需按 schema 边界校验的整型键(adminConfigUpdate 归一化用)。
// v1 既有键保留原语义;v2 新增键(max_file_size/max_save_count/notify_enabled
// v1 既有键保留原语义;26.9 新增键(max_file_size/max_save_count/notify_enabled
// 的边界来自 settings.KVSchema(单一事实来源在 config/schema.go)。
var intConfigKeys = []string{
"openUpload", "enableChunk", "showAdminAddr", "storageLimit",
@@ -815,7 +815,7 @@ var intConfigKeys = []string{
"loginCount", "loginMinute", "max_save_seconds", "uploadSize",
"adminSessionExpire",
"max_save_count", "max_file_size", "notify_enabled",
"upload_rate", "download_rate", // v3.2
"upload_rate", "download_rate", // 26.9
}
// validateConfigValue 按 settings.KVSchema 校验单个配置值:
@@ -905,7 +905,7 @@ func toStrSlice(v any) []string {
}
// adminConfigGet 读取配置(对齐参考 get_configadmin_token 屏蔽、jwt_secret 不下发)。
// v3:引擎凭据类敏感键返回掩码占位(前端表单"留空=不修改");storage_engine 为当前热切换后的引擎。
// 26.9:引擎凭据类敏感键返回掩码占位(前端表单"留空=不修改");storage_engine 为当前热切换后的引擎。
func (d *Deps) adminConfigGet(c *gin.Context) {
cfg := d.Cfg
out := gin.H{}
@@ -925,7 +925,7 @@ func (d *Deps) adminConfigGet(c *gin.Context) {
}
// jwt_secret 永不下发
delete(out, "jwt_secret")
// 引擎运行时状态(v3:热切换即时生效,无需重启)
// 引擎运行时状态(26.9:热切换即时生效,无需重启)
out["_engine_hint"] = gin.H{
"storage_backend": d.Store.CurrentName(),
"engines": gin.H{"local": true, "s3": true, "webdav": true},
@@ -973,7 +973,7 @@ func (d *Deps) adminConfigUpdate(c *gin.Context) {
if !known {
continue
}
// 类型归一 + schema 边界校验(v2:数值/字符串长度/列表键统一走 KVSchema)
// 类型归一 + schema 边界校验(26.9:数值/字符串长度/列表键统一走 KVSchema)
isInt := false
for _, key := range intConfigKeys {
if key == k {
@@ -1067,7 +1067,7 @@ func (d *Deps) adminConfigUpdate(c *gin.Context) {
dbPatch["jwt_secret"] = settings.GenerateJWTSecret()
}
// v3.1site_domain 规范化(http(s)://host[:port];空=用当前地址)
// 26.9site_domain 规范化(http(s)://host[:port];空=用当前地址)
if raw, ok := dbPatch["site_domain"]; ok {
sv, _ := raw.(string)
normalized, err := normalizeSiteDomain(sv)
@@ -1078,7 +1078,7 @@ func (d *Deps) adminConfigUpdate(c *gin.Context) {
dbPatch["site_domain"] = normalized
}
// v3 引擎键处理:参数键与 storage_engine 分离。
// 26.9 引擎键处理:参数键与 storage_engine 分离。
// 1) storage_engine 只接受合法枚举;
// 2) 敏感凭据键空串/掩码=不修改(避免管理端表单回显把密钥抹掉);
// 3) 先持久化普通键+参数键 → Invalidate 对应引擎缓存 → 再尝试 Switch 新引擎;
@@ -1152,7 +1152,7 @@ func engineOfParamKeys(patch map[string]any) []string {
return out
}
// adminStorageSwitch v3 存储引擎热切换:{engine:"local"|"s3"|"webdav"}。
// adminStorageSwitch 26.9 存储引擎热切换:{engine:"local"|"s3"|"webdav"}。
// 成功:持久化 storage_engine KV 并返回当前引擎;失败:503 且原引擎不变。
func (d *Deps) adminStorageSwitch(c *gin.Context) {
var body struct {
@@ -1302,7 +1302,7 @@ func (d *Deps) fileByID(c *gin.Context, id int64) (*model.FileCodes, error) {
// deleteFileCode 删除分享记录与存储文件(文本分享无存储文件)。
func (d *Deps) deleteFileCode(c *gin.Context, fc *model.FileCodes) error {
if fc.Text == nil && fc.FilePath != nil && fc.UUIDFileName != nil {
// v3:删除走文件归属引擎(旧引擎里的文件也要能删掉)
// 26.9:删除走文件归属引擎(旧引擎里的文件也要能删掉)
if delStore, dErr := d.storeFor(fc.Engine); dErr == nil {
if err := delStore.DeleteFile(c.Request.Context(), fileSavePath(fc)); err != nil && !errors.Is(err, storage.ErrNotFound) {
return errInternal("存储文件删除失败: " + err.Error())