355 lines
11 KiB
JavaScript
355 lines
11 KiB
JavaScript
const path = require("path");
|
|
require("dotenv").config({
|
|
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
|
|
});
|
|
const InstanceManager = require("../utils/instanceMgr").default;
|
|
const logger = require("../utils/logger");
|
|
const client = require("../graphql-client/graphql-client").client;
|
|
const queries = require("../graphql-client/queries");
|
|
const generateEmailTemplate = require("./generateTemplate");
|
|
const moment = require("moment-timezone");
|
|
const { taskEmailQueue } = require("./tasksEmailsQueue");
|
|
const mailer = require("./mailer");
|
|
|
|
// Initialize the Tasks Email Queue
|
|
const tasksEmailQueue = taskEmailQueue();
|
|
|
|
// Cleanup function for the Tasks Email Queue
|
|
const tasksEmailQueueCleanup = async () => {
|
|
try {
|
|
// Example async operation
|
|
console.log("Performing Tasks Email Reminder process cleanup...");
|
|
await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve()));
|
|
} catch (err) {
|
|
console.error("Tasks Email Reminder process cleanup failed:", err);
|
|
}
|
|
};
|
|
|
|
if (process.env.NODE_ENV !== "development") {
|
|
// Handling SIGINT (e.g., Ctrl+C)
|
|
process.on("SIGINT", async () => {
|
|
await tasksEmailQueueCleanup();
|
|
});
|
|
// Handling SIGTERM (e.g., sent by system shutdown)
|
|
process.on("SIGTERM", async () => {
|
|
await tasksEmailQueueCleanup();
|
|
});
|
|
// Handling uncaught exceptions
|
|
process.on("uncaughtException", async (err) => {
|
|
await tasksEmailQueueCleanup();
|
|
throw err;
|
|
});
|
|
// Handling unhandled promise rejections
|
|
process.on("unhandledRejection", async (reason, promise) => {
|
|
await tasksEmailQueueCleanup();
|
|
throw reason;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Format the date for the email.
|
|
* @param date
|
|
* @returns {string|string}
|
|
*/
|
|
const formatDate = (date) => {
|
|
return date ? `| Due on: ${moment(date).format("MM/DD/YYYY")}` : "";
|
|
};
|
|
|
|
const formatPriority = (priority) => {
|
|
if (priority === 1) {
|
|
return "High";
|
|
} else if (priority === 3) {
|
|
return "Low";
|
|
} else {
|
|
return "Medium";
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Generate the email template arguments.
|
|
* @param title
|
|
* @param priority
|
|
* @param description
|
|
* @param dueDate
|
|
* @param bodyshop
|
|
* @param job
|
|
* @param taskId
|
|
* @returns {{header, body: string, subHeader: string}}
|
|
*/
|
|
|
|
const getEndpoints = (bodyshop) =>
|
|
InstanceManager({
|
|
imex: process.env?.NODE_ENV === "test" ? "https://test.imex.online" : "https://imex.online",
|
|
rome:
|
|
bodyshop?.convenient_company === "promanager"
|
|
? process.env?.NODE_ENV === "test"
|
|
? "https//test.promanager.web-est.com"
|
|
: "https://promanager.web-est.com"
|
|
: process.env?.NODE_ENV === "test"
|
|
? "https//test.romeonline.io"
|
|
: "https://romeonline.io"
|
|
});
|
|
|
|
const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine) => {
|
|
const endPoints = getEndpoints(bodyshop);
|
|
return {
|
|
header: title,
|
|
subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)}`,
|
|
body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}<br>${description ? description.concat("<br>") : ""}<a href="${endPoints}/manage/tasks/alltasks?taskid=${taskId}">View this task.</a>`,
|
|
dateLine
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Send the email.
|
|
* @param type
|
|
* @param to
|
|
* @param subject
|
|
* @param html
|
|
* @param taskIds
|
|
* @param successCallback
|
|
* @param requestInstance
|
|
*/
|
|
const sendMail = (type, to, subject, html, taskIds, successCallback, requestInstance) => {
|
|
const fromEmails = InstanceManager({
|
|
imex: "ImEX Online <noreply@imex.online>",
|
|
rome:
|
|
requestInstance === "promanager"
|
|
? "ProManager <noreply@promanager.web-est.com>"
|
|
: "Rome Online <noreply@romeonline.io>"
|
|
});
|
|
|
|
mailer.sendMail(
|
|
{
|
|
from: fromEmails,
|
|
to,
|
|
subject,
|
|
html
|
|
},
|
|
(error, info) => {
|
|
if (info) {
|
|
if (typeof successCallback === "function" && taskIds && taskIds.length) {
|
|
successCallback(taskIds);
|
|
}
|
|
} else {
|
|
logger.log(`task-${type}-email-failure`, "error", null, null, error);
|
|
}
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Send an email to the assigned user.
|
|
* @param req
|
|
* @param res
|
|
* @returns {Promise<*>}
|
|
*/
|
|
const taskAssignedEmail = async (req, res) => {
|
|
// We have no event Data, bail
|
|
if (!req?.body?.event?.data?.new) {
|
|
return res.status(400).json({ message: "No data in the event body" });
|
|
}
|
|
|
|
const { new: newTask } = req.body.event.data;
|
|
|
|
// This is not a new task, but a reassignment.
|
|
const dirty = req.body.event.data?.old && req.body.event.data?.old?.assigned_to;
|
|
|
|
//Query to get the employee assigned currently.
|
|
const { tasks_by_pk } = await client.request(queries.QUERY_TASK_BY_ID, {
|
|
id: newTask.id
|
|
});
|
|
|
|
const dateLine = moment().tz(tasks_by_pk.bodyshop.timezone).format("M/DD/YYYY @ hh:mm a");
|
|
|
|
sendMail(
|
|
"assigned",
|
|
tasks_by_pk.assigned_to_employee.user_email,
|
|
`A ${formatPriority(newTask.priority)} priority task has been ${dirty ? "reassigned to" : "created for"} you - ${newTask.title}`,
|
|
generateEmailTemplate(
|
|
generateTemplateArgs(
|
|
newTask.title,
|
|
newTask.priority,
|
|
newTask.description,
|
|
newTask.due_date,
|
|
tasks_by_pk.bodyshop,
|
|
tasks_by_pk.job,
|
|
newTask.id,
|
|
dateLine
|
|
)
|
|
),
|
|
null,
|
|
null,
|
|
tasks_by_pk.bodyshop.convenient_company
|
|
);
|
|
|
|
// We return success regardless because we don't want to block the event trigger.
|
|
res.status(200).json({ success: true });
|
|
};
|
|
|
|
/**
|
|
* Send an email to remind the user of their tasks.
|
|
* @param req
|
|
* @param res
|
|
* @returns {Promise<*>}
|
|
*/
|
|
const tasksRemindEmail = async (req, res) => {
|
|
try {
|
|
const tasksRequest = await client.request(queries.QUERY_REMIND_TASKS, {
|
|
time: moment().add(1, "minutes").toISOString()
|
|
});
|
|
|
|
// No tasks present in the database, bail.
|
|
if (!tasksRequest?.tasks || !tasksRequest?.tasks.length) {
|
|
return res.status(200).json({ message: "No tasks to remind" });
|
|
}
|
|
|
|
// Group tasks by assigned_to, to avoid sending multiple emails to the same recipient.
|
|
const groupedTasks = tasksRequest.tasks.reduce((acc, task) => {
|
|
const key = task.assigned_to_employee.user_email;
|
|
if (!acc[key]) {
|
|
acc[key] = [];
|
|
}
|
|
acc[key].push(task);
|
|
return acc;
|
|
}, {});
|
|
|
|
// No grouped tasks, bail.
|
|
if (Object.keys(groupedTasks).length === 0) {
|
|
return res.status(200).json({ message: "No tasks to remind" });
|
|
}
|
|
|
|
// Build an aggregate data object containing email and the count of tasks assigned to them.
|
|
const recipientCounts = Object.keys(groupedTasks).map((key) => {
|
|
return {
|
|
email: key,
|
|
count: groupedTasks[key].length
|
|
};
|
|
});
|
|
|
|
// Iterate over all recipients and send the email.
|
|
recipientCounts.forEach((recipient) => {
|
|
const fromEmails = InstanceManager({
|
|
imex: "ImEX Online <noreply@imex.online>",
|
|
rome:
|
|
tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager"
|
|
? "ProManager <noreply@promanager.web-est.com>"
|
|
: "Rome Online <noreply@romeonline.io>"
|
|
});
|
|
|
|
const emailData = {
|
|
from: fromEmails,
|
|
to: recipient.email
|
|
};
|
|
|
|
const taskIds = groupedTasks[recipient.email].map((task) => task.id);
|
|
|
|
const dateLine = moment().tz(tasksRequest?.tasks[0].bodyshop.timezone).format("M/DD/YYYY @ hh:mm a");
|
|
|
|
// There is only the one email to send to this author.
|
|
if (recipient.count === 1) {
|
|
const onlyTask = groupedTasks[recipient.email][0];
|
|
|
|
emailData.subject =
|
|
`New ${formatPriority(onlyTask.priority)} Priority Task Reminder - ${onlyTask.title} ${onlyTask.due_date ? `- ${formatDate(onlyTask.due_date)}` : ""}`.trim();
|
|
|
|
emailData.html = generateEmailTemplate(
|
|
generateTemplateArgs(
|
|
onlyTask.title,
|
|
onlyTask.priority,
|
|
onlyTask.description,
|
|
onlyTask.due_date,
|
|
onlyTask.bodyshop,
|
|
onlyTask.job,
|
|
onlyTask.id,
|
|
dateLine
|
|
)
|
|
);
|
|
}
|
|
// There are multiple emails to send to this author.
|
|
else {
|
|
const endPoints = InstanceManager({
|
|
imex: process.env?.NODE_ENV === "test" ? "https://test.imex.online" : "https://imex.online",
|
|
rome:
|
|
tasksRequest?.tasks[0].bodyshop.convenient_company === "promanager"
|
|
? process.env?.NODE_ENV === "test"
|
|
? "https//test.promanager.web-est.com"
|
|
: "https://promanager.web-est.com"
|
|
: process.env?.NODE_ENV === "test"
|
|
? "https//test.romeonline.io"
|
|
: "https://romeonline.io"
|
|
});
|
|
|
|
const allTasks = groupedTasks[recipient.email];
|
|
emailData.subject = `New Tasks Reminder - ${allTasks.length} Tasks require your attention`;
|
|
emailData.html = generateEmailTemplate({
|
|
header: `${allTasks.length} Tasks require your attention`,
|
|
subHeader: `Please click on the Tasks below to view the Task.`,
|
|
dateLine,
|
|
body: `<ul>
|
|
${allTasks
|
|
.map((task) =>
|
|
`<li><a href="${endPoints}/manage/tasks/alltasks?taskid=${task.id}">${task.title} - Priority: ${formatPriority(task.priority)} ${task.due_date ? `${formatDate(task.due_date)}` : ""} | Bodyshop: ${task.bodyshop.shopname}</a></li>`.trim()
|
|
)
|
|
.join("")}
|
|
</ul>`
|
|
});
|
|
}
|
|
|
|
if (emailData?.subject && emailData?.html) {
|
|
// Send Email
|
|
sendMail(
|
|
"remind",
|
|
emailData.to,
|
|
emailData.subject,
|
|
emailData.html,
|
|
taskIds,
|
|
(taskIds) => {
|
|
for (const taskId of taskIds) {
|
|
tasksEmailQueue.push(taskId);
|
|
}
|
|
},
|
|
tasksRequest?.tasks[0].bodyshop.convenient_company
|
|
);
|
|
}
|
|
});
|
|
|
|
// Sixth step would be to set the remind_at_sent to the current time.
|
|
res.status(200).json({ status: "success" });
|
|
} catch (err) {
|
|
res.status(500).json({
|
|
status: "error",
|
|
message: `Something went wrong sending Task Reminders: ${err.message || "An error occurred"}`
|
|
});
|
|
}
|
|
};
|
|
|
|
// Note: Uncomment this to test locally, it will call the remind_at email check every 20 seconds
|
|
// const callTaskRemindEmailInternally = () => {
|
|
// const req = {
|
|
// body: {
|
|
// // You can mock any request data here if needed
|
|
// }
|
|
// };
|
|
//
|
|
// const res = {
|
|
// status: (code) => {
|
|
// return {
|
|
// json: (data) => {
|
|
// console.log(`Response Status: ${code}`, data);
|
|
// }
|
|
// };
|
|
// }
|
|
// };
|
|
//
|
|
// // Call the taskRemindEmail function with mock req and res
|
|
// tasksRemindEmail(req, res);
|
|
// };
|
|
// setInterval(callTaskRemindEmailInternally, 20000);
|
|
|
|
module.exports = {
|
|
taskAssignedEmail,
|
|
tasksRemindEmail,
|
|
getEndpoints
|
|
};
|