211 lines
5.6 KiB
Go
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
|
|
}
|