Skip to content

Commit 0efc10e

Browse files
committed
Hook up sending verification email
1 parent 716e944 commit 0efc10e

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

src/authentication/start-magic-link-email-pub-sub.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {EmailAddressCodec, failure} from '../types';
77
import {Dependencies} from '../dependencies';
88
import {sendLogInLink} from './send-log-in-link';
99
import {Config} from '../configuration';
10+
import * as t from 'io-ts';
11+
import { sendEmailVerification } from './send-email-verification';
1012

1113
const validateEmail = (input: unknown) =>
1214
pipe(
@@ -16,6 +18,19 @@ const validateEmail = (input: unknown) =>
1618
E.mapLeft(failure('Invalid Email'))
1719
);
1820

21+
const validateEmailVerificationCodec = t.strict({
22+
memberNumber: t.Integer,
23+
emailAddress: EmailAddressCodec,
24+
});
25+
26+
const validateEmailVerification = (input: unknown) =>
27+
pipe(
28+
input,
29+
validateEmailVerificationCodec.decode,
30+
E.mapLeft(formatValidationErrors),
31+
E.mapLeft(failure('Invalid validation request'))
32+
);
33+
1934
export const startMagicLinkEmailPubSub = (deps: Dependencies, conf: Config) => {
2035
PubSub.subscribe(
2136
'send-log-in-link',
@@ -33,4 +48,22 @@ export const startMagicLinkEmailPubSub = (deps: Dependencies, conf: Config) => {
3348
)
3449
)()
3550
);
51+
52+
PubSub.subscribe(
53+
'send-email-verification',
54+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
55+
async (topic, payload) => {
56+
await pipe(
57+
payload,
58+
validateEmailVerification,
59+
TE.fromEither,
60+
TE.chain(({memberNumber, emailAddress}) => sendEmailVerification(deps, conf)(memberNumber, emailAddress)),
61+
TE.match(
62+
failure =>
63+
deps.logger.error({topic, failure}, 'Failed to process message'),
64+
successMsg => deps.logger.info({topic, result: successMsg})
65+
)
66+
)()
67+
}
68+
)
3669
};

src/commands/members/send-email-verification.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,18 @@ const process: Command<SendMemberEmailVerification>['process'] = input => {
3737
}
3838

3939
publish('send-email-verification', {
40-
member: input.command.memberNumber,
41-
email: input.command.email,
40+
memberNumber: input.command.memberNumber,
41+
42+
// We use the emailAddress we actually matched rather than the email input
43+
// This prevents weirdness around the normalised vs raw address
44+
emailAddress,
4245
});
4346

4447
return O.some(
4548
constructEvent('MemberEmailVerificationRequested')({
4649
actor: input.command.actor,
4750
memberNumber: input.command.memberNumber,
48-
email: input.command.email,
51+
email: emailAddress,
4952
})
5053
);
5154
};

tests/queries/me/render.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,19 @@ describe('/me render', () => {
2828
emailAddress: primaryEmail,
2929
verifiedAt: O.some(new Date('2025-01-01T00:00:00.000Z')),
3030
addedAt: new Date('2025-01-01T00:00:00.000Z'),
31+
verificationLastSent: O.none,
3132
},
3233
{
3334
emailAddress: unverifiedEmail,
3435
verifiedAt: O.none,
3536
addedAt: new Date('2025-01-02T00:00:00.000Z'),
37+
verificationLastSent: O.none,
3638
},
3739
{
3840
emailAddress: verifiedSecondaryEmail,
3941
verifiedAt: O.some(new Date('2025-01-03T00:00:00.000Z')),
4042
addedAt: new Date('2025-01-03T00:00:00.000Z'),
43+
verificationLastSent: O.none,
4144
},
4245
],
4346
name: O.none,
@@ -57,15 +60,15 @@ describe('/me render', () => {
5760

5861
it('shows the primary email and all email addresses', () => {
5962
const page = renderPage(viewModel);
60-
expect(page.textContent).toContain('Primary email');
63+
expect(page.textContent).toContain('Primary');
6164
expect(page.textContent).toContain(primaryEmail);
6265
expect(page.textContent).toContain(unverifiedEmail);
6366
expect(page.textContent).toContain(verifiedSecondaryEmail);
6467
});
6568

6669
it('shows the right actions for unverified and verified non-primary emails', () => {
6770
const page = renderPage(viewModel);
68-
expect(page.textContent).toContain('Send verification email');
69-
expect(page.textContent).toContain('Make primary');
71+
expect(page.textContent).toContain('Send Verification Email');
72+
expect(page.textContent).toContain('Set Primary Email');
7073
});
7174
});

0 commit comments

Comments
 (0)