- 新增收藏夹系统 (Folder/FolderItem 模型、CRUD API、前端管理页) - 新增文章详情页收藏按钮 (书签图标、ToggleFavorite 一键收藏) - 新增 Studio 趋势图 (赋能值/评论/点赞/收藏 4 线图, 7d/30d/90d) - 新增通知偏好设置页 (评论/回复/点赞/关注 4 类开关) - 后端通知列表支持按偏好过滤 (排除已关闭的通知类型) - 下载 Chart.js 到本地静态资源 (static/js/chart.umd.min.js) - 补充收藏夹卡片、开关滑块、趋势图网格等 CSS 样式
86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
package controller
|
||
|
||
import (
|
||
"net/http"
|
||
|
||
"metazone.cc/metalab/internal/common"
|
||
"metazone.cc/metalab/internal/model"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// notifyPrefReader 通知偏好读写的接口(ISP)
|
||
type notifyPrefReader interface {
|
||
GetNotifyPrefs(userID uint) (map[string]bool, error)
|
||
UpdateNotifyPref(userID uint, key string, enabled bool) error
|
||
}
|
||
|
||
// SetNotifyPrefReader 注入通知偏好读写器
|
||
func (sc *SettingsController) SetNotifyPrefReader(reader notifyPrefReader) {
|
||
sc.notifyPrefReader = reader
|
||
}
|
||
|
||
// GetNotifyPrefs 获取通知偏好 GET /api/settings/notify-prefs
|
||
func (sc *SettingsController) GetNotifyPrefs(c *gin.Context) {
|
||
uid, exists := c.Get("uid")
|
||
if !exists {
|
||
common.Error(c, http.StatusUnauthorized, "请先登录")
|
||
return
|
||
}
|
||
|
||
if sc.notifyPrefReader == nil {
|
||
common.Error(c, http.StatusInternalServerError, "服务不可用")
|
||
return
|
||
}
|
||
|
||
prefs, err := sc.notifyPrefReader.GetNotifyPrefs(uid.(uint))
|
||
if err != nil {
|
||
common.Error(c, http.StatusInternalServerError, "获取失败")
|
||
return
|
||
}
|
||
|
||
common.Ok(c, prefs)
|
||
}
|
||
|
||
// UpdateNotifyPref 更新通知偏好 PUT /api/settings/notify-prefs
|
||
func (sc *SettingsController) UpdateNotifyPref(c *gin.Context) {
|
||
uid, exists := c.Get("uid")
|
||
if !exists {
|
||
common.Error(c, http.StatusUnauthorized, "请先登录")
|
||
return
|
||
}
|
||
|
||
if sc.notifyPrefReader == nil {
|
||
common.Error(c, http.StatusInternalServerError, "服务不可用")
|
||
return
|
||
}
|
||
|
||
var req struct {
|
||
Key string `json:"key"`
|
||
Enabled bool `json:"enabled"`
|
||
}
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
common.Error(c, http.StatusBadRequest, "参数错误")
|
||
return
|
||
}
|
||
|
||
// 验证 key 是否合法
|
||
allowedKeys := map[string]bool{
|
||
model.NotifyComment: true,
|
||
model.NotifyCommentReply: true,
|
||
model.NotifyLikeAggregated: true,
|
||
model.NotifyFollow: true,
|
||
}
|
||
if !allowedKeys[req.Key] {
|
||
common.Error(c, http.StatusBadRequest, "无效的通知类型")
|
||
return
|
||
}
|
||
|
||
if err := sc.notifyPrefReader.UpdateNotifyPref(uid.(uint), req.Key, req.Enabled); err != nil {
|
||
common.Error(c, http.StatusInternalServerError, "更新失败")
|
||
return
|
||
}
|
||
|
||
common.OkMessage(c, "通知偏好已更新")
|
||
}
|