542 lines
19 KiB
Go
542 lines
19 KiB
Go
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"`
|
||
CommentsRequireLogin *bool `json:"comments_require_login"`
|
||
AllowMessages *bool `json:"allow_messages"`
|
||
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"`
|
||
AttachmentExtLimit *bool `json:"attachment_ext_limit"`
|
||
AttachmentExts *[]string `json:"attachment_exts"`
|
||
AttachmentMaxMB *int `json:"attachment_max_mb"`
|
||
AttachmentMaxCount *int `json:"attachment_max_count"`
|
||
ImageMaxMB *int `json:"image_max_mb"`
|
||
BgSiteURL *string `json:"bg_site_url"`
|
||
BgSiteMode *string `json:"bg_site_mode"`
|
||
BgAdminURL *string `json:"bg_admin_url"`
|
||
BgAdminMode *string `json:"bg_admin_mode"`
|
||
SiteWordmark *string `json:"site_wordmark"`
|
||
SiteSlogan *string `json:"site_slogan"`
|
||
SiteKeywords *[]string `json:"site_keywords"`
|
||
LogoLightURL *string `json:"logo_light_url"`
|
||
LogoDarkURL *string `json:"logo_dark_url"`
|
||
FaviconURL *string `json:"favicon_url"`
|
||
BrandMark *string `json:"brand_mark"`
|
||
BrandLogoSize *string `json:"brand_logo_size"`
|
||
BrandLogoFit *string `json:"brand_logo_fit"`
|
||
FooterLinks *[]service.FooterLink `json:"footer_links"`
|
||
}
|
||
|
||
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,
|
||
"comments_require_login": saved.CommentsRequireLogin,
|
||
"allow_messages": saved.AllowMessages,
|
||
"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,
|
||
"attachment_ext_limit": saved.AttachmentExtLimit,
|
||
"attachment_exts": saved.AttachmentExts,
|
||
"attachment_max_mb": saved.AttachmentMaxMB,
|
||
"attachment_max_count": saved.AttachmentMaxCount,
|
||
"image_max_mb": saved.ImageMaxMB,
|
||
"bg_site_url": saved.BgSiteURL,
|
||
"bg_site_mode": saved.BgSiteMode,
|
||
"bg_admin_url": saved.BgAdminURL,
|
||
"bg_admin_mode": saved.BgAdminMode,
|
||
"site_wordmark": saved.SiteWordmark,
|
||
"site_slogan": saved.SiteSlogan,
|
||
"site_keywords": saved.SiteKeywords,
|
||
"logo_light_url": saved.LogoLightURL,
|
||
"logo_dark_url": saved.LogoDarkURL,
|
||
"favicon_url": saved.FaviconURL,
|
||
"brand_mark": saved.BrandMark,
|
||
"brand_logo_size": saved.BrandLogoSize,
|
||
"brand_logo_fit": saved.BrandLogoFit,
|
||
"footer_links": saved.FooterLinks,
|
||
}
|
||
}
|
||
|
||
func (req *updateSettingsRequest) hasAny() bool {
|
||
return req.Accent != nil || req.TrustReviewedPublish != nil || req.SiteName != nil ||
|
||
req.SiteDescription != nil || req.AllowRegister != nil || req.AllowComments != nil ||
|
||
req.CommentsRequireLogin != nil || req.AllowMessages != 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 ||
|
||
req.AttachmentExtLimit != nil || req.AttachmentExts != nil || req.AttachmentMaxMB != nil ||
|
||
req.AttachmentMaxCount != nil || req.ImageMaxMB != nil ||
|
||
req.BgSiteURL != nil || req.BgSiteMode != nil ||
|
||
req.BgAdminURL != nil || req.BgAdminMode != nil ||
|
||
req.SiteWordmark != nil || req.SiteSlogan != nil || req.SiteKeywords != nil ||
|
||
req.LogoLightURL != nil || req.LogoDarkURL != nil || req.FaviconURL != nil ||
|
||
req.BrandMark != nil || req.BrandLogoSize != nil || req.BrandLogoFit != nil ||
|
||
req.FooterLinks != nil
|
||
}
|
||
|
||
// AdminGetSettings 超管读取站点设置(与公开 payload 字段一致)
|
||
func (h *Handlers) AdminGetSettings(c *gin.Context) {
|
||
saved, err := h.Setting.Public()
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取站点设置失败"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, settingsPayload(saved))
|
||
}
|
||
|
||
// 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.hasAny() {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "未提供任何可更新的设置项"})
|
||
return
|
||
}
|
||
|
||
if req.AllowRegister != nil || req.AttachmentExtLimit != nil || req.AttachmentExts != nil || req.AttachmentMaxMB != nil || req.AttachmentMaxCount != nil || req.ImageMaxMB != nil {
|
||
c.JSON(400, 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.CommentsRequireLogin != nil {
|
||
if err := h.Setting.SetCommentsRequireLogin(*req.CommentsRequireLogin); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.AllowMessages != nil {
|
||
if err := h.Setting.SetAllowMessages(*req.AllowMessages); 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
|
||
}
|
||
}
|
||
if req.AttachmentExtLimit != nil {
|
||
if err := h.Setting.SetAttachmentExtLimit(*req.AttachmentExtLimit); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.AttachmentExts != nil {
|
||
if err := h.Setting.SetAttachmentExts(*req.AttachmentExts); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "扩展名无效或数量超限(最多 80 个,仅字母数字)"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.AttachmentMaxMB != nil {
|
||
if err := h.Setting.SetAttachmentMaxMB(*req.AttachmentMaxMB); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "附件上限须至少 1MB"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.AttachmentMaxCount != nil {
|
||
if err := h.Setting.SetAttachmentMaxCount(*req.AttachmentMaxCount); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "每帖附件数须为 1–20"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.ImageMaxMB != nil {
|
||
if err := h.Setting.SetImageMaxMB(*req.ImageMaxMB); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "插图上限须至少 1MB"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.BgSiteURL != nil {
|
||
if err := h.applyBgURL(service.BgSurfaceSite, *req.BgSiteURL); err != nil {
|
||
writeBgSettingError(c, err)
|
||
return
|
||
}
|
||
}
|
||
if req.BgAdminURL != nil {
|
||
if err := h.applyBgURL(service.BgSurfaceAdmin, *req.BgAdminURL); err != nil {
|
||
writeBgSettingError(c, err)
|
||
return
|
||
}
|
||
}
|
||
if req.BgSiteMode != nil {
|
||
if err := h.Setting.SetBgSiteMode(*req.BgSiteMode); 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.BgAdminMode != nil {
|
||
if err := h.Setting.SetBgAdminMode(*req.BgAdminMode); 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.SiteWordmark != nil {
|
||
if err := h.Setting.SetSiteWordmark(*req.SiteWordmark); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "字标过长(最多 16 字)"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.SiteSlogan != nil {
|
||
if err := h.Setting.SetSiteSlogan(*req.SiteSlogan); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "标语过长(最多 32 字)"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.SiteKeywords != nil {
|
||
if err := h.Setting.SetSiteKeywords(*req.SiteKeywords); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "关键词过多或单个过长(最多 16 个,每个 20 字)"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
return
|
||
}
|
||
}
|
||
if req.LogoLightURL != nil {
|
||
if err := h.applyBrandURL(service.BrandSlotLight, *req.LogoLightURL); err != nil {
|
||
writeBrandSettingError(c, err)
|
||
return
|
||
}
|
||
}
|
||
if req.LogoDarkURL != nil {
|
||
if err := h.applyBrandURL(service.BrandSlotDark, *req.LogoDarkURL); err != nil {
|
||
writeBrandSettingError(c, err)
|
||
return
|
||
}
|
||
}
|
||
if req.FaviconURL != nil {
|
||
if err := h.applyBrandURL(service.BrandSlotFavicon, *req.FaviconURL); err != nil {
|
||
writeBrandSettingError(c, err)
|
||
return
|
||
}
|
||
}
|
||
if req.BrandMark != nil {
|
||
if err := h.Setting.SetBrandMark(*req.BrandMark); 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.BrandLogoFit != nil {
|
||
if err := h.Setting.SetBrandLogoFit(*req.BrandLogoFit); 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.BrandLogoSize != nil {
|
||
if err := h.Setting.SetBrandLogoSize(*req.BrandLogoSize); 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.FooterLinks != nil {
|
||
if err := h.Setting.SetFooterLinks(*req.FooterLinks); err != nil {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "页脚链接无效(最多 8 条,文案 32 字,地址须为站内路径或 http(s))"})
|
||
return
|
||
}
|
||
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)
|
||
}
|
||
|
||
func writeBgSettingError(c *gin.Context, err error) {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "背景图地址无效"})
|
||
return
|
||
}
|
||
if errors.Is(err, service.ErrBgFileMissing) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
}
|
||
|
||
// applyBgURL 写入对应轨的背景 URL,并删除不再被引用的旧文件
|
||
func (h *Handlers) applyBgURL(surface, url string) error {
|
||
u, ok := service.NormalizeBgURL(url)
|
||
if !ok {
|
||
return service.ErrInvalidSiteSetting
|
||
}
|
||
if u != "" && !h.Upload.BackgroundFileExists(u) {
|
||
return service.ErrBgFileMissing
|
||
}
|
||
oldSite, err := h.Setting.BgSiteURL()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
oldAdmin, err := h.Setting.BgAdminURL()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if surface == service.BgSurfaceAdmin {
|
||
if err := h.Setting.SetBgAdminURL(u); err != nil {
|
||
return err
|
||
}
|
||
h.Upload.RemoveBackgroundIfUnused(oldAdmin, oldSite, u)
|
||
return nil
|
||
}
|
||
if err := h.Setting.SetBgSiteURL(u); err != nil {
|
||
return err
|
||
}
|
||
h.Upload.RemoveBackgroundIfUnused(oldSite, u, oldAdmin)
|
||
return nil
|
||
}
|
||
|
||
func writeBrandSettingError(c *gin.Context, err error) {
|
||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "品牌图地址无效"})
|
||
return
|
||
}
|
||
if errors.Is(err, service.ErrBrandFileMissing) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||
}
|
||
|
||
// applyBrandURL 写入对应槽位,并删除不再被引用的旧文件
|
||
func (h *Handlers) applyBrandURL(slot, url string) error {
|
||
u, ok := service.NormalizeBrandURL(slot, url)
|
||
if !ok {
|
||
return service.ErrInvalidSiteSetting
|
||
}
|
||
if u != "" && !h.Upload.BrandFileExists(u) {
|
||
return service.ErrBrandFileMissing
|
||
}
|
||
oldLight, err := h.Setting.LogoLightURL()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
oldDark, err := h.Setting.LogoDarkURL()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
oldFav, err := h.Setting.FaviconURL()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
var old string
|
||
switch slot {
|
||
case service.BrandSlotDark:
|
||
old = oldDark
|
||
if err := h.Setting.SetLogoDarkURL(u); err != nil {
|
||
return err
|
||
}
|
||
oldDark = u
|
||
case service.BrandSlotFavicon:
|
||
old = oldFav
|
||
if err := h.Setting.SetFaviconURL(u); err != nil {
|
||
return err
|
||
}
|
||
oldFav = u
|
||
default:
|
||
old = oldLight
|
||
if err := h.Setting.SetLogoLightURL(u); err != nil {
|
||
return err
|
||
}
|
||
oldLight = u
|
||
}
|
||
h.Upload.RemoveBrandIfUnused(old, oldLight, oldDark, oldFav)
|
||
return nil
|
||
}
|