Raw
 1package inviteui
 2
 3import (
 4	"context"
 5	"errors"
 6	"fmt"
 7
 8	"tug/internal/service/invite"
 9	"tug/internal/service/password"
10	"tug/internal/transport/web"
11)
12
13type Redeemer struct {
14	service *invite.Service
15}
16
17func New(service *invite.Service) Redeemer {
18	if service == nil {
19		panic("inviteui: the redeemer needs an invite service")
20	}
21	return Redeemer{service: service}
22}
23
24var inviteProblems = []struct {
25	err     error
26	problem web.InviteProblem
27}{
28	{invite.ErrUsernameGrammar, web.InviteUsernameGrammar},
29	{invite.ErrUsernameTaken, web.InviteUsernameTaken},
30	{invite.ErrDisplayNameInvalid, web.InviteDisplayNameInvalid},
31	{password.ErrTooShort, web.InvitePasswordShort},
32	{password.ErrTooLong, web.InvitePasswordLong},
33	{invite.ErrPasswordMismatch, web.InvitePasswordMismatch},
34}
35
36func inviteError(err error) error {
37	if errors.Is(err, invite.ErrInvalidToken) {
38		return web.ErrInviteInvalid
39	}
40	if errors.Is(err, password.ErrBusy) {
41		return fmt.Errorf("%w: %w", web.ErrInviteBusy, err)
42	}
43	for _, p := range inviteProblems {
44		if errors.Is(err, p.err) {
45			return p.problem
46		}
47	}
48	return err
49}
50
51func (r Redeemer) Check(ctx context.Context, token string) error {
52	if err := r.service.Check(ctx, token); err != nil {
53		return inviteError(err)
54	}
55	return nil
56}
57
58func (r Redeemer) Redeem(ctx context.Context, token string, f web.InviteForm) (web.InviteRedeemed, error) {
59	redeemed, err := r.service.RedeemAccount(ctx, token, invite.Form{
60		Username:    f.Username,
61		DisplayName: f.DisplayName,
62		Password:    f.Password,
63		Confirm:     f.Confirm,
64	})
65	if err != nil {
66		return web.InviteRedeemed{}, inviteError(err)
67	}
68	return web.InviteRedeemed{Username: redeemed.Username, Code: redeemed.Code}, nil
69}