spark-server/internal/module/group/logic/remove.go
zhr ae9a71034d feat: implement Spark IM V3 modular monolith
Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 19:52:11 +08:00

60 lines
1.7 KiB
Go

package logic
import (
"context"
"spark-server/internal/module/group/entity"
"spark-server/internal/pkg/errs"
"spark-server/internal/pkg/i18n"
"spark-server/internal/pkg/reqctx"
)
func (s *Service) RemoveMember(ctx context.Context, actorID, groupID, targetID int64) error {
if !s.ready() || actorID <= 0 {
return errs.ErrUnauthorized
}
if targetID <= 0 {
return errs.ErrInvalidArgument
}
g, err := s.loadActive(ctx, groupID)
if err != nil {
return err
}
target, err := s.repo.GetMember(ctx, groupID, targetID)
if err != nil {
return err
}
if actorID == targetID {
return s.leave(ctx, g, target)
}
return s.kick(ctx, g, actorID, target)
}
func (s *Service) leave(ctx context.Context, g *entity.Group, self *entity.Member) error {
if self.Role == entity.RoleOwner {
return errs.ErrForbidden.WithMsg(i18n.T(reqctx.Lang(ctx), i18n.KeyGroupOwnerLeave, nil))
}
if err := s.repo.RemoveMember(ctx, g.ID, self.UserID); err != nil {
return err
}
s.invalidateMembers(g.ConversationID)
_ = s.notice(ctx, g, self.UserID, entity.SystemKindLeave, []int64{self.UserID})
return nil
}
func (s *Service) kick(ctx context.Context, g *entity.Group, actorID int64, target *entity.Member) error {
actor, err := s.requireManage(ctx, g.ID, actorID)
if err != nil {
return err
}
if target.Role == entity.RoleOwner || (target.Role == entity.RoleAdmin && actor.Role != entity.RoleOwner) {
return errs.ErrForbidden.WithMsg(i18n.T(reqctx.Lang(ctx), i18n.KeyGroupRoleDenied, nil))
}
if err := s.repo.RemoveMember(ctx, g.ID, target.UserID); err != nil {
return err
}
s.invalidateMembers(g.ConversationID)
_ = s.notice(ctx, g, actorID, entity.SystemKindKick, []int64{target.UserID})
return nil
}