spark-server/internal/module/group/model/write.go
2026-09-18 14:50:41 +08:00

211 lines
5.6 KiB
Go

package model
import (
"context"
"time"
"gorm.io/gorm"
conventity "spark-server/internal/module/conversation/entity"
convmodel "spark-server/internal/module/conversation/model"
"spark-server/internal/module/group/entity"
"spark-server/internal/pkg/errs"
)
func (m *Repo) CreateGroup(ctx context.Context, g *entity.Group, members []*entity.Member) error {
if g == nil || g.ConversationID <= 0 || len(members) == 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
now := msTime(g.CreatedAtMS)
return db.Transaction(func(tx *gorm.DB) error {
conv := convmodel.Conversation{
ID: g.ConversationID, Type: int(conventity.TypeGroup), LastMsgAt: now, CreatedAt: now,
}
if err := tx.Create(&conv).Error; err != nil {
return mapDBErr(err)
}
g.ID = 0
g.MemberCount = len(members)
row := groupRow(g)
if err := tx.Create(row).Error; err != nil {
return mapDBErr(err)
}
g.ID = row.ID
for _, mem := range members {
if mem == nil {
continue
}
mem.GroupID = g.ID
if err := insertMember(tx, mem, g.ConversationID, now); err != nil {
return err
}
}
return nil
})
}
func (m *Repo) AddMembers(ctx context.Context, groupID int64, members []*entity.Member) error {
if groupID <= 0 || len(members) == 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
now := time.Now()
return db.Transaction(func(tx *gorm.DB) error {
g, err := takeActiveGroup(tx, groupID)
if err != nil {
return err
}
for _, mem := range members {
if mem == nil {
continue
}
mem.GroupID = groupID
if err := insertMember(tx, mem, g.ConversationID, now); err != nil {
return err
}
}
return bumpMemberCount(tx, groupID, len(members), now)
})
}
func (m *Repo) RemoveMember(ctx context.Context, groupID, userID int64) error {
if groupID <= 0 || userID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
now := time.Now()
return db.Transaction(func(tx *gorm.DB) error {
g, err := takeActiveGroup(tx, groupID)
if err != nil {
return err
}
res := tx.Where("group_id = ? AND user_id = ?", groupID, userID).Delete(&GroupMember{})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
if err := tx.Where("conversation_id = ? AND user_id = ?", g.ConversationID, userID).
Delete(&convmodel.ConversationMember{}).Error; err != nil {
return mapDBErr(err)
}
return bumpMemberCount(tx, groupID, -1, now)
})
}
func (m *Repo) Dissolve(ctx context.Context, groupID int64) error {
if groupID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
now := time.Now()
return db.Transaction(func(tx *gorm.DB) error {
g, err := takeActiveGroup(tx, groupID)
if err != nil {
return err
}
res := tx.Model(&Group{}).Where("id = ? AND status = ?", groupID, entity.StatusActive).Updates(map[string]any{
"status": entity.StatusDissolved,
"member_count": 0,
"updated_at": now,
})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
if err := tx.Where("group_id = ?", groupID).Delete(&GroupMember{}).Error; err != nil {
return mapDBErr(err)
}
if err := tx.Where("conversation_id = ?", g.ConversationID).Delete(&convmodel.ConversationMember{}).Error; err != nil {
return mapDBErr(err)
}
return nil
})
}
func (m *Repo) TransferOwner(ctx context.Context, groupID, fromID, toID int64) error {
if groupID <= 0 || fromID <= 0 || toID <= 0 || fromID == toID {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
now := time.Now()
return db.Transaction(func(tx *gorm.DB) error {
res := tx.Model(&Group{}).Where("id = ? AND owner_id = ? AND status = ?", groupID, fromID, entity.StatusActive).
Updates(map[string]any{"owner_id": toID, "updated_at": now})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
if err := tx.Model(&GroupMember{}).Where("group_id = ? AND user_id = ?", groupID, fromID).
Update("role", entity.RoleMember).Error; err != nil {
return mapDBErr(err)
}
res = tx.Model(&GroupMember{}).Where("group_id = ? AND user_id = ?", groupID, toID).
Updates(map[string]any{"role": entity.RoleOwner, "speak_muted": 0})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
return nil
})
}
func takeActiveGroup(tx *gorm.DB, groupID int64) (*Group, error) {
var row Group
if err := tx.Where("id = ? AND status = ?", groupID, entity.StatusActive).Take(&row).Error; err != nil {
return nil, mapDBErr(err)
}
return &row, nil
}
func insertMember(tx *gorm.DB, mem *entity.Member, conversationID int64, now time.Time) error {
if mem.JoinedAtMS <= 0 {
mem.JoinedAtMS = now.UnixMilli()
}
if err := tx.Create(memberRow(mem)).Error; err != nil {
return mapDBErr(err)
}
row := convmodel.ConversationMember{
ConversationID: conversationID, UserID: mem.UserID, JoinedAt: msTime(mem.JoinedAtMS),
}
return mapDBErr(tx.Create(&row).Error)
}
func bumpMemberCount(tx *gorm.DB, groupID int64, delta int, now time.Time) error {
res := tx.Model(&Group{}).Where("id = ? AND status = ?", groupID, entity.StatusActive).
Updates(map[string]any{
"member_count": gorm.Expr("member_count + ?", delta),
"updated_at": now,
})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
return nil
}