const EmailClient = require("../core/EmailClient"); const TemplateManager = require("../core/TemplateManager"); /** * AuthEmailService handles all authentication and account security related emails * This service is responsible for: * - Sending email verification links * - Sending password reset links * - Sending password changed confirmations */ class AuthEmailService { constructor() { this.emailClient = new EmailClient(); this.templateManager = new TemplateManager(); this.initialized = false; } /** * Initialize the auth email service * @returns {Promise} */ async initialize() { if (this.initialized) return; await Promise.all([ this.emailClient.initialize(), this.templateManager.initialize(), ]); this.initialized = true; console.log("Auth Email Service initialized successfully"); } /** * Send email verification email to new users * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @param {string} verificationToken - Email verification token * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendVerificationEmail(user, verificationToken) { if (!this.initialized) { await this.initialize(); } const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000"; const verificationUrl = `${frontendUrl}/verify-email?token=${verificationToken}`; const variables = { recipientName: user.firstName || "there", verificationUrl: verificationUrl, verificationCode: verificationToken, // 6-digit code for display in email }; const htmlContent = await this.templateManager.renderTemplate( "emailVerificationToUser", variables ); return await this.emailClient.sendEmail( user.email, "Verify Your Email - Village Share", htmlContent ); } /** * Send password reset email with reset link * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @param {string} resetToken - Password reset token * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendPasswordResetEmail(user, resetToken) { if (!this.initialized) { await this.initialize(); } const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000"; const resetUrl = `${frontendUrl}/reset-password?token=${resetToken}`; const variables = { recipientName: user.firstName || "there", resetUrl: resetUrl, }; const htmlContent = await this.templateManager.renderTemplate( "passwordResetToUser", variables ); return await this.emailClient.sendEmail( user.email, "Reset Your Password - Village Share", htmlContent ); } /** * Send password changed confirmation email * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendPasswordChangedEmail(user) { if (!this.initialized) { await this.initialize(); } const timestamp = new Date().toLocaleString("en-US", { dateStyle: "long", timeStyle: "short", }); const variables = { recipientName: user.firstName || "there", email: user.email, timestamp: timestamp, }; const htmlContent = await this.templateManager.renderTemplate( "passwordChangedToUser", variables ); return await this.emailClient.sendEmail( user.email, "Password Changed Successfully - Village Share", htmlContent ); } /** * Send personal information changed notification email * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendPersonalInfoChangedEmail(user) { if (!this.initialized) { await this.initialize(); } const timestamp = new Date().toLocaleString("en-US", { dateStyle: "long", timeStyle: "short", }); const variables = { recipientName: user.firstName || "there", email: user.email, timestamp: timestamp, }; const htmlContent = await this.templateManager.renderTemplate( "personalInfoChangedToUser", variables ); return await this.emailClient.sendEmail( user.email, "Personal Information Updated - Village Share", htmlContent ); } /** * Send two-factor authentication OTP email * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @param {string} otpCode - 6-digit OTP code * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendTwoFactorOtpEmail(user, otpCode) { if (!this.initialized) { await this.initialize(); } const variables = { recipientName: user.firstName || "there", otpCode: otpCode, }; const htmlContent = await this.templateManager.renderTemplate( "twoFactorOtpToUser", variables ); return await this.emailClient.sendEmail( user.email, "Your Verification Code - Village Share", htmlContent ); } /** * Send two-factor authentication enabled confirmation email * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendTwoFactorEnabledEmail(user) { if (!this.initialized) { await this.initialize(); } const timestamp = new Date().toLocaleString("en-US", { dateStyle: "long", timeStyle: "short", }); const variables = { recipientName: user.firstName || "there", timestamp: timestamp, }; const htmlContent = await this.templateManager.renderTemplate( "twoFactorEnabledToUser", variables ); return await this.emailClient.sendEmail( user.email, "Multi-Factor Authentication Enabled - Village Share", htmlContent ); } /** * Send two-factor authentication disabled notification email * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendTwoFactorDisabledEmail(user) { if (!this.initialized) { await this.initialize(); } const timestamp = new Date().toLocaleString("en-US", { dateStyle: "long", timeStyle: "short", }); const variables = { recipientName: user.firstName || "there", timestamp: timestamp, }; const htmlContent = await this.templateManager.renderTemplate( "twoFactorDisabledToUser", variables ); return await this.emailClient.sendEmail( user.email, "Multi-Factor Authentication Disabled - Village Share", htmlContent ); } /** * Send recovery code used notification email * @param {Object} user - User object * @param {string} user.firstName - User's first name * @param {string} user.email - User's email address * @param {number} remainingCodes - Number of remaining recovery codes * @returns {Promise<{success: boolean, messageId?: string, error?: string}>} */ async sendRecoveryCodeUsedEmail(user, remainingCodes) { if (!this.initialized) { await this.initialize(); } const timestamp = new Date().toLocaleString("en-US", { dateStyle: "long", timeStyle: "short", }); // Determine color based on remaining codes let remainingCodesColor = "#28a745"; // Green if (remainingCodes <= 2) { remainingCodesColor = "#dc3545"; // Red } else if (remainingCodes <= 5) { remainingCodesColor = "#fd7e14"; // Orange } const variables = { recipientName: user.firstName || "there", remainingCodes: remainingCodes, remainingCodesColor: remainingCodesColor, lowCodesWarning: remainingCodes <= 2, timestamp: timestamp, }; const htmlContent = await this.templateManager.renderTemplate( "recoveryCodeUsedToUser", variables ); return await this.emailClient.sendEmail( user.email, "Recovery Code Used - Village Share", htmlContent ); } } module.exports = AuthEmailService;