package logic import ( "context" "strings" "spark-server/internal/module/group/entity" "spark-server/internal/pkg/errs" "spark-server/internal/pkg/i18n" "spark-server/internal/pkg/reqctx" "spark-server/internal/pkg/validate" ) type UpdateMemberInput struct { Role *int `json:"role" validate:"omitempty,oneof=2 3" label:"field.role" errmsg:"oneof:validate.group.role_invalid"` SpeakMuted *bool `json:"speak_muted"` Nickname *string `json:"nickname" validate:"omitempty,max=32" label:"field.group_nickname" errmsg:"max:validate.group.nickname_invalid"` } func (s *Service) UpdateMember(ctx context.Context, actorID, groupID, targetID int64, in *UpdateMemberInput) (*MemberView, error) { if !s.ready() || actorID <= 0 { return nil, errs.ErrUnauthorized } if in == nil || targetID <= 0 { return nil, errs.ErrInvalidArgument } if err := validate.StructLang(reqctx.Lang(ctx), in); err != nil { return nil, err } if in.Role == nil && in.SpeakMuted == nil && in.Nickname == nil { return nil, errs.ErrInvalidArgument } g, err := s.loadActive(ctx, groupID) if err != nil { return nil, err } target, err := s.requireMember(ctx, groupID, targetID) if err != nil { return nil, err } if err := s.applyMemberPatch(ctx, g, actorID, target, in); err != nil { return nil, err } if err := s.repo.UpdateMember(ctx, target); err != nil { return nil, err } u, _ := s.users.Get(ctx, target.UserID) return memberViewOf(target, u), nil } func (s *Service) applyMemberPatch(ctx context.Context, g *entity.Group, actorID int64, target *entity.Member, in *UpdateMemberInput) error { lang := reqctx.Lang(ctx) self := actorID == target.UserID if in.Nickname != nil { if !self { if _, err := s.requireManage(ctx, g.ID, actorID); err != nil { return err } } target.Nickname = strings.TrimSpace(*in.Nickname) } if in.Role != nil { if err := s.requireOwner(ctx, g, actorID); err != nil { return err } if self || (*in.Role != entity.RoleAdmin && *in.Role != entity.RoleMember) { return errs.ErrForbidden.WithMsg(i18n.T(lang, i18n.KeyGroupRoleDenied, nil)) } target.Role = *in.Role } if in.SpeakMuted != nil { if _, err := s.requireManage(ctx, g.ID, actorID); err != nil { return err } if target.Role == entity.RoleOwner { return errs.ErrForbidden.WithMsg(i18n.T(lang, i18n.KeyGroupRoleDenied, nil)) } target.SpeakMuted = *in.SpeakMuted } return nil }