- Service 层:energy_service → energize/operations/admin/query 四文件 - Service 层:post_service → helpers/audit + 核心 CRUD 保留 - Service 层:favorite_service → items + 核心文件夹操作保留 - Service 层:auth_service → password + 核心注册/登录保留 - Service 层:notification_service → notify + 核心列表/已读保留 - Service 层:audit_service → review + 核心列表/详情保留 - Controller 层:studio_controller → page/write/api/post_api/action 五文件 - Controller 层:post_controller → page/api/upload 三文件 - Controller 层:comment_controller → list/write/action/upload 四文件 - 清理未使用导入(notification_service.go 移除 fmt)
213 lines
5.8 KiB
Go
213 lines
5.8 KiB
Go
package service
|
||
|
||
import (
|
||
"encoding/json"
|
||
|
||
"metazone.cc/metalab/internal/common"
|
||
"metazone.cc/metalab/internal/model"
|
||
)
|
||
|
||
// ParseNotifyPrefs 解析用户通知偏好 JSON 字符串
|
||
func ParseNotifyPrefs(raw string) map[string]bool {
|
||
prefs := map[string]bool{
|
||
model.NotifyComment: true,
|
||
model.NotifyCommentReply: true,
|
||
model.NotifyLikeAggregated: true,
|
||
model.NotifyFollow: true,
|
||
}
|
||
if raw == "" {
|
||
return prefs
|
||
}
|
||
var parsed map[string]bool
|
||
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
|
||
return prefs
|
||
}
|
||
for k, v := range parsed {
|
||
prefs[k] = v
|
||
}
|
||
return prefs
|
||
}
|
||
|
||
// notifRepo 通知服务所需的最小仓储接口(ISP)
|
||
type notifRepo interface {
|
||
Create(n *model.Notification) error
|
||
ListByUser(userID uint, offset, limit int) ([]model.Notification, error)
|
||
ListByUserAndType(userID uint, notifyType string, offset, limit int) ([]model.Notification, error)
|
||
ListByUserExcludeTypes(userID uint, excludeTypes []string, offset, limit int) ([]model.Notification, error)
|
||
CountByUser(userID uint) (int64, error)
|
||
CountByUserExcludeTypes(userID uint, excludeTypes []string) (int64, error)
|
||
CountByUserAndType(userID uint, notifyType string) (int64, error)
|
||
CountUnread(userID uint) (int64, error)
|
||
CountUnreadExcludeTypes(userID uint, excludeTypes []string) (int64, error)
|
||
CountUnreadByType(userID uint, notifyType string) (int64, error)
|
||
MarkRead(id, userID uint) error
|
||
MarkAllRead(userID uint) error
|
||
GetUnnotifiedDailyLikeSummaries(userID uint) ([]model.DailyLikeSummary, error)
|
||
MarkDailyLikeSummaryNotified(id uint) error
|
||
GetUsernameByID(userID uint) (string, error)
|
||
GetNotifyPrefs(userID uint) (string, error)
|
||
}
|
||
|
||
// NotificationService 消息/通知业务逻辑
|
||
type NotificationService struct {
|
||
repo notifRepo
|
||
}
|
||
|
||
// NewNotificationService 构造函数
|
||
func NewNotificationService(repo notifRepo) *NotificationService {
|
||
return &NotificationService{repo: repo}
|
||
}
|
||
|
||
// Create 创建消息
|
||
func (s *NotificationService) Create(userID uint, notifyType, title, content string, relatedID, commentID *uint) error {
|
||
n := &model.Notification{
|
||
UserID: userID,
|
||
NotifyType: notifyType,
|
||
Title: title,
|
||
Content: content,
|
||
IsRead: false,
|
||
RelatedID: relatedID,
|
||
CommentID: commentID,
|
||
}
|
||
return s.repo.Create(n)
|
||
}
|
||
|
||
// List 分页查询用户消息列表(触发聚合通知检查)
|
||
func (s *NotificationService) List(userID uint, page, pageSize int) (*model.NotificationListResult, error) {
|
||
// 自动触发点赞聚合通知生成
|
||
s.checkAndNotifyAggregation(userID)
|
||
|
||
p := common.Pagination{Page: page, PageSize: pageSize}
|
||
p.DefaultPagination()
|
||
|
||
excludeTypes := s.getDisabledTypes(userID)
|
||
|
||
total, err := s.repo.CountByUserExcludeTypes(userID, excludeTypes)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
items, err := s.repo.ListByUserExcludeTypes(userID, excludeTypes, p.Offset(), p.PageSize)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if items == nil {
|
||
items = []model.Notification{}
|
||
}
|
||
|
||
totalPages := int((total + int64(p.PageSize) - 1) / int64(p.PageSize))
|
||
unread, _ := s.CountUnread(userID)
|
||
|
||
return &model.NotificationListResult{
|
||
Items: items,
|
||
Total: total,
|
||
Page: p.Page,
|
||
TotalPages: totalPages,
|
||
Unread: unread,
|
||
}, nil
|
||
}
|
||
|
||
// ListByCategory 按通知分类分页查询(供消息页分类 TAB 使用)
|
||
func (s *NotificationService) ListByCategory(userID uint, category string, page, pageSize int) (*model.NotificationListResult, error) {
|
||
s.checkAndNotifyAggregation(userID)
|
||
|
||
p := common.Pagination{Page: page, PageSize: pageSize}
|
||
p.DefaultPagination()
|
||
|
||
// 分类→通知类型映射
|
||
notifyTypes := categoryTypes(category)
|
||
var combinedItems []model.Notification
|
||
var total int64
|
||
|
||
for _, nt := range notifyTypes {
|
||
c, _ := s.repo.CountByUserAndType(userID, nt)
|
||
total += c
|
||
}
|
||
|
||
allItems := make([]model.Notification, 0)
|
||
for _, nt := range notifyTypes {
|
||
items, err := s.repo.ListByUserAndType(userID, nt, 0, 10000) // 大 limit,在内存里分页
|
||
if err != nil {
|
||
continue
|
||
}
|
||
allItems = append(allItems, items...)
|
||
}
|
||
|
||
// 按 created_at 降序排序
|
||
sortNotifications(allItems)
|
||
|
||
// 分页
|
||
start := p.Offset()
|
||
end := start + p.PageSize
|
||
if start > len(allItems) {
|
||
start = len(allItems)
|
||
}
|
||
if end > len(allItems) {
|
||
end = len(allItems)
|
||
}
|
||
if start < end {
|
||
combinedItems = allItems[start:end]
|
||
}
|
||
|
||
if combinedItems == nil {
|
||
combinedItems = []model.Notification{}
|
||
}
|
||
|
||
totalPages := int((total + int64(p.PageSize) - 1) / int64(p.PageSize))
|
||
unread, _ := s.CountUnread(userID)
|
||
|
||
return &model.NotificationListResult{
|
||
Items: combinedItems,
|
||
Total: total,
|
||
Page: p.Page,
|
||
TotalPages: totalPages,
|
||
Unread: unread,
|
||
}, nil
|
||
}
|
||
|
||
// CountUnread 统计未读消息数(排除用户禁用的通知类型)
|
||
func (s *NotificationService) CountUnread(userID uint) (int64, error) {
|
||
excludeTypes := s.getDisabledTypes(userID)
|
||
return s.repo.CountUnreadExcludeTypes(userID, excludeTypes)
|
||
}
|
||
|
||
// getDisabledTypes 获取用户禁用的通知类型列表
|
||
func (s *NotificationService) getDisabledTypes(userID uint) []string {
|
||
raw, err := s.repo.GetNotifyPrefs(userID)
|
||
if err != nil || raw == "" {
|
||
return nil
|
||
}
|
||
prefs := ParseNotifyPrefs(raw)
|
||
var disabled []string
|
||
for _, t := range []string{
|
||
model.NotifyComment,
|
||
model.NotifyCommentReply,
|
||
model.NotifyLikeAggregated,
|
||
model.NotifyFollow,
|
||
} {
|
||
if !prefs[t] {
|
||
disabled = append(disabled, t)
|
||
}
|
||
}
|
||
return disabled
|
||
}
|
||
|
||
// MarkRead 标记单条消息为已读
|
||
func (s *NotificationService) MarkRead(id, userID uint) error {
|
||
return s.repo.MarkRead(id, userID)
|
||
}
|
||
|
||
// MarkAllRead 标记所有未读为已读
|
||
func (s *NotificationService) MarkAllRead(userID uint) error {
|
||
return s.repo.MarkAllRead(userID)
|
||
}
|
||
|
||
// getUsername 获取用户名(辅助方法)
|
||
func (s *NotificationService) getUsername(userID uint) string {
|
||
name, err := s.repo.GetUsernameByID(userID)
|
||
if err != nil || name == "" {
|
||
return "一位用户"
|
||
}
|
||
return name
|
||
}
|