package logic import ( "context" "time" "spark-server/internal/module/user/entity" "spark-server/internal/pkg/errs" ) // AccountModeration is implemented by user persistence for send gates and bans. type AccountModeration interface { SetUserStatus(ctx context.Context, userID int64, status entity.Status) error ExtendSendMutedUntil(ctx context.Context, userID int64, until time.Time) error } type BannedKicker interface { KickUserBanned(userID int64) } // AssertCanSend is the AccountGate for message send (all content types). func (s *Service) AssertCanSend(ctx context.Context, userID int64) error { if !s.ready() || userID <= 0 { return errs.ErrUnauthorized } u, err := s.repo.GetByID(ctx, userID) if err != nil { return err } if u.Status != entity.StatusActive { return errs.ErrForbidden } if !u.SendMutedUntil.IsZero() && u.SendMutedUntil.After(time.Now()) { return errs.ErrSendMuted } return nil } // ExtendSendMutedUntil implements moderation.UserModeration. func (s *Service) ExtendSendMutedUntil(ctx context.Context, userID int64, until time.Time) error { mod, ok := s.repo.(AccountModeration) if !ok || mod == nil { return errs.ErrAvailable } return mod.ExtendSendMutedUntil(ctx, userID, until) } // DisableAccount disables the user and revokes live sessions (moderation / admin ban). func (s *Service) DisableAccount(ctx context.Context, userID int64) error { mod, ok := s.repo.(AccountModeration) if !ok || mod == nil { return errs.ErrAvailable } if err := mod.SetUserStatus(ctx, userID, entity.StatusDisabled); err != nil { return err } s.revokeAccessBanned(ctx, userID) return nil } func (s *Service) revokeAccessBanned(ctx context.Context, userID int64) { if s.tokens != nil { _ = s.tokens.LogoutAll(ctx, userID) } if bk, ok := s.sessions.(BannedKicker); ok && bk != nil { bk.KickUserBanned(userID) return } if s.sessions != nil { s.sessions.KickUser(userID) } }