后台:站点设置新增社交链接与自定义 JS 字段

social_links 以 JSON 数组存进 settings KV([{label,url}]),解码容错:
空串 / 坏 JSON / 缺 label 或 url 的条目一律丢弃,前台拿到空数组时区块
自动隐藏。custom_js 原样存取——它是站主自己的代码(统计脚本等),
做转义只会把脚本洗坏。后台表单与前台展示在下一笔前端提交里。
This commit is contained in:
Sakurasan
2026-09-27 03:34:43 +08:00
parent 75737034d9
commit 5dfa1550fb
3 changed files with 54 additions and 2 deletions
+39 -1
View File
@@ -193,12 +193,46 @@ func settingsFromMap(m map[string]string) model.Settings {
st.ThemeID = st.LightSkinID
st.UIID = sanitizeUI(m["ui_id"])
st.CustomCSS = decodeCSSMap(m["custom_css"])
st.CustomJS = m["custom_js"]
st.SocialLinks = decodeSocialLinks(m["social_links"])
if n := atoi(m["posts_per_page"]); n > 0 {
st.PostsPerPage = n
}
return st
}
// decodeSocialLinks 把 KV 里的 JSON 数组还原成社交链接。容错:空串、坏 JSON、
// 缺 label/url 的条目一律丢弃,返回空切片(前台区块自动隐藏)。
func decodeSocialLinks(s string) []model.SocialLink {
out := []model.SocialLink{}
if strings.TrimSpace(s) == "" {
return out
}
if err := json.Unmarshal([]byte(s), &out); err != nil {
return []model.SocialLink{}
}
clean := make([]model.SocialLink, 0, len(out))
for _, l := range out {
l.Label = strings.TrimSpace(l.Label)
l.URL = strings.TrimSpace(l.URL)
if l.Label != "" && l.URL != "" {
clean = append(clean, l)
}
}
return clean
}
func encodeSocialLinks(ls []model.SocialLink) string {
if len(ls) == 0 {
return ""
}
b, err := json.Marshal(ls)
if err != nil {
return ""
}
return string(b)
}
func atoi(v string) int {
n := 0
for _, r := range v {
@@ -341,6 +375,10 @@ func (s *Store) UpdateSettings(st model.Settings) error {
"ui_id": st.UIID,
// Full replace: an omitted/empty map clears every section's CSS.
"custom_css": encodeCSSMap(st.CustomCSS),
// 原样存:站主自己的代码,不做任何转义/清洗。
"custom_js": st.CustomJS,
// 空数组存空串:KV 里不留 "null"。
"social_links": encodeSocialLinks(st.SocialLinks),
}
for k, v := range sets {
if s.db.Dialect == db.Postgres {
@@ -522,7 +560,7 @@ func (s *Store) Get(id int64) (model.Post, error) {
// 返回顺序与时间线一致(published_at DESC):最旧在最前、最新在最后,
// 目标文章夹在中间,前后各取最多 2 篇。
func (s *Store) Neighbors(slug string) ([]model.Post, error) {
rows, err := s.db.Query(s.db.Q(`SELECT ` + listCols + ` FROM posts
rows, err := s.db.Query(s.db.Q(`SELECT `+listCols+` FROM posts
WHERE status = ? ORDER BY published_at DESC`), model.StatusPublished)
if err != nil {
return nil, err
-1
View File
@@ -490,4 +490,3 @@ func TestProjectCRUD(t *testing.T) {
t.Errorf("after delete: got %v, want ErrNotFound", err)
}
}