diff --git a/backend/internal/account/email.go b/backend/internal/account/email.go index ecfc967..4cfdf9a 100644 --- a/backend/internal/account/email.go +++ b/backend/internal/account/email.go @@ -319,6 +319,11 @@ func (s *EmailService) ConfirmByToken(ctx context.Context, token string) (LinkCo if err := s.store.confirmEmailIdentity(ctx, pend.id, pend.accountID, pend.email, s.now()); err != nil { return LinkConfirmation{}, err } + // Binding the first email promotes a guest to a durable account, matching the + // code-based link flow (which clears the guest flag in the link service). + if err := s.store.ClearGuest(ctx, pend.accountID); err != nil { + return LinkConfirmation{}, err + } return LinkConfirmation{Purpose: purposeLink, Account: pend.accountID}, nil default: return LinkConfirmation{}, fmt.Errorf("account: unsupported confirmation purpose %q", pend.purpose) diff --git a/backend/internal/inttest/email_test.go b/backend/internal/inttest/email_test.go index ea3940b..667edd1 100644 --- a/backend/internal/inttest/email_test.go +++ b/backend/internal/inttest/email_test.go @@ -394,3 +394,32 @@ func TestEmailAccountSeedsDisplayName(t *testing.T) { t.Errorf("display name = %q, want the email local part %q", acc.DisplayName, local) } } + +// TestConfirmByTokenLinkClearsGuest: binding an email to a guest via the deeplink +// promotes the guest to a durable account (the deeplink path must match the +// code-based link flow, which clears the guest flag). +func TestConfirmByTokenLinkClearsGuest(t *testing.T) { + ctx := context.Background() + store := account.NewStore(testDB) + mailer := &capturingMailer{} + svc := account.NewEmailService(store, mailer, "https://erudit-game.ru") + guest, err := store.ProvisionGuest(ctx, "") + if err != nil { + t.Fatalf("provision guest: %v", err) + } + email := "guest-link-" + uuid.NewString() + "@example.com" + + if err := svc.RequestLinkCode(ctx, guest.ID, email); err != nil { + t.Fatalf("request link: %v", err) + } + if _, err := svc.ConfirmByToken(ctx, tokenFromMail(t, mailer.lastBody)); err != nil { + t.Fatalf("confirm by token: %v", err) + } + acc, err := store.GetByID(ctx, guest.ID) + if err != nil { + t.Fatalf("get: %v", err) + } + if acc.IsGuest { + t.Error("linking an email via the deeplink must promote the guest to durable") + } +}