spark-server/internal/module/seed/logic/welcome.go
DESKTOP-L8OUL9F\gfl0034 ce2cdf6bf3 feat: music 运营曲目、seed 机器人欢迎消息,并补充 novels/music OpenAPI
合并 origin/main 设备注册后,纳入本地 music 模块、seed 命令与 popadmin 相关路由/文档;music migration 编号为 0020 以避免与 0019_devices 冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 16:07:05 +08:00

108 lines
3.3 KiB
Go

package logic
import (
"context"
"errors"
"fmt"
"time"
friendentity "spark-server/internal/module/friend/entity"
msgentity "spark-server/internal/module/message/entity"
userentity "spark-server/internal/module/user/entity"
"spark-server/internal/pkg/errs"
)
const (
welcomeBody = "Welcome to Spark! This is a system welcome message. Explore chats, groups, and sample content anytime."
greetingBody = "Hi! I'm %s — your sample robot friend. Reply anytime; this is an English greeting demo."
)
func (s *Service) onboardUser(ctx context.Context, user, bot *userentity.User) error {
if user == nil || bot == nil || user.ID == bot.ID {
return errs.ErrInvalidArgument
}
if err := s.ensureFriendship(ctx, user.ID, bot.ID); err != nil {
return err
}
convID, err := s.chats.EnsureP2P(ctx, user.ID, bot.ID)
if err != nil {
return err
}
if err := s.ensureSystemWelcome(ctx, user.ID, convID); err != nil {
return err
}
return s.ensureBotGreeting(ctx, user.ID, bot, convID)
}
func (s *Service) ensureFriendship(ctx context.Context, userID, botID int64) error {
rel, err := s.friends.GetRelation(ctx, userID, botID)
if err == nil && rel.Active() {
return nil
}
if err != nil && !errors.Is(err, errs.ErrNotFound) {
return err
}
now := time.Now()
return ignoreDup(s.friends.AcceptFriend(ctx, friendentity.AcceptParams{
Edges: []*friendentity.Relation{
friendentity.NewFriendEdge(userID, botID, "", friendentity.SourceEmail, now),
friendentity.NewFriendEdge(botID, userID, "", friendentity.SourceEmail, now),
},
}))
}
func (s *Service) ensureSystemWelcome(ctx context.Context, userID, convID int64) error {
clientID := fmt.Sprintf("seed:welcome:%d", userID)
msgID, err := s.ids.NextID()
if err != nil {
return err
}
raw, err := msgentity.NewSystem(&msgentity.System{
Kind: userentity.SystemKindWelcome, Body: welcomeBody,
}).Marshal()
if err != nil {
return err
}
now := time.Now().UnixMilli()
msg := &msgentity.Message{
ID: msgID, ConversationID: convID, SenderID: 0, ReceiverID: userID,
ClientMsgID: clientID, Type: msgentity.TypeSystem, Kind: msgentity.KindPrivate,
Content: raw, Status: msgentity.StatusNormal, CreatedAtMS: now,
}
if err := s.msgs.Create(ctx, msg); err != nil {
if errors.Is(err, errs.ErrDuplicate) {
return nil
}
return err
}
return s.chats.UpdateLastMsg(ctx, convID, msgID, now)
}
func (s *Service) ensureBotGreeting(ctx context.Context, userID int64, bot *userentity.User, convID int64) error {
clientID := fmt.Sprintf("seed:greet:%d", userID)
if _, err := s.msgs.GetByClientMsgID(ctx, bot.ID, convID, clientID); err == nil {
return nil
} else if err != nil && !errors.Is(err, errs.ErrNotFound) {
return err
}
msgID, err := s.ids.NextID()
if err != nil {
return err
}
body := fmt.Sprintf(greetingBody, bot.Nickname)
raw, err := msgentity.NewText(body).Marshal()
if err != nil {
return err
}
now := time.Now().UnixMilli()
msg := &msgentity.Message{
ID: msgID, ConversationID: convID, SenderID: bot.ID, ReceiverID: userID,
ClientMsgID: clientID, Type: msgentity.TypeText, Kind: msgentity.KindPrivate,
Content: raw, Status: msgentity.StatusNormal, CreatedAtMS: now,
}
if err := ignoreDup(s.msgs.Create(ctx, msg)); err != nil {
return err
}
return s.chats.UpdateLastMsg(ctx, convID, msgID, now)
}