Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ workflows:
context : org-global
filters:
branches:
only: ['develop', 'migration-setup', 'pm-1613']
only: ['develop', 'migration-setup', 'pm-1611']
- deployProd:
context : org-global
filters:
Expand Down
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ export const TEMPLATE_IDS = {
INFORM_PM_COPILOT_APPLICATION_ACCEPTED: 'd-b35d073e302b4279a1bd208fcfe96f58',
COPILOT_ALREADY_PART_OF_PROJECT: 'd-003d41cdc9de4bbc9e14538e8f2e0585',
COPILOT_APPLICATION_ACCEPTED: 'd-eef5e7568c644940b250e76d026ced5b',
COPILOT_OPPORTUNITY_COMPLETED: 'd-dc448919d11b4e7d8b4ba351c4b67b8b',
COPILOT_OPPORTUNITY_CANCELED: 'd-2a67ba71e82f4d70891fe6989c3522a3'
}
export const REGEX = {
URL: /^(http(s?):\/\/)?(www\.)?[a-zA-Z0-9\.\-\_]+(\.[a-zA-Z]{2,15})+(\:[0-9]{2,5})?(\/[a-zA-Z0-9\_\-\s\.\/\?\%\#\&\=;]*)?$/, // eslint-disable-line
Expand Down
38 changes: 38 additions & 0 deletions src/routes/copilotOpportunity/assign.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,41 @@ const assignCopilotOpportunityValidations = {
}),
};

const sendEmailToAllApplicants = async (req, opportunity, copilotRequest, applicationId) => {
const allApplications = await models.Sequelize.CopilotApplication.findAll({
where: {
opportunityId: opportunity.id,
id: {
[Op.notIn]: [applicationId],
}
}
});

const userIds = allApplications.map(item => item.userId);

const users = await util.getMemberDetailsByUserIds(userIds, req.log, req.id);

users.forEach(async (user) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using forEach with an async function can lead to unexpected behavior because the asynchronous operations inside the loop won't be awaited. Consider using a for...of loop or Promise.all to handle asynchronous operations properly.

req.log.debug(`Sending email notification to copilots who are not accepted`);
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL;
const copilotPortalUrl = config.get('copilotPortalUrl');
const requestData = copilotRequest.data;
createEvent(emailEventType, {
data: {
opportunity_details_url: `${copilotPortalUrl}/opportunity`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL construction for opportunity_details_url might need to include the specific opportunity ID or other identifiers to ensure the link directs to the correct opportunity details page.

opportunity_title: requestData.opportunityTitle,
user_name: user ? user.handle : "",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider handling the case where user might be null or undefined more explicitly to avoid potential errors when accessing user.handle.

},
sendgrid_template_id: TEMPLATE_IDS.COPILOT_OPPORTUNITY_COMPLETED,
recipients: [user.email],
version: 'v3',
}, req.log);

req.log.debug(`Email sent to copilots who are not accepted`);
});

};

module.exports = [
validate(assignCopilotOpportunityValidations),
async (req, res, next) => {
Expand Down Expand Up @@ -134,6 +169,9 @@ module.exports = [
}, req.log);

req.log.debug(`Email sent`);

// Send email to all applicants about opportunity completion
await sendEmailToAllApplicants(req, opportunity, copilotRequest, application.id);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider handling potential errors from the sendEmailToAllApplicants function. If the email sending fails, it might be useful to log the error or take corrective actions.

};

const existingMember = activeMembers.find(item => item.userId === userId);
Expand Down
31 changes: 30 additions & 1 deletion src/routes/copilotOpportunity/delete.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
import _ from 'lodash';
import { Op } from 'sequelize';
import config from 'config';

import models from '../../models';
import util from '../../util';
import { COPILOT_APPLICATION_STATUS, COPILOT_OPPORTUNITY_STATUS, COPILOT_REQUEST_STATUS, EVENT, INVITE_STATUS, RESOURCES } from '../../constants';
import { CONNECT_NOTIFICATION_EVENT, COPILOT_APPLICATION_STATUS, COPILOT_OPPORTUNITY_STATUS, COPILOT_REQUEST_STATUS, EVENT, INVITE_STATUS, RESOURCES, TEMPLATE_IDS } from '../../constants';
import { createEvent } from '../../services/busApi';
import { PERMISSION } from '../../permissions/constants';


const sendEmailToAllApplicants = async (req, copilotRequest, applications) => {
const userIds = applications.map(item => item.userId);
const users = await util.getMemberDetailsByUserIds(userIds, req.log, req.id);

users.forEach(async (user) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using Promise.all to handle asynchronous operations in the users.forEach loop. This will ensure that all email sending operations are completed before proceeding, and it will also handle errors more effectively.

req.log.debug(`Sending email notification to copilots who applied`);
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL;
const copilotPortalUrl = config.get('copilotPortalUrl');
const requestData = copilotRequest.data;
createEvent(emailEventType, {
data: {
opportunity_details_url: `${copilotPortalUrl}/opportunity`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL concatenation for opportunity_details_url may lead to incorrect URLs if copilotPortalUrl does not end with a slash. Consider using a URL library or ensuring the base URL ends with a slash to prevent potential issues.

opportunity_title: requestData.opportunityTitle,
user_name: user ? user.handle : "",
},
sendgrid_template_id: TEMPLATE_IDS.COPILOT_OPPORTUNITY_CANCELED,
recipients: [user.email],
version: 'v3',
}, req.log);

req.log.debug(`Email sent to copilots who applied`);
});

};

module.exports = [
(req, res, next) => {
if (!util.hasPermissionByReq(PERMISSION.CANCEL_COPILOT_OPPORTUNITY, req)) {
Expand Down Expand Up @@ -93,6 +120,8 @@ module.exports = [
invite.toJSON());
}

await sendEmailToAllApplicants(req, copilotRequest, applications)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the function sendEmailToAllApplicants is being called here, but there is no error handling around this asynchronous operation. Consider adding a try-catch block to handle any potential errors that may occur during the email sending process.


res.status(200).send({ id: opportunity.id });
})

Expand Down