Raw
 1package admin
 2
 3import (
 4	"context"
 5	"errors"
 6	"fmt"
 7	"time"
 8
 9	"tug/internal/storage"
10)
11
12var (
13	ErrConfirmCode  = errors.New("admin: the confirmation code does not match")
14	ErrConfirmSpent = errors.New("admin: too many wrong confirmation codes")
15)
16
17type PendingAccount struct {
18	Username   string
19	Spent      bool
20	WrongCodes int
21	ExpiresAt  time.Time
22}
23
24func (s *Service) pending(ctx context.Context) (map[string]storage.Pending, error) {
25	pending, err := s.store.PendingUsers(ctx)
26	if err != nil {
27		return nil, failed("read the pending accounts", err)
28	}
29	return pending, nil
30}
31
32func (s *Service) PendingAccount(ctx context.Context, id string) (PendingAccount, error) {
33	pending, err := s.pending(ctx)
34	if err != nil {
35		return PendingAccount{}, err
36	}
37	p, ok := pending[id]
38	if !ok {
39		return PendingAccount{}, fmt.Errorf("%w: %s is not waiting for a confirmation", ErrNotFound, id)
40	}
41	u, err := s.store.UserByID(ctx, id)
42	if err != nil {
43		return PendingAccount{}, target("read user", err)
44	}
45	return PendingAccount{Username: u.Username, Spent: p.WrongCodes >= storage.ConfirmWrongLimit, WrongCodes: p.WrongCodes, ExpiresAt: p.ExpiresAt}, nil
46}
47
48func (s *Service) ConfirmAccount(ctx context.Context, actor, id, code string) error {
49	err := s.store.ConfirmUserAudited(ctx, id, code, actor)
50	switch {
51	case err == nil:
52		return nil
53	case errors.Is(err, storage.ErrConfirmCode):
54		return ErrConfirmCode
55	case errors.Is(err, storage.ErrConfirmSpent):
56		return ErrConfirmSpent
57	case errors.Is(err, storage.ErrNotPending):
58		return fmt.Errorf("%w: %w", ErrNotFound, err)
59	}
60	return failed("confirm account", err)
61}
62
63func (s *Service) RejectAccount(ctx context.Context, actor, id string) error {
64	_, err := s.store.RejectPendingUserAudited(ctx, id, actor)
65	switch {
66	case err == nil:
67		return nil
68	case errors.Is(err, storage.ErrNotPending), errors.Is(err, storage.ErrNotFound):
69		return fmt.Errorf("%w: %w", ErrNotFound, err)
70	}
71	return failed("reject account", err)
72}
73
74func markPending(members []Member, pending map[string]storage.Pending) []Member {
75	for i := range members {
76		_, members[i].Pending = pending[members[i].ID]
77	}
78	return members
79}
80
81func isPendingIn(pending map[string]storage.Pending, id string) bool {
82	_, ok := pending[id]
83	return ok
84}