Skip to content

Commit b6bff7e

Browse files
committed
refactor
1 parent 0faa3a3 commit b6bff7e

File tree

10 files changed

+119
-72
lines changed

10 files changed

+119
-72
lines changed

config/default.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,5 +274,7 @@ module.exports = {
274274
RESOURCE_BOOKING_EXPIRY_TIME: process.env.RESOURCE_BOOKING_EXPIRY_TIME || 'P21D',
275275
// The Stripe
276276
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
277-
CURRENCY: process.env.CURRENCY || 'usd'
277+
CURRENCY: process.env.CURRENCY || 'usd',
278+
// The slack webhook url to send slack notifications
279+
SLACK_WEBHOOK_URL: process.env.SLACK_WEBHOOK_URL
278280
}

data/notifications-email-template.html

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242
{{/if}}
243243
{{#if notificationType.newTeamCreated}}
244244
<span style="font-weight:bold;">Team Name:</span>
245-
{{teamName}}
245+
<a href={{teamURL}} target="_blank" rel="noopener noreferrer">{{teamName}}</a>
246246
<table style="font-size:13px;border:1px solid black;border-collapse:collapse;width:95%;">
247247
<tr style="font-weight:bold;border:1px solid black;border-collapse:collapse">
248248
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job Title</td>
@@ -251,7 +251,7 @@
251251
</tr>
252252
{{#each jobList}}
253253
<tr>
254-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.title}}</td>
254+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{this.jobUrl}} target="_blank" rel="noopener noreferrer">{{this.title}}</a></td>
255255
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.duration}}</td>
256256
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.startDate}}</td>
257257
</tr>
@@ -267,8 +267,8 @@
267267
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Start Date</td>
268268
</tr>
269269
<tr>
270-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{teamName}}</td>
271-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobTitle}}</td>
270+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{teamURL}} target="_blank" rel="noopener noreferrer">{{teamName}}</a></td>
271+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{jobURL}} target="_blank" rel="noopener noreferrer">{{jobTitle}}</a></td>
272272
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobDuration}}</td>
273273
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobStartDate}}</td>
274274
</tr>
@@ -278,19 +278,15 @@
278278
<table style="font-size:13px;border:1px solid black;border-collapse:collapse;width:95%;">
279279
<tr style="font-weight:bold;border:1px solid black;border-collapse:collapse">
280280
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Team Name</td>
281-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Team URL</td>
282281
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job title</td>
283-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job URL</td>
284282
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job Candidate</td>
285283
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Interview Start Date</td>
286284
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Interview End Date</td>
287285
</tr>
288286
{{#each interviews}}
289287
<tr>
290-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.teamName}}</td>
291-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.teamURL}}</td>
292-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.jobTitle}}</td>
293-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.jobURL}}</td>
288+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{this.teamURL}} target="_blank" rel="noopener noreferrer">{{this.teamName}}</a></td>
289+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{this.jobURL}} target="_blank" rel="noopener noreferrer">{{this.jobTitle}}</a></td>
294290
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.candidateUserHandle}}</td>
295291
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.startTime}}</td>
296292
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{this.endTime}}</td>
@@ -303,15 +299,13 @@
303299
<tr style="font-weight:bold;border:1px solid black;border-collapse:collapse">
304300
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Team Name</td>
305301
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job title</td>
306-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job URL</td>
307302
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job Start Date</td>
308303
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Job Duration</td>
309304
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Candidate User Handle</td>
310305
</tr>
311306
<tr>
312-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{teamName}}</td>
313-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobTitle}}</td>
314-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobUrl}}</td>
307+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{teamUrl}} target="_blank" rel="noopener noreferrer">{{teamName}}</a></td>
308+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{jobUrl}} target="_blank" rel="noopener noreferrer">{{jobTitle}}</a></td>
315309
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobStartDate}}</td>
316310
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobDuration}}</td>
317311
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{userHandle}}</td>
@@ -328,8 +322,8 @@
328322
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">Resource Bookings End Date</td>
329323
</tr>
330324
<tr>
331-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{teamName}}</td>
332-
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{jobTitle}}</td>
325+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{teamUrl}} target="_blank" rel="noopener noreferrer">{{teamName}}</a></td>
326+
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;"><a href={{jobUrl}} target="_blank" rel="noopener noreferrer">{{jobTitle}}</a></td>
333327
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{userHandle}}</td>
334328
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{startDate}}</td>
335329
<td style="border:1px solid black;border-collapse:collapse;text-align:center;line-height:1.5;">{{endDate}}</td>

scripts/demo-email-notifications/README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,24 @@ This script does 2 things:
1818
INTERVIEW_COMING_UP_MATCH_WINDOW=PT1M
1919
INTERVIEW_COMPLETED_MATCH_WINDOW=PT1M
2020
```
21+
2. Config `SLACK_WEBHOOK_URL` env, if you want to send slack notifications
2122

22-
2. Recreate demo data by:
23+
```sh
24+
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/***
25+
```
26+
27+
3. Recreate demo data by:
2328

2429
```sh
2530
npm run local:init`
2631

27-
3. Run TaaS API by:
32+
4. Run TaaS API by:
2833

2934
```sh
3035
npm run dev
3136
```
3237

33-
4. Run this demo script:
38+
5. Run this demo script:
3439

3540
```sh
3641
node scripts/demo-email-notifications

scripts/demo-email-notifications/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const { Interview, JobCandidate, ResourceBooking } = require('../../src/models')
1010
const { Interviews } = require('../../app-constants')
1111

1212
const consumer = new Kafka.GroupConsumer({ connectionString: process.env.KAFKA_URL, groupId: 'test-render-email' })
13-
const slackURL = null
1413

1514
const localLogger = {
1615
debug: message => logger.debug({ component: 'render email content', context: 'test', message }),
@@ -72,8 +71,8 @@ async function initConsumer () {
7271
fs.writeFileSync(`./out/${notification.details.data.subject}-${Date.now()}.html`, email)
7372
})
7473
for (const notification of _.filter(message.payload.notifications, ['serviceId', 'slack'])) {
75-
if (slackURL) {
76-
await axios.post(slackURL, { text: notification.details.text, blocks: notification.details.blocks })
74+
if (config.SLACK_WEBHOOK_URL) {
75+
await axios.post(config.SLACK_WEBHOOK_URL, { text: notification.details.text, blocks: notification.details.blocks })
7776
}
7877
}
7978
}

src/common/helper.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,13 +1914,7 @@ async function getTags (description) {
19141914
* @returns {Object} the project created
19151915
*/
19161916
async function createProject (currentUser, data) {
1917-
let token
1918-
if (currentUser.hasManagePermission || currentUser.isMachine) {
1919-
const m2mToken = await getM2MToken()
1920-
token = `Bearer ${m2mToken}`
1921-
} else {
1922-
token = currentUser.jwtToken
1923-
}
1917+
const token = currentUser.jwtToken
19241918
const res = await request
19251919
.post(`${config.TC_API}/projects/`)
19261920
.set('Authorization', token)
@@ -2047,6 +2041,19 @@ function getEmailTemplatesForKey (key) {
20472041
})
20482042
}
20492043

2044+
/**
2045+
* Format date to be used in email
2046+
*
2047+
* @param {Date} date date to be formatted
2048+
* @returns {String} formatted date
2049+
*/
2050+
function formatDate (date) {
2051+
if (date) {
2052+
const tzName = date.toLocaleString('en', { timeZoneName: 'short' }).split(' ').pop()
2053+
return `${moment(date).format('MMM D, YYYY, h:mm:ss a')} ${tzName}`
2054+
}
2055+
}
2056+
20502057
module.exports = {
20512058
encodeQueryString,
20522059
getParamFromCliArgs,
@@ -2110,5 +2117,6 @@ module.exports = {
21102117
getMemberGroups,
21112118
removeTextFormatting,
21122119
getMembersSuggest,
2113-
getEmailTemplatesForKey
2120+
getEmailTemplatesForKey,
2121+
formatDate
21142122
}

src/eventHandlers/InterviewEventHandler.js

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const models = require('../models')
99
const logger = require('../common/logger')
1010
const helper = require('../common/helper')
1111
const teamService = require('../services/TeamService')
12+
const Constants = require('../../app-constants')
1213

1314
/**
1415
* Once we request Interview for a JobCandidate, the invitation emails to be sent out.
@@ -45,27 +46,34 @@ async function sendInvitationEmail (payload) {
4546
*/
4647
async function checkOverlapping (payload) {
4748
const interview = payload.value
49+
if (_.includes([Constants.Interviews.Status.Cancelled, Constants.Interviews.Status.Completed], interview.status)) {
50+
return
51+
}
4852
const overlappingInterview = await models.Interview.findAll({
4953
where: {
50-
[Op.or]: [{
51-
startTimestamp: {
52-
[Op.lt]: interview.endTimestamp,
53-
[Op.gte]: interview.startTimestamp
54-
}
55-
}, {
56-
endTimestamp: {
57-
[Op.lte]: interview.endTimestamp,
58-
[Op.gt]: interview.startTimestamp
59-
}
54+
[Op.and]: [{
55+
status: _.values(_.omit(Constants.Interviews.Status, 'Completed', 'Cancelled'))
6056
}, {
61-
[Op.and]: [{
57+
[Op.or]: [{
6258
startTimestamp: {
63-
[Op.lt]: interview.startTimestamp
59+
[Op.lt]: interview.endTimestamp,
60+
[Op.gte]: interview.startTimestamp
6461
}
6562
}, {
6663
endTimestamp: {
67-
[Op.gt]: interview.endTimestamp
64+
[Op.lte]: interview.endTimestamp,
65+
[Op.gt]: interview.startTimestamp
6866
}
67+
}, {
68+
[Op.and]: [{
69+
startTimestamp: {
70+
[Op.lt]: interview.startTimestamp
71+
}
72+
}, {
73+
endTimestamp: {
74+
[Op.gt]: interview.endTimestamp
75+
}
76+
}]
6977
}]
7078
}]
7179
}
@@ -87,8 +95,8 @@ async function checkOverlapping (payload) {
8795
jobTitle: job.title,
8896
jobURL: `${config.TAAS_APP_URL}/${project.id}/positions/${job.id}`,
8997
candidateUserHandle: user.handle,
90-
startTime: oli.startTimestamp,
91-
endTime: oli.endTimestamp
98+
startTime: helper.formatDate(oli.startTimestamp),
99+
endTime: helper.formatDate(oli.endTimestamp)
92100
})
93101
}
94102

@@ -104,7 +112,7 @@ async function checkOverlapping (payload) {
104112
notificationType: {
105113
overlappingInterview: true
106114
},
107-
description: 'Send notification if there is a new Interview created which overlaps existent interview by time (from "startTimestamp" till "endTimestamp"). Do the same if we update start/end timestamp for Some Interview and now it overlaps with another one'
115+
description: 'Overlapping Interview Invites'
108116
},
109117
sendgridTemplateId: template.sendgridTemplateId,
110118
version: 'v3'
@@ -120,25 +128,19 @@ async function checkOverlapping (payload) {
120128
type: 'context',
121129
elements: [{
122130
type: 'mrkdwn',
123-
text: `teamName: *${iv.teamName}*`
124-
}, {
125-
type: 'mrkdwn',
126-
text: `teamURL: ${iv.teamURL}`
127-
}, {
128-
type: 'mrkdwn',
129-
text: `jobTitle: *${iv.jobTitle}*`
131+
text: `teamName: <${iv.teamURL}|*${iv.teamName}*>`
130132
}, {
131133
type: 'mrkdwn',
132-
text: `jobURL: ${iv.jobURL}`
134+
text: `jobTitle: <${iv.jobURL}|*${iv.jobTitle}*>`
133135
}, {
134136
type: 'mrkdwn',
135137
text: `candidateUserHandle: *${iv.candidateUserHandle}*`
136138
}, {
137139
type: 'mrkdwn',
138-
text: `startTime: *${iv.startTime.toISOString()}*`
140+
text: `startTime: *${helper.formatDate(iv.startTime)}*`
139141
}, {
140142
type: 'mrkdwn',
141-
text: `endTime: *${iv.endTime.toISOString()}*`
143+
text: `endTime: *${helper.formatDate(iv.endTime)}*`
142144
}]
143145
}, { type: 'divider' }])
144146
}

src/eventHandlers/JobCandidateEventHandler.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ async function sendJobCandidateSelectedNotification (payload) {
154154
const template = helper.getEmailTemplatesForKey('notificationEmailTemplates')['taas.notification.job-candidate-selected']
155155
const project = await helper.getProjectById({ isMachine: true }, job.projectId)
156156
const jobUrl = `${config.TAAS_APP_URL}/${project.id}/positions/${job.id}`
157+
const teamUrl = `${config.TAAS_APP_URL}/${project.id}`
157158
const emailData = {
158159
serviceId: 'email',
159160
type: 'taas.notification.job-candidate-selected',
@@ -163,15 +164,16 @@ async function sendJobCandidateSelectedNotification (payload) {
163164
data: {
164165
subject: template.subject,
165166
teamName: project.name,
167+
teamUrl,
166168
jobTitle: job.title,
167169
jobDuration: job.duration,
168-
jobStartDate: job.startDate,
170+
jobStartDate: helper.formatDate(job.startDate),
169171
userHandle: user.handle,
170172
jobUrl,
171173
notificationType: {
172174
candidateSelected: true
173175
},
174-
description: 'Send notification if Job Candidate status has been change to "selected" or Job Candidate has been created with "selected" status'
176+
description: 'Job Candidate is Selected'
175177
},
176178
sendgridTemplateId: template.sendgridTemplateId,
177179
version: 'v3'
@@ -187,22 +189,19 @@ async function sendJobCandidateSelectedNotification (payload) {
187189
type: 'context',
188190
elements: [{
189191
type: 'mrkdwn',
190-
text: `teamName: *${project.name}*`
192+
text: `teamName: <${teamUrl}|*${project.name}*>`
191193
}, {
192194
type: 'mrkdwn',
193-
text: `jobTitle: *${job.title}*`
195+
text: `jobTitle: <${jobUrl}|*${job.title}*>`
194196
}, {
195197
type: 'mrkdwn',
196198
text: `jobDuration: *${job.duration}*`
197199
}, {
198200
type: 'mrkdwn',
199-
text: `jobStartDate: *${job.startDate.toISOString()}*`
201+
text: `jobStartDate: *${helper.formatDate(job.startDate)}*`
200202
}, {
201203
type: 'mrkdwn',
202204
text: `userHandle: *${user.handle}*`
203-
}, {
204-
type: 'mrkdwn',
205-
text: `jobUrl: ${jobUrl}`
206205
}]
207206
}]
208207
}

src/eventHandlers/JobEventHandler.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ async function processUpdate (payload) {
6868
}
6969

7070
/**
71-
* Process job create event.
71+
* When Job is created, send notification to user.
7272
*
7373
* @param {Object} payload the event payload
7474
* @returns {undefined}
7575
*/
76-
async function processCreate (payload) {
76+
async function sendNotifications (payload) {
7777
if (payload.options.onTeamCreating) {
7878
logger.debug({
7979
component: 'JobEventHandler',
@@ -93,13 +93,15 @@ async function processCreate (payload) {
9393
data: {
9494
subject: template.subject,
9595
teamName: project.name,
96+
teamURL: `${config.TAAS_APP_URL}/${project.id}`,
9697
jobTitle: payload.value.title,
98+
jobURL: `${config.TAAS_APP_URL}/${project.id}/positions/${payload.value.id}`,
9799
jobDuration: payload.value.duration,
98-
jobStartDate: payload.value.startDate,
100+
jobStartDate: helper.formatDate(payload.value.startDate),
99101
notificationType: {
100102
newJobCreated: true
101103
},
102-
description: 'Send notification a new Job was created'
104+
description: 'New Job created'
103105
},
104106
sendgridTemplateId: template.sendgridTemplateId,
105107
version: 'v3'
@@ -115,6 +117,16 @@ async function processCreate (payload) {
115117
})
116118
}
117119

120+
/**
121+
* Process job create event.
122+
*
123+
* @param {Object} payload the event payload
124+
* @returns {undefined}
125+
*/
126+
async function processCreate (payload) {
127+
await sendNotifications(payload)
128+
}
129+
118130
module.exports = {
119131
processUpdate,
120132
processCreate

0 commit comments

Comments
 (0)