Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/refactor submission approved #34

Merged
merged 9 commits into from
Jan 9, 2024
15 changes: 0 additions & 15 deletions site/gatsby-site/cypress/e2e/integration/apps/submitted.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,21 +171,6 @@ describe('Submitted reports', () => {
}
);

cy.conditionalIntercept(
'**/graphql',
(req) =>
req.body.operationName == 'UpsertSubscription' &&
req.body.variables?.query?.type === SUBSCRIPTION_TYPE.submissionPromoted,
'UpsertSubscriptionPromoted',
{
data: {
upsertOneSubscription: {
_id: 'dummyIncidentId',
},
},
}
);

cy.get('select[data-cy="promote-select"]').as('dropdown');

cy.get('@dropdown').select('Incident');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ const pendingNotifications = [
type: SUBSCRIPTION_TYPE.submissionPromoted,
incident_id: 217,
processed: false,
userId: '63320ce63ec803072c9f5291',
},
{
_id: '63616f82d0db19c07d081401',
type: SUBSCRIPTION_TYPE.submissionPromoted,
incident_id: 218,
processed: false,
userId: '63320ce63ec803072c9f5291',
},
//Duplicated pending notification
{
_id: '63616f82d0db19c07d081402',
type: SUBSCRIPTION_TYPE.submissionPromoted,
incident_id: 218,
processed: false,
userId: '63320ce63ec803072c9f5291',
},
];

Expand Down Expand Up @@ -73,9 +76,7 @@ describe('Process New Promotions Pending Notifications', () => {

const sendEmailCallArgs = sendEmailCalls[i].args[1];

const userIds = subscriptions
.filter((s) => s.incident_id === pendingNotification.incident_id)
.map((subscription) => subscription.userId);
const userIds = pendingNotifications.map((n) => n.userId);

const incident = incidents.find((i) => i.incident_id == pendingNotification.incident_id);

Expand Down Expand Up @@ -107,43 +108,32 @@ describe('Process New Promotions Pending Notifications', () => {
});

it('New Promotions - Should send pending submissions promoted notifications', () => {
const { notificationsCollection, subscriptionsCollection, incidentsCollection } =
stubEverything({
subscriptionType: SUBSCRIPTION_TYPE.submissionPromoted,
pendingNotifications,
subscriptions,
});
const { notificationsCollection, incidentsCollection } = stubEverything({
subscriptionType: SUBSCRIPTION_TYPE.submissionPromoted,
pendingNotifications,
subscriptions,
});

cy.wrap(processNotifications()).then(() => {
expect(notificationsCollection.find.getCall(3).args[0]).to.deep.equal({
processed: false,
type: SUBSCRIPTION_TYPE.submissionPromoted,
});

for (const subscription of subscriptions) {
for (const notification of pendingNotifications) {
expect(global.context.functions.execute).to.be.calledWith('getUser', {
userId: subscription.userId,
userId: notification.userId,
});
}

for (let i = 0; i < uniquePendingNotifications.length; i++) {
const pendingNotification = uniquePendingNotifications[i];

expect(
subscriptionsCollection.find.getCall(i).args[0],
'Get subscriptions for Incident'
).to.deep.equal({
type: SUBSCRIPTION_TYPE.submissionPromoted,
incident_id: pendingNotification.incident_id,
});

expect(incidentsCollection.findOne.getCall(i).args[0], 'Find incident').to.deep.equal({
incident_id: pendingNotification.incident_id,
});

const userIds = subscriptions
.filter((s) => s.incident_id === pendingNotification.incident_id)
.map((subscription) => subscription.userId);
const userIds = pendingNotifications.map((n) => n.userId);

const incident = incidents.find((i) => i.incident_id == pendingNotification.incident_id);

Expand Down Expand Up @@ -176,7 +166,7 @@ describe('Process New Promotions Pending Notifications', () => {
});

it('New Promotions - Should mark pending notifications as processed if there are no subscribers', () => {
const { notificationsCollection, subscriptionsCollection } = stubEverything({
const { notificationsCollection } = stubEverything({
subscriptionType: SUBSCRIPTION_TYPE.submissionPromoted,
pendingNotifications,
subscriptions: [],
Expand All @@ -203,16 +193,9 @@ describe('Process New Promotions Pending Notifications', () => {
type: SUBSCRIPTION_TYPE.submissionPromoted,
});

expect(global.context.functions.execute).not.to.be.called;

for (let i = 0; i < uniquePendingNotifications.length; i++) {
const pendingNotification = uniquePendingNotifications[i];

expect(subscriptionsCollection.find.getCall(i).args[0]).to.deep.equal({
type: SUBSCRIPTION_TYPE.submissionPromoted,
incident_id: pendingNotification.incident_id,
});

expect(notificationsCollection.updateOne.getCall(i).args[0]).to.deep.equal({
_id: pendingNotification._id,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,11 @@ describe('Functions', () => {
modifiedBy: submission.user,
});

expect(subscriptionsCollection.insertOne.firstCall.args[0]).to.deep.equal({
expect(notificationsCollection.insertOne.firstCall.args[0]).to.deep.equal({
type: SUBSCRIPTION_TYPE.submissionPromoted,
incident_id: 2,
userId: 'user1',
processed: false,
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
{}
{
"userId": {
"ref": "#/relationship/mongodb-atlas/customData/users",
"source_key": "userId",
"foreign_key": "userId",
"is_list": false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
},
"type": {
"bsonType": "string"
},
"userId": {
"bsonType": "string"
}
},
"title": "notification"
Expand Down
143 changes: 65 additions & 78 deletions site/realm/functions/processNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,54 +240,54 @@ exports = async function () {
if (!uniqueNotifications.some(n => n.incident_id === pendingNotification.incident_id && n.type === pendingNotification.type)) {
uniqueNotifications.push(pendingNotification);

try {
const subscriptionsToIncidentUpdates = await subscriptionsCollection.find({
type: 'incident',
incident_id: pendingNotification.incident_id
}).toArray();
try {
const subscriptionsToIncidentUpdates = await subscriptionsCollection.find({
type: 'incident',
incident_id: pendingNotification.incident_id
}).toArray();

// Process subscriptions to Incident updates
if (subscriptionsToIncidentUpdates.length > 0) {
// Process subscriptions to Incident updates
if (subscriptionsToIncidentUpdates.length > 0) {

const userIds = subscriptionsToIncidentUpdates.map((subscription) => subscription.userId);
const userIds = subscriptionsToIncidentUpdates.map((subscription) => subscription.userId);

const uniqueUserIds = [...new Set(userIds)];
const uniqueUserIds = [...new Set(userIds)];

const recipients = await getRecipients(uniqueUserIds);
const recipients = await getRecipients(uniqueUserIds);

const incident = await incidentsCollection.findOne({ incident_id: pendingNotification.incident_id });
const incident = await incidentsCollection.findOne({ incident_id: pendingNotification.incident_id });

const newReportNumber = pendingNotification.report_number;
const newReportNumber = pendingNotification.report_number;

const newReport = newReportNumber ? await reportsCollection.findOne({ report_number: newReportNumber }) : null;
const newReport = newReportNumber ? await reportsCollection.findOne({ report_number: newReportNumber }) : null;

//Send email notification
const sendEmailParams = {
recipients,
subject: 'Incident {{incidentId}} was updated',
dynamicData: {
incidentId: `${incident.incident_id}`,
incidentTitle: incident.title,
incidentUrl: `https://incidentdatabase.ai/cite/${incident.incident_id}`,
reportUrl: `https://incidentdatabase.ai/cite/${incident.incident_id}#r${newReportNumber}`,
reportTitle: newReportNumber ? newReport.title : '',
reportAuthor: newReportNumber && newReport.authors[0] ? newReport.authors[0] : '',
},
// Template value from function name sufix from "site/realm/functions/config.json"
templateId: newReportNumber ? 'NewReportAddedToAnIncident' : 'IncidentUpdate',
};
//Send email notification
const sendEmailParams = {
recipients,
subject: 'Incident {{incidentId}} was updated',
dynamicData: {
incidentId: `${incident.incident_id}`,
incidentTitle: incident.title,
incidentUrl: `https://incidentdatabase.ai/cite/${incident.incident_id}`,
reportUrl: `https://incidentdatabase.ai/cite/${incident.incident_id}#r${newReportNumber}`,
reportTitle: newReportNumber ? newReport.title : '',
reportAuthor: newReportNumber && newReport.authors[0] ? newReport.authors[0] : '',
},
// Template value from function name sufix from "site/realm/functions/config.json"
templateId: newReportNumber ? 'NewReportAddedToAnIncident' : 'IncidentUpdate',
};

await context.functions.execute('sendEmail', sendEmailParams);
await context.functions.execute('sendEmail', sendEmailParams);

console.log(`Incident ${incident.incident_id} updates: Pending notification was processed.`);
}
} catch (error) {
// If there is an error sending the email > Mark the notification as not processed
await markNotificationsAsNotProcessed(notificationsCollection, [pendingNotification]);
console.log(`Incident ${incident.incident_id} updates: Pending notification was processed.`);
}
} catch (error) {
// If there is an error sending the email > Mark the notification as not processed
await markNotificationsAsNotProcessed(notificationsCollection, [pendingNotification]);

error.message = `[Process Pending Notifications: Incidents Updates]: ${error.message}`;
context.functions.execute('logRollbar', { error });
}
error.message = `[Process Pending Notifications: Incidents Updates]: ${error.message}`;
context.functions.execute('logRollbar', { error });
}
}
}
}
Expand All @@ -299,7 +299,6 @@ exports = async function () {
context.functions.execute('logRollbar', { error });
}


// Notifications to New Promotions
try {

Expand All @@ -310,63 +309,51 @@ exports = async function () {

result += pendingNotificationsToNewPromotions.length;

const userIds = pendingNotificationsToNewPromotions.map((subscription) => subscription.userId);

const uniqueUserIds = [...new Set(userIds)];

const recipients = await getRecipients(uniqueUserIds);

let uniqueNotifications = [];

for (const pendingNotification of pendingNotificationsToNewPromotions) {

// Mark the notification as processed before sending the email
await markNotificationsAsProcessed(notificationsCollection, [pendingNotification]);

// Process each Incident only once
if (!uniqueNotifications.includes(pendingNotification.incident_id)) {
uniqueNotifications.push(pendingNotification.incident_id);

// Finds all subscriptions to New Promotions for this Incident
const subscriptionsToNewPromotions = await subscriptionsCollection.find({
type: 'submission-promoted',
incident_id: pendingNotification.incident_id
}).toArray();

// Process subscriptions to New Incidents
if (subscriptionsToNewPromotions.length > 0) {

const userIds = subscriptionsToNewPromotions.map((subscription) => subscription.userId);

const uniqueUserIds = [...new Set(userIds)];

const recipients = await getRecipients(uniqueUserIds);

try {
const incident = await incidentsCollection.findOne({ incident_id: pendingNotification.incident_id });

//Send email notification
const sendEmailParams = {
recipients,
subject: 'Your submission has been approved!',
dynamicData: {
incidentId: `${incident.incident_id}`,
incidentTitle: incident.title,
incidentUrl: `https://incidentdatabase.ai/cite/${incident.incident_id}`,
incidentDescription: incident.description,
incidentDate: incident.date,
},
templateId: 'SubmissionApproved' // Template value from function name sufix from "site/realm/functions/config.json"
};
try {
const incident = await incidentsCollection.findOne({ incident_id: pendingNotification.incident_id });

await context.functions.execute('sendEmail', sendEmailParams);
//Send email notification
const sendEmailParams = {
recipients,
subject: 'Your submission has been approved!',
dynamicData: {
incidentId: `${incident.incident_id}`,
incidentTitle: incident.title,
incidentUrl: `https://incidentdatabase.ai/cite/${incident.incident_id}`,
incidentDescription: incident.description,
incidentDate: incident.date,
},
templateId: 'SubmissionApproved' // Template value from function name sufix from "site/realm/functions/config.json"
};

console.log(`Promoted notification for incident ${incident.incident_id} was processed.`);
await context.functions.execute('sendEmail', sendEmailParams);

} catch (error) {
// If there is an error sending the email > Mark the notification as not processed
await markNotificationsAsNotProcessed(notificationsCollection, [pendingNotification]);
} catch (error) {
// If there is an error sending the email > Mark the notification as not processed
await markNotificationsAsNotProcessed(notificationsCollection, [pendingNotification]);

error.message = `[Process Pending Notifications: Submission Promoted]: ${error.message}`;
context.functions.execute('logRollbar', { error });
}
error.message = `[Process Pending Notifications: Submission Promoted]: ${error.message}`;
context.functions.execute('logRollbar', { error });
}
}
}

console.log(`New Promotions: ${pendingNotificationsToNewPromotions.length} pending notifications were processed.`);
}
else {
Expand Down
8 changes: 2 additions & 6 deletions site/realm/functions/promoteSubmissionToReport.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,12 @@ exports = async (input) => {
await incidents.insertOne({ ...newIncident, incident_id: BSON.Int32(newIncident.incident_id) });

if (submission.user) {
await subscriptionsCollection.insertOne({
type: 'submission-promoted',
incident_id: BSON.Int32(newIncident.incident_id),
userId: submission.user
});

await notificationsCollection.insertOne({
type: 'submission-promoted',
incident_id: BSON.Int32(newIncident.incident_id),
processed: false
processed: false,
userId: submission.user
});
}

Expand Down
Loading