Skip to content

Commit 0db2d55

Browse files
committed
add logging
1 parent 579103f commit 0db2d55

File tree

2 files changed

+147
-139
lines changed

2 files changed

+147
-139
lines changed
Lines changed: 91 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import _ from 'lodash';
21
import config from 'config';
32
import moment from 'moment';
43
import { Op } from 'sequelize';
54

65
import models from '../../models';
7-
import { CONNECT_NOTIFICATION_EVENT, COPILOT_OPPORTUNITY_STATUS, COPILOT_REQUEST_STATUS, TEMPLATE_IDS, USER_ROLE } from '../../constants';
6+
import {
7+
CONNECT_NOTIFICATION_EVENT,
8+
COPILOT_OPPORTUNITY_STATUS,
9+
COPILOT_REQUEST_STATUS,
10+
TEMPLATE_IDS, USER_ROLE,
11+
} from '../../constants';
812
import util from '../../util';
913
import { createEvent } from '../../services/busApi';
1014
import { getCopilotTypeLabel } from '../../utils/copilot';
@@ -17,85 +21,91 @@ const resolveTransaction = (transaction, callback) => {
1721
return models.sequelize.transaction(callback);
1822
};
1923

20-
module.exports = (req, data, existingTransaction) => {
24+
module.exports = async (req, data, existingTransaction) => {
2125
const { projectId, copilotRequestId, opportunityTitle, type, startDate } = data;
2226

23-
return resolveTransaction(existingTransaction, transaction =>
24-
models.Project.findOne({
25-
where: { id: projectId, deletedAt: { $eq: null } },
26-
}, { transaction })
27-
.then((existingProject) => {
28-
if (!existingProject) {
29-
const err = new Error(`active project not found for project id ${projectId}`);
30-
err.status = 404;
31-
throw err;
32-
}
33-
return models.CopilotRequest.findByPk(copilotRequestId, { transaction })
34-
.then((existingCopilotRequest) => {
35-
if (!existingCopilotRequest) {
36-
const err = new Error(`no active copilot request found for copilot request id ${copilotRequestId}`);
37-
err.status = 404;
38-
throw err;
39-
}
40-
41-
return existingCopilotRequest.update({
42-
status: COPILOT_REQUEST_STATUS.APPROVED,
43-
}, { transaction }).then(() => models.CopilotOpportunity
44-
.findOne({
45-
where: {
46-
projectId,
47-
type: data.type,
48-
status: {
49-
[Op.in]: [COPILOT_OPPORTUNITY_STATUS.ACTIVE],
50-
}
51-
},
52-
})
53-
.then((existingCopilotOpportunityOfSameType) => {
54-
if (existingCopilotOpportunityOfSameType) {
55-
const err = new Error('There\'s an active opportunity of same type already!');
56-
_.assign(err, {
57-
status: 403,
58-
});
59-
throw err;
60-
}
61-
return models.CopilotOpportunity
62-
.create(data, { transaction });
63-
}))
64-
.then(async (opportunity) => {
65-
const roles = await util.getRolesByRoleName(USER_ROLE.TC_COPILOT, req.log, req.id);
66-
const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id);
67-
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL;
68-
const copilotPortalUrl = config.get('copilotPortalUrl');
69-
req.log.info("Sending emails to all copilots about new opportunity");
70-
71-
const sendNotification = (userName, recipient) => createEvent(emailEventType, {
72-
data: {
73-
user_name: userName,
74-
opportunity_details_url: `${copilotPortalUrl}/opportunity/${opportunity.id}`,
75-
work_manager_url: config.get('workManagerUrl'),
76-
opportunity_type: getCopilotTypeLabel(type),
77-
opportunity_title: opportunityTitle,
78-
start_date: moment(startDate).format("DD-MM-YYYY"),
79-
},
80-
sendgrid_template_id: TEMPLATE_IDS.CREATE_REQUEST,
81-
recipients: [recipient],
82-
version: 'v3',
83-
}, req.log);
84-
85-
subjects.forEach(subject => sendNotification(subject.handle, subject.email));
86-
87-
// send email to notify via slack
88-
sendNotification('Copilots', config.copilotsSlackEmail);
89-
90-
req.log.info("Finished sending emails to copilots");
91-
92-
return opportunity;
93-
})
94-
.catch((err) => {
95-
transaction.rollback();
96-
return Promise.reject(err);
97-
});
98-
});
99-
}),
100-
);
27+
return resolveTransaction(existingTransaction, async (transaction) => {
28+
try {
29+
req.log.debug('approveRequest: finding project', { projectId });
30+
31+
const existingProject = await models.Project.findOne({
32+
where: { id: projectId, deletedAt: { $eq: null } },
33+
transaction,
34+
});
35+
36+
if (!existingProject) {
37+
const err = new Error(`active project not found for project id ${projectId}`);
38+
err.status = 404;
39+
throw err;
40+
}
41+
42+
const copilotRequest = await models.CopilotRequest.findByPk(copilotRequestId, { transaction });
43+
req.log.debug('approveRequest: found copilot request', { copilotRequestId: copilotRequest.id });
44+
45+
if (!copilotRequest) {
46+
const err = new Error(`no active copilot request found for copilot request id ${copilotRequestId}`);
47+
err.status = 404;
48+
throw err;
49+
}
50+
51+
await copilotRequest.update({ status: COPILOT_REQUEST_STATUS.APPROVED }, { transaction });
52+
req.log.debug('Copilot request status updated to APPROVED', { copilotRequestId });
53+
54+
const existingOpportunity = await models.CopilotOpportunity.findOne({
55+
where: {
56+
projectId,
57+
type: data.type,
58+
status: { [Op.in]: [COPILOT_OPPORTUNITY_STATUS.ACTIVE] },
59+
},
60+
transaction,
61+
});
62+
63+
if (existingOpportunity) {
64+
const err = new Error('There\'s an active opportunity of same type already!');
65+
err.status = 403;
66+
throw err;
67+
}
68+
69+
const opportunity = await models.CopilotOpportunity.create(data, { transaction });
70+
req.log.debug('Created new copilot opportunity', { opportunityId: opportunity.id });
71+
72+
// Send notifications
73+
try {
74+
const roles = await util.getRolesByRoleName(USER_ROLE.TC_COPILOT, req.log, req.id);
75+
req.log.debug('Roles fetched', { roles });
76+
77+
const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id);
78+
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL;
79+
const copilotPortalUrl = config.get('copilotPortalUrl');
80+
req.log.info('Sending emails to all copilots about new opportunity');
81+
82+
const sendNotification = (userName, recipient) => createEvent(emailEventType, {
83+
data: {
84+
user_name: userName,
85+
opportunity_details_url: `${copilotPortalUrl}/opportunity/${opportunity.id}`,
86+
work_manager_url: config.get('workManagerUrl'),
87+
opportunity_type: getCopilotTypeLabel(type),
88+
opportunity_title: opportunityTitle,
89+
start_date: moment(startDate).format('DD-MM-YYYY'),
90+
},
91+
sendgrid_template_id: TEMPLATE_IDS.CREATE_REQUEST,
92+
recipients: [recipient],
93+
version: 'v3',
94+
}, req.log);
95+
96+
subjects.forEach(subject => sendNotification(subject.handle, subject.email));
97+
98+
// send email to notify via slack
99+
sendNotification('Copilots', config.copilotsSlackEmail);
100+
req.log.info('Finished sending emails to copilots');
101+
} catch (emailErr) {
102+
req.log.error('Error sending notifications', { error: emailErr });
103+
}
104+
105+
return opportunity;
106+
} catch (err) {
107+
req.log.error('approveRequest failed', { error: err });
108+
throw err; // let outer transaction handle rollback
109+
}
110+
});
101111
};

src/routes/copilotRequest/create.js

Lines changed: 56 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const addCopilotRequestValidations = {
3939

4040
module.exports = [
4141
validate(addCopilotRequestValidations),
42-
(req, res, next) => {
42+
async (req, res, next) => {
4343
const data = req.body;
4444
if (!util.hasPermissionByReq(PERMISSION.MANAGE_COPILOT_REQUEST, req)) {
4545
const err = new Error('Unable to create copilot request');
@@ -58,66 +58,64 @@ module.exports = [
5858
updatedBy: req.authUser.userId,
5959
});
6060

61-
return models.sequelize.transaction((transaction) => {
62-
req.log.debug('Create Copilot request transaction', data);
63-
return models.Project.findOne({
64-
where: { id: projectId, deletedAt: { $eq: null } },
65-
})
66-
.then((existingProject) => {
67-
if (!existingProject) {
68-
const err = new Error(`active project not found for project id ${projectId}`);
69-
err.status = 404;
70-
throw err;
71-
}
72-
return models.CopilotRequest.findOne({
73-
where: {
74-
createdBy: req.authUser.userId,
75-
projectId,
76-
status: {
77-
[Op.in]: [COPILOT_REQUEST_STATUS.NEW, COPILOT_REQUEST_STATUS.APPROVED, COPILOT_REQUEST_STATUS.SEEKING],
78-
},
79-
},
80-
}).then((copilotRequest) => {
81-
if (copilotRequest && copilotRequest.data.projectType === data.data.projectType) {
82-
const err = new Error('There\'s a request of same type already!');
83-
_.assign(err, {
84-
status: 400,
85-
});
86-
throw err;
87-
}
61+
try {
62+
const copilotRequest = await models.sequelize.transaction(async (transaction) => {
63+
req.log.debug('Starting create copilot request transaction', { data });
64+
65+
const existingProject = await models.Project.findOne({
66+
where: { id: projectId, deletedAt: { $eq: null } },
67+
transaction,
68+
});
8869

89-
return models.CopilotRequest
90-
.create(data, { transaction });
91-
}).then((copilotRequest) => {
92-
/**
93-
* Automatically approve the copilot request.
94-
*/
95-
const approveData = _.assign({
96-
projectId,
97-
copilotRequestId: copilotRequest.id,
98-
createdBy: req.authUser.userId,
99-
updatedBy: req.authUser.userId,
100-
type: copilotRequest.data.projectType,
101-
opportunityTitle: copilotRequest.data.opportunityTitle,
102-
startDate: copilotRequest.data.startDate,
103-
});
104-
return approveRequest(req, approveData, transaction).then(() => copilotRequest);
105-
}).then(copilotRequest => res.status(201).json(copilotRequest))
106-
.catch((err) => {
107-
try {
108-
transaction.rollback();
109-
} catch (e) {
110-
_.noop(e);
111-
}
112-
return Promise.reject(err);
113-
});
70+
if (!existingProject) {
71+
const err = new Error(`Active project not found for project id ${projectId}`);
72+
err.status = 404;
73+
throw err;
74+
}
75+
76+
const existingRequest = await models.CopilotRequest.findOne({
77+
where: {
78+
createdBy: req.authUser.userId,
79+
projectId,
80+
status: {
81+
[Op.in]: [
82+
COPILOT_REQUEST_STATUS.NEW,
83+
COPILOT_REQUEST_STATUS.APPROVED,
84+
COPILOT_REQUEST_STATUS.SEEKING,
85+
],
86+
},
87+
},
88+
transaction,
11489
});
115-
})
116-
.catch((err) => {
117-
if (err.message) {
118-
_.assign(err, { details: err.message });
90+
91+
if (existingRequest && existingRequest.data.projectType === data.data.projectType) {
92+
const err = new Error('There\'s a request of same type already!');
93+
err.status = 400;
94+
throw err;
11995
}
120-
util.handleError('Error creating copilot request', err, req, next);
96+
97+
const newRequest = await models.CopilotRequest.create(data, { transaction });
98+
99+
await approveRequest(req, {
100+
projectId,
101+
copilotRequestId: newRequest.id,
102+
createdBy: req.authUser.userId,
103+
updatedBy: req.authUser.userId,
104+
type: newRequest.data.projectType,
105+
opportunityTitle: newRequest.data.opportunityTitle,
106+
startDate: newRequest.data.startDate,
107+
}, transaction);
108+
109+
return newRequest;
121110
});
111+
112+
return res.status(201).json(copilotRequest);
113+
} catch (err) {
114+
req.log.error('Error creating copilot request', { error: err });
115+
if (err.message) _.assign(err, { details: err.message });
116+
util.handleError('Error creating copilot request', err, req, next);
117+
return undefined;
118+
}
122119
},
123120
];
121+

0 commit comments

Comments
 (0)