Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(email): add magic link smtp email #788

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 30 additions & 53 deletions cypress/e2e/signin_with_magic_link/index.cy.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
//

import { getMagicLinkFromEmail } from "#cypress/support/get-from-email";

describe("sign-in with magic link", () => {
before(() => {
cy.mailslurp().then((mailslurp) =>
mailslurp.inboxController.deleteAllInboxEmails({
inboxId: "66ac0a4c-bd2d-490e-a277-1e7c2520100d",
}),
);
});

it("should sign-up with magic link", function () {
cy.visit("/users/start-sign-in");

Expand All @@ -25,20 +15,16 @@ describe("sign-in with magic link", () => {

cy.contains("Votre lien vous attend à l’adresse...");

cy.mailslurp()
// use inbox id and a timeout of 30 seconds
.then((mailslurp) =>
mailslurp.waitForLatestEmail(
"66ac0a4c-bd2d-490e-a277-1e7c2520100d",
60000,
true,
),
)
// extract the connection link from the email subject
.then(getMagicLinkFromEmail)
.then((link) => {
cy.visit(link);
});
cy.maildevGetMessageBySubject("Lien de connexion à ProConnect").then(
(email) => {
cy.maildevVisitMessageById(email.id);
cy.contains(
"Vous avez demandé un lien de connexion à ProConnect. Utilisez le bouton ci-dessous pour vous connecter instantanément.",
);
cy.contains("Se connecter").click();
cy.maildevDeleteMessageById(email.id);
},
);

cy.contains("Renseigner son identité");
});
Expand All @@ -61,20 +47,16 @@ describe("sign-in with magic link", () => {

cy.contains("Votre lien vous attend à l’adresse...");

cy.mailslurp()
// use inbox id and a timeout of 30 seconds
.then((mailslurp) =>
mailslurp.waitForLatestEmail(
"66ac0a4c-bd2d-490e-a277-1e7c2520100d",
60000,
true,
),
)
// extract the connection link from the email subject
.then(getMagicLinkFromEmail)
.then((link) => {
cy.visit(link);
});
cy.maildevGetMessageBySubject("Lien de connexion à ProConnect").then(
(email) => {
cy.maildevVisitMessageById(email.id);
cy.contains(
"Vous avez demandé un lien de connexion à ProConnect. Utilisez le bouton ci-dessous pour vous connecter instantanément.",
);
cy.contains("Se connecter").click();
cy.maildevDeleteMessageById(email.id);
},
);

cy.contains("Renseigner son identité");
});
Expand Down Expand Up @@ -125,21 +107,16 @@ describe("sign-in with magic link", () => {

cy.contains("Votre lien vous attend à l’adresse...");

cy.mailslurp()
// use inbox id and a timeout of 30 seconds
.then((mailslurp) =>
mailslurp.waitForLatestEmail(
"66ac0a4c-bd2d-490e-a277-1e7c2520100d",
60000,
true,
),
)
// extract the connection link from the email subject
.then(getMagicLinkFromEmail)
.then((link) => {
cy.visit(link);
});

cy.maildevGetMessageBySubject("Lien de connexion à ProConnect").then(
(email) => {
cy.maildevVisitMessageById(email.id);
cy.contains(
"Vous avez demandé un lien de connexion à ProConnect. Utilisez le bouton ci-dessous pour vous connecter instantanément.",
);
cy.contains("Se connecter").click();
cy.maildevDeleteMessageById(email.id);
},
);
cy.contains("Renseigner son identité");
});
});
15 changes: 15 additions & 0 deletions packages/email/src/MagicLink.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//

import type { ComponentAnnotations, Renderer } from "@storybook/csf";
import MagicLink, { type Props } from "./MagicLink";

//

export default {
title: "Magic Link",
render: MagicLink,
args: {
baseurl: "http://localhost:3000",
magic_link: "#/../src/MagicLink.stories.tsx",
} as Props,
} as ComponentAnnotations<Renderer, Props>;
32 changes: 32 additions & 0 deletions packages/email/src/MagicLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//

import { Layout, type LayoutProps } from "./_layout";
import { Button, Em, Text } from "./components";

//

export default function MagicLink(props: Props) {
const { baseurl, magic_link } = props;
return (
<Layout baseurl={baseurl}>
<Text>Bonjour,</Text>
<br />
<Text>
Vous avez demandé un <b>lien de connexion</b> à ProConnect. Utilisez le
bouton ci-dessous pour vous connecter instantanément.
<br />
<Em>Il est valable 1 heure</Em>.
</Text>
<br />
<Button href={magic_link}>Se connecter</Button>
<br />
<Text>Ce lien a été généré pour vous. Merci de ne pas le partager.</Text>
</Layout>
);
}

//

export type Props = LayoutProps & {
magic_link: string;
};
1 change: 1 addition & 0 deletions packages/email/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { default as Delete2faProtection } from "./Delete2faProtection";
export { default as DeleteAccessKey } from "./DeleteAccessKey";
export { default as DeleteAccount } from "./DeleteAccount";
export { default as DeleteFreeTotpMail } from "./DeleteFreeTotpMail";
export { default as MagicLink } from "./MagicLink";
export { default as OfficialContactEmailVerification } from "./OfficialContactEmailVerification";
export { default as ResetPassword } from "./ResetPassword";
export { default as UpdatePersonalDataMail } from "./UpdatePersonalDataMail";
Expand Down
2 changes: 1 addition & 1 deletion src/connectors/brevo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { BrevoApiError } from "../config/errors";
import { logger } from "../services/log";
import { render } from "../services/renderer";

type RemoteTemplateSlug = "magic-link";
type RemoteTemplateSlug = never;
type LocalTemplateSlug = "moderation-processed";

// active templates id are listed at https://app-smtp.brevo.com/templates
Expand Down
10 changes: 5 additions & 5 deletions src/managers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DeleteAccessKey,
DeleteAccount,
DeleteFreeTotpMail,
MagicLink,
ResetPassword,
UpdatePersonalDataMail,
UpdateTotpApplication,
Expand All @@ -23,7 +24,6 @@ import {
UserNotFoundError,
WeakPasswordError,
} from "../config/errors";
import { sendMail as legacySendMail } from "../connectors/brevo";
import { isEmailSafeToSendTransactional } from "../connectors/debounce";
import { sendMail } from "../connectors/mail";

Expand Down Expand Up @@ -478,13 +478,13 @@ export const sendSendMagicLinkEmail = async (
magic_link_sent_at: new Date(),
});

await legacySendMail({
await sendMail({
to: [user.email],
subject: "Lien de connexion à ProConnect",
template: "magic-link",
params: {
html: MagicLink({
baseurl: host,
magic_link: `${host}/users/sign-in-with-magic-link?magic_link_token=${magicLinkToken}`,
},
}).toString(),
});

return true;
Expand Down