Skip to content

Commit

Permalink
[DEV-1299] Handle user update attribute event in CognitoFunctions (#563)
Browse files Browse the repository at this point in the history
  • Loading branch information
kin0992 authored Jan 17, 2024
1 parent 66fbc5e commit 6af6358
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-windows-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"cognito-functions": minor
---

Handle the event UpdateUserAttribute, triggered when the user updates the email address
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CustomMessageTriggerEvent } from 'aws-lambda';
import { makeHandler } from '../custom-message-handler';
import { makeConfirmationEmail } from '../templates/confirmation-message';
import { makeConfirmationForgotPasswordEmail } from '../templates/confirmation-forgot-password';
import { makeConfirmationUpdateEmailAddress } from '../templates/confirmation-update-email-address';

const makeEvent = (): CustomMessageTriggerEvent => ({
version: 'aVersion',
Expand Down Expand Up @@ -109,4 +110,18 @@ describe('Handler', () => {
expect(error).toStrictEqual(new Error('Operation not permitted'));
}
});

it('should reply with verification link on UpdateUserAttribute event', async () => {
const updateUserAttributeEvent: CustomMessageTriggerEvent = {
...makeEvent(),
triggerSource: 'CustomMessage_UpdateUserAttribute',
};
const { response } = await makeHandler(env)(updateUserAttributeEvent);
const { userAttributes, codeParameter } = updateUserAttributeEvent.request;
const expected = makeConfirmationUpdateEmailAddress(
`https://${env.domain}/auth/email-confirmation?username=${userAttributes['sub']}&code=${codeParameter}`,
env.domain
);
expect(response.emailMessage).toStrictEqual(expected);
});
});
17 changes: 14 additions & 3 deletions apps/cognito-functions/src/custom-message-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as t from 'io-ts';
import { CustomMessageTriggerEvent } from 'aws-lambda';
import { makeConfirmationEmail } from './templates/confirmation-message';
import { makeConfirmationForgotPasswordEmail } from './templates/confirmation-forgot-password';
import { makeConfirmationUpdateEmailAddress } from './templates/confirmation-update-email-address';

export const CustomMessageEnv = t.type({
domain: t.string,
Expand All @@ -13,10 +14,11 @@ export const makeHandler =
const username = event.request.userAttributes['sub'];
const cognitoUserStatus =
event.request.userAttributes['cognito:user_status'];
const eventTrigger = event.triggerSource;

if (
event.triggerSource === 'CustomMessage_SignUp' ||
event.triggerSource === 'CustomMessage_ResendCode'
eventTrigger === 'CustomMessage_SignUp' ||
eventTrigger === 'CustomMessage_ResendCode'
) {
if (cognitoUserStatus === 'CONFIRMED') {
// eslint-disable-next-line functional/no-expression-statements
Expand All @@ -32,7 +34,7 @@ export const makeHandler =
const emailSubject = 'Verifica la tua e-mail per PagoPA DevPortal';
const response = { ...event.response, emailMessage, emailSubject };
return { ...event, response };
} else if (event.triggerSource === 'CustomMessage_ForgotPassword') {
} else if (eventTrigger === 'CustomMessage_ForgotPassword') {
const { codeParameter } = event.request;
const href = `https://${env.domain}/auth/change-password?username=${username}&code=${codeParameter}`;
const emailMessage = makeConfirmationForgotPasswordEmail(
Expand All @@ -42,6 +44,15 @@ export const makeHandler =
const emailSubject = 'Password dimenticata';
const response = { ...event.response, emailMessage, emailSubject };
return { ...event, response };
} else if (eventTrigger === 'CustomMessage_UpdateUserAttribute') {
// eslint-disable-next-line functional/no-expression-statements
console.log(`User ${username} has requested to update the email address`);
const { codeParameter } = event.request;
const href = `https://${env.domain}/auth/email-confirmation?username=${username}&code=${codeParameter}`;
const emailMessage = makeConfirmationUpdateEmailAddress(href, env.domain);
const emailSubject = 'Verifica nuovo indirizzo email';
const response = { ...event.response, emailMessage, emailSubject };
return { ...event, response };
} else {
return event;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { parseMjmlToHtml } from './mjmlParser';

const TRANSLATIONS = {
previewText: 'Confermarci la validità di questa e-mail',
title: 'L’ultimo passo per attivare la tua utenza su PagoPA DevPortal',
text: 'Ciao,<br><br><br>Grazie per aver creato un account sul nostro DevPortal!<br><br>Non ti resta che confermarci la validità di questa e-mail.',
emailVerification: 'Verifica e-mail',
companyLegalDetails:
'PagoPA S.p.A. - Società per azioni con socio unico capitale sociale di euro 1,000,000 i.v.Sede legale in Roma, Piazza Colonna 370, CAP 00187Sede operativa in Roma, Via Sardegna 38, CAP 00187N. di iscrizione a Registro Imprese di Roma, CF e P.IVA 15376371009',
wrongRecipient:
'Ricevi questa e-mail perché hai creato un account su PagoPA DevPortal.<br>Non sei tu? Ignora o cancella questa e-mail.',
buttonFallbackText: 'Il bottone non funziona? Puoi usare il seguente link:',
};

export const makeConfirmationUpdateEmailAddress = (
confirmationLink: string,
domain: string
) => parseMjmlToHtml(updateEmailAddressMessage(confirmationLink, domain));

const updateEmailAddressMessage = (
confirmationLink: string,
domain: string
): string => `
<mjml>
<mj-head>
<mj-preview>${TRANSLATIONS.previewText}</mj-preview>
<mj-font name="Titillium Web" href="https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,400;0,700;1,400&display=swap" />
<mj-style>
.section {
box-sizing: border-box;
padding: 20px;
}
@media (min-width:480px) {
.section {
padding: 32px 40px 32px 40px;
}
}
@media (min-width:960px) {
.section {
padding: 78px 106px 60px 106px;
}
}
@media (min-width:760px) {
.container > table > tbody > tr > td {
padding: 22px 90px 0 0;
}
}
.box-shadow {
border: 1px solid #fefefe;
box-shadow: 0px 0px 45px 0px #0000001A;
}
.link a:link, .link a:visited, .link a:focus, .link a:hover, .link a:active {
text-decoration: none;
color: #0073E6;
}
</mj-style>
<mj-attributes>
<mj-class name="title" font-family="'Titillium Web', sans-serif" font-size="32px" font-weight="700" color="#17324D" />
<mj-class name="text" font-family="'Titillium Web', sans-serif" font-weight="400" color="#17324D" line-height="24px" align="left" />
<mj-class name="footer-text" font-family="'Titillium Web', sans-serif" font-size="14px" font-weight="400" color="#5C6F82" line-height="24px" align="left" />
</mj-attributes>
</mj-head>
<mj-body width="800px">
<mj-spacer height="10px" />
<mj-section css-class="section box-shadow" background-color="#fff">
<mj-column width="100%" padding-bottom="24px">
<mj-image align="left" src="https://${domain}/images/logo-pago-pa.png" alt="PagoPA" width="114px" height="33px" />
</mj-column>
<mj-column width="100%">
<mj-text mj-class="title" align="left" color="#17324D" font-size="32px">${TRANSLATIONS.title}</mj-text>
</mj-column>
<mj-column css-class="container" width="100%" padding-top="22px">
<mj-text mj-class="text" font-size="18px">${TRANSLATIONS.text}</mj-text>
<mj-button align="left" background-color="#0073E6" href="${confirmationLink}" font-size="16px" font-weight="700">
${TRANSLATIONS.emailVerification}
</mj-button>
<mj-text mj-class="text link" font-size="14px">${TRANSLATIONS.buttonFallbackText}<br><a href="${confirmationLink}">${confirmationLink}</a></mj-text>
<mj-spacer height="5px" />
<mj-divider border-width="1px" border-style="solid" border-color="#E3E7EB" />
<mj-spacer height="5px" />
<mj-text mj-class="text" font-size="14px">${TRANSLATIONS.wrongRecipient}</mj-text>
<mj-text mj-class="footer-text">${TRANSLATIONS.companyLegalDetails}</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
`;

0 comments on commit 6af6358

Please sign in to comment.