package inviteui import ( "context" "errors" "fmt" "tug/internal/service/invite" "tug/internal/service/password" "tug/internal/transport/web" ) type Redeemer struct { service *invite.Service } func New(service *invite.Service) Redeemer { if service == nil { panic("inviteui: the redeemer needs an invite service") } return Redeemer{service: service} } var inviteProblems = []struct { err error problem web.InviteProblem }{ {invite.ErrUsernameGrammar, web.InviteUsernameGrammar}, {invite.ErrUsernameTaken, web.InviteUsernameTaken}, {invite.ErrDisplayNameInvalid, web.InviteDisplayNameInvalid}, {password.ErrTooShort, web.InvitePasswordShort}, {password.ErrTooLong, web.InvitePasswordLong}, {invite.ErrPasswordMismatch, web.InvitePasswordMismatch}, } func inviteError(err error) error { if errors.Is(err, invite.ErrInvalidToken) { return web.ErrInviteInvalid } if errors.Is(err, password.ErrBusy) { return fmt.Errorf("%w: %w", web.ErrInviteBusy, err) } for _, p := range inviteProblems { if errors.Is(err, p.err) { return p.problem } } return err } func (r Redeemer) Check(ctx context.Context, token string) error { if err := r.service.Check(ctx, token); err != nil { return inviteError(err) } return nil } func (r Redeemer) Redeem(ctx context.Context, token string, f web.InviteForm) (web.InviteRedeemed, error) { redeemed, err := r.service.RedeemAccount(ctx, token, invite.Form{ Username: f.Username, DisplayName: f.DisplayName, Password: f.Password, Confirm: f.Confirm, }) if err != nil { return web.InviteRedeemed{}, inviteError(err) } return web.InviteRedeemed{Username: redeemed.Username, Code: redeemed.Code}, nil }