feature/IO-3096-GlobalNotifications - Code Review Part 2

This commit is contained in:
Dave Richer
2025-03-03 23:11:03 -05:00
parent a57abec81b
commit 555bedbb6c
3 changed files with 67 additions and 58 deletions

View File

@@ -23,7 +23,7 @@ const FILTER_SELF_FROM_WATCHERS = process.env?.FILTER_SELF_FROM_WATCHERS === "tr
* Queries job watchers and notification settings before triggering scenario builders.
*
* @param {Object} req - The request object containing event data, trigger, table, and logger.
* @param {string} jobIdField - The field name used to extract the job ID from the event data.
* @param {string} jobIdField - The field path (e.g., "req.body.event.new.id") to extract the job ID.
* @returns {Promise<void>} Resolves when the parsing and notification dispatching process is complete.
* @throws {Error} If required request fields (event data, trigger, or table) or body shop data are missing.
*/
@@ -34,8 +34,9 @@ const scenarioParser = async (req, jobIdField) => {
// Validate we know what user committed the action that fired the parser
const hasuraUserId = event?.session_variables?.["x-hasura-user-id"];
// Bail if we don't know
// Bail if we don't know who started the scenario
if (!hasuraUserId) {
logger.log("No Hasura user ID found, skipping notification parsing", "info", "notifications");
return;
}
@@ -44,18 +45,25 @@ const scenarioParser = async (req, jobIdField) => {
throw new Error("Missing required request fields: event data, trigger, or table.");
}
// Step 1: Parse the event data to extract details like job ID and changed fields
const eventData = await eventParser({
newData: event.data.new,
oldData: event.data.old,
trigger,
table,
jobIdField
});
// Step 1a: Extract just the jobId using the provided jobIdField
let jobId = null;
if (jobIdField) {
let keyName = jobIdField;
const prefix = "req.body.event.new.";
if (keyName.startsWith(prefix)) {
keyName = keyName.slice(prefix.length);
}
jobId = event.data.new[keyName] || (event.data.old && event.data.old[keyName]) || null;
}
if (!jobId) {
logger.log(`No jobId found using path "${jobIdField}", skipping notification parsing`, "info", "notifications");
return;
}
// Step 2: Query job watchers associated with the job ID using GraphQL
const watcherData = await gqlClient.request(queries.GET_JOB_WATCHERS, {
jobid: eventData.jobId
jobid: jobId
});
// Transform watcher data into a simplified format with email and employee details
@@ -73,9 +81,19 @@ const scenarioParser = async (req, jobIdField) => {
// Exit early if no job watchers are found for this job
if (isEmpty(jobWatchers)) {
logger.log(`No watchers found for jobId "${jobId}", skipping notification parsing`, "info", "notifications");
return;
}
// Step 1b: Perform the full event diff now that we know there are watchers
const eventData = await eventParser({
newData: event.data.new,
oldData: event.data.old,
trigger,
table,
jobId
});
// Step 3: Extract body shop information from the job data
const bodyShopId = watcherData?.job?.bodyshop?.id;
const bodyShopName = watcherData?.job?.bodyshop?.shopname;
@@ -97,6 +115,11 @@ const scenarioParser = async (req, jobIdField) => {
// Exit early if no matching scenarios are identified
if (isEmpty(matchingScenarios)) {
logger.log(
`No matching scenarios found for jobId "${jobId}", skipping notification dispatch`,
"info",
"notifications"
);
return;
}
@@ -117,6 +140,11 @@ const scenarioParser = async (req, jobIdField) => {
// Exit early if no notification associations are found
if (isEmpty(associationsData?.associations)) {
logger.log(
`No notification associations found for jobId "${jobId}", skipping notification dispatch`,
"info",
"notifications"
);
return;
}
@@ -150,6 +178,11 @@ const scenarioParser = async (req, jobIdField) => {
// Exit early if no scenarios have eligible watchers after filtering
if (isEmpty(finalScenarioData?.matchingScenarios)) {
logger.log(
`No eligible watchers after filtering for jobId "${jobId}", skipping notification dispatch`,
"info",
"notifications"
);
return;
}
@@ -204,35 +237,29 @@ const scenarioParser = async (req, jobIdField) => {
);
}
// Exit early if no scenarios are ready to dispatch
if (isEmpty(scenariosToDispatch)) {
logger.log(`No scenarios to dispatch for jobId "${jobId}" after building`, "info", "notifications");
return;
}
// Step 9: Dispatch email notifications to the email queue
// Step 8: Dispatch email notifications to the email queue
const emailsToDispatch = scenariosToDispatch.map((scenario) => scenario?.email);
if (!isEmpty(emailsToDispatch)) {
dispatchEmailsToQueue({
emailsToDispatch,
logger
}).catch((e) =>
// Log any errors encountered during email dispatching
dispatchEmailsToQueue({ emailsToDispatch, logger }).catch((e) =>
logger.log("Something went wrong dispatching emails to the Email Notification Queue", "error", "queue", null, {
message: e?.message
message: e?.message,
stack: e?.stack
})
);
}
// Step 10: Dispatch app notifications to the app queue
// Step 9: Dispatch app notifications to the app queue
const appsToDispatch = scenariosToDispatch.map((scenario) => scenario?.app);
if (!isEmpty(appsToDispatch)) {
dispatchAppsToQueue({
appsToDispatch,
logger
}).catch((e) =>
// Log any errors encountered during app notification dispatching
dispatchAppsToQueue({ appsToDispatch, logger }).catch((e) =>
logger.log("Something went wrong dispatching apps to the App Notification Queue", "error", "queue", null, {
message: e?.message
message: e?.message,
stack: e?.stack
})
);
}