合并 origin/main 设备注册后,纳入本地 music 模块、seed 命令与 popadmin 相关路由/文档;music migration 编号为 0020 以避免与 0019_devices 冲突。 Co-authored-by: Cursor <cursoragent@cursor.com>
108 lines
3.3 KiB
Go
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)
|
|
}
|