package handler import ( "errors" "net/http" "github.com/freefire/jiang13-bbs/realtime" "github.com/freefire/jiang13-bbs/service" "github.com/gin-gonic/gin" ) // GET /api/settings func (h *Handlers) PublicSettings(c *gin.Context) { s, err := h.Setting.Public() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取站点设置失败"}) return } c.JSON(http.StatusOK, s) } // updateSettingsRequest 字段均为可选指针:只更新请求里出现的项,避免外观页覆盖其它设置 type updateSettingsRequest struct { Accent *string `json:"accent"` TrustReviewedPublish *bool `json:"trust_reviewed_publish"` SiteName *string `json:"site_name"` SiteDescription *string `json:"site_description"` AllowRegister *bool `json:"allow_register"` AllowComments *bool `json:"allow_comments"` PostCooldownHours *int `json:"post_cooldown_hours"` CodeBlockAutoFold *bool `json:"code_block_auto_fold"` CodeBlockFoldLines *int `json:"code_block_fold_lines"` UIAnimations *bool `json:"ui_animations"` AnimCodeFold *bool `json:"anim_code_fold"` AnimSmoothScroll *bool `json:"anim_smooth_scroll"` AnimChrome *bool `json:"anim_chrome"` PostLinkNewTab *bool `json:"post_link_new_tab"` } func settingsPayload(saved service.PublicSiteSettings) gin.H { return gin.H{ "accent": saved.Accent, "trust_reviewed_publish": saved.TrustReviewedPublish, "site_name": saved.SiteName, "site_description": saved.SiteDescription, "allow_register": saved.AllowRegister, "allow_comments": saved.AllowComments, "post_cooldown_hours": saved.PostCooldownHours, "code_block_auto_fold": saved.CodeBlockAutoFold, "code_block_fold_lines": saved.CodeBlockFoldLines, "ui_animations": saved.UIAnimations, "anim_code_fold": saved.AnimCodeFold, "anim_smooth_scroll": saved.AnimSmoothScroll, "anim_chrome": saved.AnimChrome, "post_link_new_tab": saved.PostLinkNewTab, } } // PUT /api/admin/settings func (h *Handlers) UpdateSettings(c *gin.Context) { var req updateSettingsRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"}) return } if req.Accent == nil && req.TrustReviewedPublish == nil && req.SiteName == nil && req.SiteDescription == nil && req.AllowRegister == nil && req.AllowComments == nil && req.PostCooldownHours == nil && req.CodeBlockAutoFold == nil && req.CodeBlockFoldLines == nil && req.UIAnimations == nil && req.AnimCodeFold == nil && req.AnimSmoothScroll == nil && req.AnimChrome == nil && req.PostLinkNewTab == nil { c.JSON(http.StatusBadRequest, gin.H{"error": "未提供任何可更新的设置项"}) return } if req.Accent != nil { if err := h.Setting.SetAccent(*req.Accent); err != nil { if errors.Is(err, service.ErrInvalidAccent) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.TrustReviewedPublish != nil { if err := h.Setting.SetTrustReviewedPublish(*req.TrustReviewedPublish); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.SiteName != nil { if err := h.Setting.SetSiteName(*req.SiteName); err != nil { if errors.Is(err, service.ErrInvalidSiteSetting) { c.JSON(http.StatusBadRequest, gin.H{"error": "站点名称过长或无效"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.SiteDescription != nil { if err := h.Setting.SetSiteDescription(*req.SiteDescription); err != nil { if errors.Is(err, service.ErrInvalidSiteSetting) { c.JSON(http.StatusBadRequest, gin.H{"error": "站点简介过长"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.AllowRegister != nil { if err := h.Setting.SetAllowRegister(*req.AllowRegister); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.AllowComments != nil { if err := h.Setting.SetAllowComments(*req.AllowComments); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.PostCooldownHours != nil { if err := h.Setting.SetPostCooldownHours(*req.PostCooldownHours); err != nil { if errors.Is(err, service.ErrInvalidSiteSetting) { c.JSON(http.StatusBadRequest, gin.H{"error": "冷静期须为 0–168 小时"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.CodeBlockAutoFold != nil { if err := h.Setting.SetCodeBlockAutoFold(*req.CodeBlockAutoFold); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.CodeBlockFoldLines != nil { if err := h.Setting.SetCodeBlockFoldLines(*req.CodeBlockFoldLines); err != nil { if errors.Is(err, service.ErrInvalidSiteSetting) { c.JSON(http.StatusBadRequest, gin.H{"error": "折叠行数须为 0–100"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.UIAnimations != nil { if err := h.Setting.SetUIAnimations(*req.UIAnimations); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.AnimCodeFold != nil { if err := h.Setting.SetAnimCodeFold(*req.AnimCodeFold); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.AnimSmoothScroll != nil { if err := h.Setting.SetAnimSmoothScroll(*req.AnimSmoothScroll); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.AnimChrome != nil { if err := h.Setting.SetAnimChrome(*req.AnimChrome); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } if req.PostLinkNewTab != nil { if err := h.Setting.SetPostLinkNewTab(*req.PostLinkNewTab); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"}) return } } saved, err := h.Setting.Public() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取站点设置失败"}) return } payload := settingsPayload(saved) h.Hub.BroadcastAll(realtime.Envelope{ Type: realtime.EventSettingsChanged, Data: payload, }) out := settingsPayload(saved) out["ok"] = true c.JSON(http.StatusOK, out) }