email sent when personal information changed
This commit is contained in:
@@ -11,8 +11,16 @@ const { htmlToPlainText } = require("./emailUtils");
|
||||
*/
|
||||
class EmailClient {
|
||||
constructor() {
|
||||
// Singleton pattern - return existing instance if already created
|
||||
if (EmailClient.instance) {
|
||||
return EmailClient.instance;
|
||||
}
|
||||
|
||||
this.sesClient = null;
|
||||
this.initialized = false;
|
||||
this.initializationPromise = null;
|
||||
|
||||
EmailClient.instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,19 +28,30 @@ class EmailClient {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async initialize() {
|
||||
// If already initialized, return immediately
|
||||
if (this.initialized) return;
|
||||
|
||||
try {
|
||||
// Use centralized AWS configuration with credential profiles
|
||||
const awsConfig = getAWSConfig();
|
||||
this.sesClient = new SESClient(awsConfig);
|
||||
|
||||
this.initialized = true;
|
||||
console.log("AWS SES Email Client initialized successfully");
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize AWS SES Email Client:", error);
|
||||
throw error;
|
||||
// If initialization is in progress, wait for it
|
||||
if (this.initializationPromise) {
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
// Start initialization and store the promise
|
||||
this.initializationPromise = (async () => {
|
||||
try {
|
||||
// Use centralized AWS configuration with credential profiles
|
||||
const awsConfig = getAWSConfig();
|
||||
this.sesClient = new SESClient(awsConfig);
|
||||
|
||||
this.initialized = true;
|
||||
console.log("AWS SES Email Client initialized successfully");
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize AWS SES Email Client:", error);
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,16 @@ const path = require("path");
|
||||
*/
|
||||
class TemplateManager {
|
||||
constructor() {
|
||||
// Singleton pattern - return existing instance if already created
|
||||
if (TemplateManager.instance) {
|
||||
return TemplateManager.instance;
|
||||
}
|
||||
|
||||
this.templates = new Map();
|
||||
this.initialized = false;
|
||||
this.initializationPromise = null;
|
||||
|
||||
TemplateManager.instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,11 +28,22 @@ class TemplateManager {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async initialize() {
|
||||
// If already initialized, return immediately
|
||||
if (this.initialized) return;
|
||||
|
||||
await this.loadEmailTemplates();
|
||||
this.initialized = true;
|
||||
console.log("Email Template Manager initialized successfully");
|
||||
// If initialization is in progress, wait for it
|
||||
if (this.initializationPromise) {
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
// Start initialization and store the promise
|
||||
this.initializationPromise = (async () => {
|
||||
await this.loadEmailTemplates();
|
||||
this.initialized = true;
|
||||
console.log("Email Template Manager initialized successfully");
|
||||
})();
|
||||
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,6 +53,14 @@ class TemplateManager {
|
||||
async loadEmailTemplates() {
|
||||
const templatesDir = path.join(__dirname, "..", "..", "..", "templates", "emails");
|
||||
|
||||
// Critical templates that must load for the app to function
|
||||
const criticalTemplates = [
|
||||
"emailVerificationToUser.html",
|
||||
"passwordResetToUser.html",
|
||||
"passwordChangedToUser.html",
|
||||
"personalInfoChangedToUser.html",
|
||||
];
|
||||
|
||||
try {
|
||||
const templateFiles = [
|
||||
"conditionCheckReminderToUser.html",
|
||||
@@ -41,6 +68,7 @@ class TemplateManager {
|
||||
"emailVerificationToUser.html",
|
||||
"passwordResetToUser.html",
|
||||
"passwordChangedToUser.html",
|
||||
"personalInfoChangedToUser.html",
|
||||
"lateReturnToCS.html",
|
||||
"damageReportToCS.html",
|
||||
"lostItemToCS.html",
|
||||
@@ -69,6 +97,8 @@ class TemplateManager {
|
||||
"forumCommentDeletionToAuthor.html",
|
||||
];
|
||||
|
||||
const failedTemplates = [];
|
||||
|
||||
for (const templateFile of templateFiles) {
|
||||
try {
|
||||
const templatePath = path.join(templatesDir, templateFile);
|
||||
@@ -84,16 +114,39 @@ class TemplateManager {
|
||||
console.error(
|
||||
` Template path: ${path.join(templatesDir, templateFile)}`
|
||||
);
|
||||
failedTemplates.push(templateFile);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Loaded ${this.templates.size} of ${templateFiles.length} email templates`
|
||||
);
|
||||
|
||||
// Check if critical templates are missing
|
||||
const missingCriticalTemplates = criticalTemplates.filter(
|
||||
(template) => !this.templates.has(path.basename(template, ".html"))
|
||||
);
|
||||
|
||||
if (missingCriticalTemplates.length > 0) {
|
||||
const error = new Error(
|
||||
`Critical email templates failed to load: ${missingCriticalTemplates.join(", ")}`
|
||||
);
|
||||
error.missingTemplates = missingCriticalTemplates;
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Warn if non-critical templates failed
|
||||
if (failedTemplates.length > 0) {
|
||||
console.warn(
|
||||
`⚠️ Non-critical templates failed to load: ${failedTemplates.join(", ")}`
|
||||
);
|
||||
console.warn("These templates will use fallback versions");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load email templates:", error);
|
||||
console.error("Templates directory:", templatesDir);
|
||||
console.error("Error stack:", error.stack);
|
||||
throw error; // Re-throw to fail server startup
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user