envoie du mail de confirmation

This commit is contained in:
2026-03-31 19:50:51 +02:00
parent e0f862b361
commit e3968e6dbf
4 changed files with 63 additions and 14 deletions

View File

@@ -45,9 +45,9 @@ model User {
}
model UserPreference {
id String @id @default(uuid())
id String @id
userId String @unique
language String @default("fr")
theme String @default("light")
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
}

View File

@@ -9,10 +9,17 @@ export default async function authRoutes(fastify: FastifyInstance) {
fastify.post('/auth/register', async (request, reply) => {
const body = RegisterSchema.parse(request.body) // Zod throw → handler global
const lang = request.headers['accept-language']
?.split(',')[0]
.split('-')[0] as 'fr' | 'en'
const validLang = ['fr', 'en'].includes(lang) ? lang : 'fr'
const { user, authToken } = await registerUser(
fastify.prisma,
fastify.mailer,
body
body,
validLang
)
reply.setCookie('authToken', authToken, {

View File

@@ -10,7 +10,8 @@ import { Errors } from '../errors/AppError.js'
export async function registerUser(
prisma: PrismaClient,
mailer: Transporter,
input: RegisterInput
input: RegisterInput,
lang: 'fr' | 'en' = 'fr'
) {
// 1. Vérif email unique
const existing = await prisma.user.findUnique({
@@ -53,8 +54,8 @@ export async function registerUser(
},
})
// 5. Envoi du mail
await sendConfirmationMail(mailer, user.email, confirmToken)
// 5. Envoi du mail avec la langue
await sendConfirmationMail(mailer, user.email, confirmToken, lang)
// 6. AuthToken pour la persistance
const authToken = generateToken()
@@ -66,6 +67,16 @@ export async function registerUser(
expiresAt: generateAuthTokenExpiry(),
},
})
// 7 Création des préférences avec la langue détectée
await prisma.userPreference.create({
data: {
id: crypto.randomUUID(),
userId: user.id,
language: lang,
theme: 'light',
},
})
return { user, authToken }
}

View File

@@ -1,20 +1,51 @@
import { Transporter } from 'nodemailer'
type Lang = 'fr' | 'en'
const templates = {
fr: (url: string) => ({
subject: 'Merci de confirmer votre e-mail',
html: `
<html><body>
<p>Bienvenue sur le gestionnaire de listes !</p>
<p>
Pour pouvoir utiliser le site, vous devez confirmer votre adresse mail sous 7 jours en cliquant sur
<a href="${url}" style="font-size:1.2em;color:blueviolet;">
ce lien
</a>.
</p>
</body></html>
`,
}),
en: (url: string) => ({
subject: 'Please confirm your email address',
html: `
<html><body>
<p>Welcome to the list manager!</p>
<p>
To start using the site, please confirm your email address within 7 days by clicking
<a href="${url}" style="font-size:1.2em;color:blueviolet;">
this link
</a>.
</p>
</body></html>
`,
}),
}
export async function sendConfirmationMail(
mailer: Transporter,
email: string,
token: string
token: string,
lang: Lang = 'fr'
): Promise<void> {
const url = `${process.env.APP_URL}/auth/confirm-email?token=${token}`
const url = `${process.env.FRONT_URL}/${lang}/confirm?token=${token}`
const { subject, html } = templates[lang](url)
await mailer.sendMail({
from: process.env.MAIL_FROM,
to: email,
subject: 'Confirmez votre adresse mail',
html: `
<p>Merci de vous être inscrit !</p>
<p>Cliquez sur ce lien pour confirmer votre adresse mail (valable 24h) :</p>
<a href="${url}">${url}</a>
`,
subject,
html,
})
}