package admin import ( "context" "errors" "fmt" "time" "tug/internal/storage" ) var ( ErrConfirmCode = errors.New("admin: the confirmation code does not match") ErrConfirmSpent = errors.New("admin: too many wrong confirmation codes") ) type PendingAccount struct { Username string Spent bool WrongCodes int ExpiresAt time.Time } func (s *Service) pending(ctx context.Context) (map[string]storage.Pending, error) { pending, err := s.store.PendingUsers(ctx) if err != nil { return nil, failed("read the pending accounts", err) } return pending, nil } func (s *Service) PendingAccount(ctx context.Context, id string) (PendingAccount, error) { pending, err := s.pending(ctx) if err != nil { return PendingAccount{}, err } p, ok := pending[id] if !ok { return PendingAccount{}, fmt.Errorf("%w: %s is not waiting for a confirmation", ErrNotFound, id) } u, err := s.store.UserByID(ctx, id) if err != nil { return PendingAccount{}, target("read user", err) } return PendingAccount{Username: u.Username, Spent: p.WrongCodes >= storage.ConfirmWrongLimit, WrongCodes: p.WrongCodes, ExpiresAt: p.ExpiresAt}, nil } func (s *Service) ConfirmAccount(ctx context.Context, actor, id, code string) error { err := s.store.ConfirmUserAudited(ctx, id, code, actor) switch { case err == nil: return nil case errors.Is(err, storage.ErrConfirmCode): return ErrConfirmCode case errors.Is(err, storage.ErrConfirmSpent): return ErrConfirmSpent case errors.Is(err, storage.ErrNotPending): return fmt.Errorf("%w: %w", ErrNotFound, err) } return failed("confirm account", err) } func (s *Service) RejectAccount(ctx context.Context, actor, id string) error { _, err := s.store.RejectPendingUserAudited(ctx, id, actor) switch { case err == nil: return nil case errors.Is(err, storage.ErrNotPending), errors.Is(err, storage.ErrNotFound): return fmt.Errorf("%w: %w", ErrNotFound, err) } return failed("reject account", err) } func markPending(members []Member, pending map[string]storage.Pending) []Member { for i := range members { _, members[i].Pending = pending[members[i].ID] } return members } func isPendingIn(pending map[string]storage.Pending, id string) bool { _, ok := pending[id] return ok }