Files
FarmaFinder/apps/backend/src/email.js
T
Antoni Nuñez Romeu 87df61ab15
Run Tests on Branches / Detect Changes (push) Successful in 14s
Run Tests on Branches / Backend Tests (push) Successful in 2m24s
Run Tests on Branches / Frontend Tests (push) Successful in 1m57s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Has been skipped
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
feat: add forgot password and username recovery flow
- Add Mailpit SMTP container to docker-compose for dev email capture
- Add nodemailer dependency for email sending
- Add password_reset_tokens table (PG + SQLite)
- Add POST /api/auth/forgot-username endpoint
- Add POST /api/auth/forgot-password endpoint (token-based, 1h expiry)
- Add POST /api/auth/reset-password endpoint
- Create ForgotPasswordModal component (choose mode → email → sent)
- Create ResetPasswordView (token-based new password form)
- Add forgot/recovery links to LoginModal
- Add i18n translations (ES/CA) for the full flow
2026-07-27 15:57:54 +02:00

87 lines
3.5 KiB
JavaScript

import nodemailer from 'nodemailer';
const SMTP_HOST = process.env.SMTP_HOST || 'localhost';
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '1025', 10);
const SMTP_USER = process.env.SMTP_USER || '';
const SMTP_PASS = process.env.SMTP_PASS || '';
const SMTP_FROM = process.env.SMTP_FROM || 'noreply@farmafinder.com';
const APP_URL = process.env.APP_URL || 'http://localhost:3000';
let transporter = null;
function getTransporter() {
if (transporter) return transporter;
const auth = SMTP_USER && SMTP_PASS ? { user: SMTP_USER, pass: SMTP_PASS } : undefined;
transporter = nodemailer.createTransport({
host: SMTP_HOST,
port: SMTP_PORT,
secure: SMTP_PORT === 465,
auth,
ignoreTLS: SMTP_PORT !== 465 && !SMTP_USER,
});
return transporter;
}
export async function sendPasswordResetEmail(email, username, token) {
const resetUrl = `${APP_URL}/reset-password?token=${token}`;
const html = `
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body style="font-family: sans-serif; max-width: 480px; margin: 0 auto; padding: 24px;">
<h2>Restablecer contraseña — FarmaFinder</h2>
<p>Hola <strong>${username}</strong>,</p>
<p>Has solicitado restablecer tu contraseña. Haz clic en el siguiente enlace para crear una nueva:</p>
<p style="text-align: center; margin: 32px 0;">
<a href="${resetUrl}"
style="background: #2563eb; color: #fff; padding: 12px 24px; border-radius: 6px; text-decoration: none; display: inline-block;">
Restablecer contraseña
</a>
</p>
<p>Si no has solicitado este cambio, ignora este mensaje.</p>
<p>El enlace caduca en 1 hora.</p>
<hr style="margin-top: 32px; border: none; border-top: 1px solid #e5e7eb;">
<p style="color: #6b7280; font-size: 12px;">FarmaFinder — Encuentra tus medicamentos en farmacias cercanas</p>
</body>
</html>
`;
const text = `Restablecer contraseña — FarmaFinder\n\nHola ${username},\n\nHas solicitado restablecer tu contraseña. Abre este enlace para crear una nueva:\n${resetUrl}\n\nSi no has solicitado este cambio, ignora este mensaje.\nEl enlace caduca en 1 hora.`;
await getTransporter().sendMail({
from: SMTP_FROM,
to: email,
subject: 'Restablece tu contraseña — FarmaFinder',
text,
html,
});
}
export async function sendForgotUsernameEmail(email, username) {
const html = `
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body style="font-family: sans-serif; max-width: 480px; margin: 0 auto; padding: 24px;">
<h2>Tu usuario — FarmaFinder</h2>
<p>Has solicitado recordar tu nombre de usuario.</p>
<p style="font-size: 20px; text-align: center; padding: 16px; background: #f3f4f6; border-radius: 6px; margin: 24px 0;">
<strong>${username}</strong>
</p>
<p>Puedes iniciar sesión con este usuario y tu contraseña.</p>
<p>Si no has solicitado este dato, ignora este mensaje.</p>
<hr style="margin-top: 32px; border: none; border-top: 1px solid #e5e7eb;">
<p style="color: #6b7280; font-size: 12px;">FarmaFinder — Encuentra tus medicamentos en farmacias cercanas</p>
</body>
</html>
`;
const text = `Tu usuario — FarmaFinder\n\nHas solicitado recordar tu nombre de usuario.\n\nTu usuario es: ${username}\n\nSi no has solicitado este dato, ignora este mensaje.`;
await getTransporter().sendMail({
from: SMTP_FROM,
to: email,
subject: 'Tu nombre de usuario — FarmaFinder',
text,
html,
});
}