${notification.message}
${notification.deviceId ? `Device ID: ${notification.deviceId}
` : ''} ${notification.data ? `Details: ${JSON.stringify(notification.data, null, 2)}
` : ''}Timestamp: ${new Date().toLocaleString()}
const nodemailer = require('nodemailer'); const twilio = require('twilio'); const logger = require('../utils/logger'); const database = require('../config/database'); const redis = require('../config/redis'); class NotificationService { constructor() { this.emailTransporter = null; this.twilioClient = null; this.isInitialized = false; } async initialize() { try { await this.setupEmailTransporter(); await this.setupTwilioClient(); this.isInitialized = true; logger.info('Notification service initialized successfully'); } catch (error) { logger.error('Failed to initialize Notification service:', error); throw error; } } async setupEmailTransporter() { try { this.emailTransporter = nodemailer.createTransporter({ host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, secure: process.env.SMTP_PORT === '465', auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS } }); // Verify connection await this.emailTransporter.verify(); logger.info('Email transporter configured successfully'); } catch (error) { logger.error('Failed to setup email transporter:', error); this.emailTransporter = null; } } async setupTwilioClient() { try { if (process.env.TWILIO_ACCOUNT_SID && process.env.TWILIO_AUTH_TOKEN) { this.twilioClient = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN); logger.info('Twilio client configured successfully'); } else { logger.warn('Twilio credentials not provided, SMS notifications disabled'); } } catch (error) { logger.error('Failed to setup Twilio client:', error); this.twilioClient = null; } } async sendNotification(userId, notification) { try { const startTime = Date.now(); // Get user notification preferences const user = await this.getUserNotificationPreferences(userId); if (!user) { logger.warn(`User ${userId} not found for notification`); return false; } // Store notification in database const notificationId = await this.storeNotification(userId, notification); // Send notifications based on user preferences const results = { email: false, sms: false, inApp: true // Always store in-app }; // Send email if enabled if (user.email_enabled && user.email) { results.email = await this.sendEmail(user.email, notification); } // Send SMS if enabled if (user.sms_enabled && user.phone && this.twilioClient) { results.sms = await this.sendSMS(user.phone, notification); } // Update notification status await this.updateNotificationStatus(notificationId, results); const processingTime = Date.now() - startTime; logger.logNotification('multi_channel', userId, notification.title, results); logger.logPerformance('notification_sending', processingTime, { userId, channels: Object.keys(results).filter(k => results[k]).length }); return results; } catch (error) { logger.error('Error sending notification:', error); return false; } } async sendEmail(recipients, notification) { try { if (!this.emailTransporter) { logger.warn('Email transporter not configured'); return false; } const emailContent = this.formatEmailContent(notification); const mailOptions = { from: process.env.SMTP_USER, to: Array.isArray(recipients) ? recipients.join(',') : recipients, subject: emailContent.subject, html: emailContent.html, text: emailContent.text }; const result = await this.emailTransporter.sendMail(mailOptions); logger.logNotification('email', recipients, notification.title, 'sent'); return true; } catch (error) { logger.error('Error sending email:', error); return false; } } async sendSMS(recipients, notification) { try { if (!this.twilioClient) { logger.warn('Twilio client not configured'); return false; } const message = this.formatSMSContent(notification); const phoneNumbers = Array.isArray(recipients) ? recipients : [recipients]; const results = await Promise.allSettled( phoneNumbers.map(phone => this.twilioClient.messages.create({ body: message, from: process.env.TWILIO_PHONE_NUMBER, to: phone }) ) ); const successCount = results.filter(r => r.status === 'fulfilled').length; const success = successCount === phoneNumbers.length; if (success) { logger.logNotification('sms', recipients, notification.title, 'sent'); } else { logger.error('Some SMS messages failed to send'); } return success; } catch (error) { logger.error('Error sending SMS:', error); return false; } } async sendWebhook(url, data) { try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); const success = response.ok; if (success) { logger.logNotification('webhook', url, 'Webhook notification', 'sent'); } else { logger.error(`Webhook failed with status: ${response.status}`); } return success; } catch (error) { logger.error('Error sending webhook:', error); return false; } } formatEmailContent(notification) { const severityColors = { critical: '#dc3545', warning: '#ffc107', info: '#17a2b8', success: '#28a745' }; const color = severityColors[notification.severity] || '#6c757d'; const html = `
${notification.message}
${notification.deviceId ? `Device ID: ${notification.deviceId}
` : ''} ${notification.data ? `Details: ${JSON.stringify(notification.data, null, 2)}
` : ''}Timestamp: ${new Date().toLocaleString()}