- 页脚「纯文本驱动」改为 Powered by Pure Note(链至仓库地址),新增 公安备案展示:国徽图标 + 备案号链至 beian.mps.gov.cn,备案号可在 后台设置(站点描述下一项)配置,留空不显示 - settings 白名单新增 beian_no 键(trim、≤200 字符、可清空),/api/site 一并下发;TestSettingsWhitelist 补生效/清空/超长用例 - 去除首页 hero 文案区(PURE NOTE · 极简笔记/记录,而不打扰。等), 同步清理失效样式并微调顶部留白 - 博客 header 首页/标签菜单补 House/Tags 图标,与管理按钮同风格 - 管理侧栏「返回博客/退出登录」浓缩为图标按钮置于用户行右侧,CSS 悬浮 tooltip(top-center、带箭头,原生 title 延迟高不采用),返回 博客改新窗口打开
80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
package store
|
||
|
||
import (
|
||
"database/sql"
|
||
"errors"
|
||
"strconv"
|
||
"strings"
|
||
)
|
||
|
||
// Settings 键白名单(§7.1 SettingsDTO 同源;admin_password_hash 永不进入 API 响应)。
|
||
const (
|
||
KeyAdminPasswordHash = "admin_password_hash"
|
||
KeySiteTitle = "site_title"
|
||
KeySiteDesc = "site_desc"
|
||
KeyPageSize = "page_size"
|
||
KeyBeianNo = "beian_no"
|
||
)
|
||
|
||
// GetSetting 读取单个设置。
|
||
func (s *Store) GetSetting(key string) (string, bool, error) {
|
||
var v string
|
||
err := s.db.QueryRow(`SELECT value FROM settings WHERE key=?`, key).Scan(&v)
|
||
if errors.Is(err, sql.ErrNoRows) {
|
||
return "", false, nil
|
||
}
|
||
return v, err == nil, err
|
||
}
|
||
|
||
// SetSetting 写入单个设置(INSERT OR REPLACE)。
|
||
func (s *Store) SetSetting(key, value string) error {
|
||
_, err := s.db.Exec(`INSERT INTO settings (key, value) VALUES (?, ?)
|
||
ON CONFLICT(key) DO UPDATE SET value=excluded.value`, key, value)
|
||
return err
|
||
}
|
||
|
||
// SiteSettings 对外的站点设置白名单视图。
|
||
type SiteSettings struct {
|
||
SiteTitle string `json:"site_title"`
|
||
SiteDesc string `json:"site_desc"`
|
||
PageSize int `json:"page_size"`
|
||
BeianNo string `json:"beian_no"`
|
||
}
|
||
|
||
// Defaults,未初始化时兜底。
|
||
const (
|
||
DefaultSiteTitle = "Pure Note"
|
||
DefaultSiteDesc = ""
|
||
DefaultPageSize = 10
|
||
DefaultBeianNo = ""
|
||
)
|
||
|
||
// GetSiteSettings 读取站点设置(白名单键,带默认值)。
|
||
func (s *Store) GetSiteSettings() (*SiteSettings, error) {
|
||
ss := &SiteSettings{SiteTitle: DefaultSiteTitle, SiteDesc: DefaultSiteDesc, PageSize: DefaultPageSize, BeianNo: DefaultBeianNo}
|
||
if v, ok, err := s.GetSetting(KeySiteTitle); err != nil {
|
||
return nil, err
|
||
} else if ok && v != "" {
|
||
ss.SiteTitle = v
|
||
}
|
||
if v, ok, err := s.GetSetting(KeySiteDesc); err != nil {
|
||
return nil, err
|
||
} else if ok {
|
||
ss.SiteDesc = v
|
||
}
|
||
if v, ok, err := s.GetSetting(KeyPageSize); err != nil {
|
||
return nil, err
|
||
} else if ok {
|
||
// strconv.Atoi 全文解析:拒绝 "10abc" 类部分解析的脏值(评审 round2 P2-13)
|
||
if n, err := strconv.Atoi(strings.TrimSpace(v)); err == nil && n >= 1 && n <= 100 {
|
||
ss.PageSize = n
|
||
}
|
||
}
|
||
if v, ok, err := s.GetSetting(KeyBeianNo); err != nil {
|
||
return nil, err
|
||
} else if ok {
|
||
ss.BeianNo = strings.TrimSpace(v)
|
||
}
|
||
return ss, nil
|
||
}
|