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
- 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
87 lines
3.5 KiB
JavaScript
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,
|
|
});
|
|
}
|