feat(api): add message segments support for posts and comments
Add rich message segment support enabling structured content (text, images, votes, mentions) in posts and comments. Includes segments field in models, DTOs, handlers, and services. Also adds @mention notification processing and migrates vote data to embedded segments.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package service
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"with_you/internal/cache"
|
||||
"with_you/internal/dto"
|
||||
"with_you/internal/model"
|
||||
"with_you/internal/pkg/cursor"
|
||||
"with_you/internal/pkg/hook"
|
||||
@@ -25,7 +26,7 @@ const (
|
||||
// PostService 帖子服务接口
|
||||
type PostService interface {
|
||||
// 帖子CRUD
|
||||
Create(ctx context.Context, userID, title, content string, images []string, channelID *string) (*model.Post, error)
|
||||
Create(ctx context.Context, userID, title, content string, segments model.MessageSegments, images []string, channelID *string) (*model.Post, error)
|
||||
GetByID(ctx context.Context, id string) (*model.Post, error)
|
||||
Update(ctx context.Context, post *model.Post) error
|
||||
UpdateWithImages(ctx context.Context, post *model.Post, images *[]string) error
|
||||
@@ -98,13 +99,27 @@ type PostListResult struct {
|
||||
}
|
||||
|
||||
// Create 创建帖子
|
||||
func (s *postServiceImpl) Create(ctx context.Context, userID, title, content string, images []string, channelID *string) (*model.Post, error) {
|
||||
func (s *postServiceImpl) Create(ctx context.Context, userID, title, content string, segments model.MessageSegments, images []string, channelID *string) (*model.Post, error) {
|
||||
// 如果没有提供 content 但有 segments,从 segments 提取文本摘要
|
||||
if content == "" && len(segments) > 0 {
|
||||
content = dto.ExtractTextContent(segments)
|
||||
}
|
||||
// 如果有 segments 但 content 为空,将 content 设为空字符串(NOT NULL 约束)
|
||||
if content == "" {
|
||||
content = " "
|
||||
}
|
||||
|
||||
// 检查 segments 中是否包含投票
|
||||
isVote := dto.HasVoteSegment(segments)
|
||||
|
||||
post := &model.Post{
|
||||
UserID: userID,
|
||||
ChannelID: channelID,
|
||||
Title: title,
|
||||
Content: content,
|
||||
Segments: segments,
|
||||
Status: model.PostStatusPending,
|
||||
IsVote: isVote,
|
||||
}
|
||||
|
||||
err := s.postRepo.Create(post, images)
|
||||
@@ -127,6 +142,12 @@ func (s *postServiceImpl) Create(ctx context.Context, userID, title, content str
|
||||
// 失效帖子列表缓存
|
||||
cache.InvalidatePostList(s.cache)
|
||||
|
||||
// 异步处理 @提及通知
|
||||
if len(segments) > 0 {
|
||||
bgCtx := context.WithoutCancel(ctx)
|
||||
go s.processMentionNotifications(bgCtx, userID, post.ID, post.Title, segments)
|
||||
}
|
||||
|
||||
// 异步执行审核流
|
||||
go s.reviewPostAsync(post.ID, userID, title, content, images)
|
||||
|
||||
@@ -246,6 +267,27 @@ func (s *postServiceImpl) notifyModerationRejected(userID, reason string) {
|
||||
}()
|
||||
}
|
||||
|
||||
// processMentionNotifications 处理帖子中 @提及的通知
|
||||
func (s *postServiceImpl) processMentionNotifications(ctx context.Context, authorID, postID, postTitle string, segments model.MessageSegments) {
|
||||
if s.systemMessageService == nil {
|
||||
return
|
||||
}
|
||||
|
||||
mentionedUserIDs := dto.ExtractMentionedUsers(segments)
|
||||
if len(mentionedUserIDs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, targetUserID := range mentionedUserIDs {
|
||||
if targetUserID == authorID {
|
||||
continue
|
||||
}
|
||||
if err := s.systemMessageService.SendMentionNotification(ctx, targetUserID, authorID, postID); err != nil {
|
||||
log.Printf("[WARN] Failed to send mention notification to user %s: %v", targetUserID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取帖子
|
||||
func (s *postServiceImpl) GetByID(ctx context.Context, id string) (*model.Post, error) {
|
||||
return s.postRepo.GetByID(id)
|
||||
|
||||
Reference in New Issue
Block a user