spark-server/internal/module/moment/logic/notice.go
2026-09-18 17:51:42 +08:00

133 lines
3.4 KiB
Go

package logic
import (
"context"
"time"
"spark-server/internal/module/moment/entity"
"spark-server/internal/pkg/errs"
)
type NoticeView struct {
ID int64 `json:"id"`
Kind entity.NoticeKind `json:"kind"`
From UserCard `json:"from"`
PostID int64 `json:"post_id"`
CommentID int64 `json:"comment_id,omitempty"`
Read bool `json:"read"`
CreatedAt int64 `json:"created_at"`
}
type NoticeList struct {
Items []*NoticeView `json:"items"`
NextCursor int64 `json:"next_cursor"`
}
type Unread struct {
HasNew bool `json:"has_new"`
LatestID int64 `json:"latest_id"`
}
type ReadInput struct {
PostID int64 `json:"post_id" validate:"required,gt=0" label:"field.moment_id"`
}
type NoticeReadInput struct {
Cursor int64 `json:"cursor" validate:"omitempty,gte=0" label:"field.moment_cursor"`
}
func (s *Service) ListNotices(ctx context.Context, userID, cursor int64, limit int) (*NoticeList, error) {
if !s.ready() || userID <= 0 {
return nil, errs.ErrUnauthorized
}
limit = entity.ClampLimit(limit)
rows, err := s.repo.ListNotices(ctx, userID, cursor, limit)
if err != nil {
return nil, err
}
uids := make([]int64, 0, len(rows))
for _, n := range rows {
uids = append(uids, n.FromUserID)
}
users := s.loadUsers(ctx, uids)
remarks := s.loadRemarks(ctx, userID, uids)
items := make([]*NoticeView, 0, len(rows))
next := int64(0)
for _, n := range rows {
items = append(items, &NoticeView{
ID: n.ID, Kind: n.Kind, From: cardOf(users[n.FromUserID], remarks[n.FromUserID]),
PostID: n.PostID, CommentID: n.CommentID, Read: n.ReadAtMS > 0, CreatedAt: n.CreatedAtMS,
})
next = n.ID
}
return &NoticeList{Items: items, NextCursor: next}, nil
}
func (s *Service) ReadNotices(ctx context.Context, userID int64, in *NoticeReadInput) error {
if !s.ready() || userID <= 0 {
return errs.ErrUnauthorized
}
cursor := int64(0)
if in != nil {
cursor = in.Cursor
}
return s.repo.MarkNoticesRead(ctx, userID, cursor)
}
func (s *Service) UnreadFeed(ctx context.Context, userID int64) (*Unread, error) {
if !s.ready() || userID <= 0 {
return nil, errs.ErrUnauthorized
}
st, err := s.repo.GetSettings(ctx, userID)
if err != nil {
return nil, err
}
feed, err := s.Feed(ctx, userID, 0, 1)
if err != nil {
return nil, err
}
latest := int64(0)
for _, item := range feed.Items {
if item != nil && item.User.UID != userID {
latest = item.ID
break
}
}
return &Unread{HasNew: latest > st.LastReadPostID, LatestID: latest}, nil
}
func (s *Service) MarkFeedRead(ctx context.Context, userID, postID int64) error {
if !s.ready() || userID <= 0 {
return errs.ErrUnauthorized
}
if postID <= 0 {
return errs.ErrInvalidArgument
}
return s.repo.AdvanceRead(ctx, userID, postID)
}
func (s *Service) notify(ctx context.Context, rows []*entity.Notice) error {
out := make([]*entity.Notice, 0, len(rows))
now := time.Now().UnixMilli()
for _, n := range rows {
if n == nil || n.ToUserID <= 0 || n.ToUserID == n.FromUserID {
continue
}
id, err := s.ids.NextID()
if err != nil {
return err
}
n.ID = id
n.CreatedAtMS = now
out = append(out, n)
}
return s.repo.CreateNotices(ctx, out)
}
func (s *Service) newNotice(to, from int64, kind entity.NoticeKind, postID, commentID int64) *entity.Notice {
if to <= 0 || to == from {
return nil
}
return &entity.Notice{ToUserID: to, FromUserID: from, Kind: kind, PostID: postID, CommentID: commentID}
}