Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 7 additions & 3 deletions scripts/demo-email-notifications/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,19 @@ This script does 2 things:
TAAS_NOTIFICATION_RESOURCE_BOOKING_EXPIRATION_SENDGRID_TEMPLATE_ID=7
TAAS_NOTIFICATION_TEAM_CREATED_SENDGRID_TEMPLATE_ID=8
TAAS_NOTIFICATION_JOB_CREATED_SENDGRID_TEMPLATE_ID=9
TAAS_NOTIFICATION_RESOURCE_BOOKING_PLACED_SENDGRID_TEMPLATE_ID=10
TAAS_NOTIFICATION_INTERVIEWS_OVERLAPPING_SENDGRID_TEMPLATE_ID=11
TAAS_NOTIFICATION_JOB_CANDIDATE_SELECTED_SENDGRID_TEMPLATE_ID=12
TAAS_NOTIFICATION_INTERVIEWS_OVERLAPPING_SENDGRID_TEMPLATE_ID=10
TAAS_NOTIFICATION_JOB_CANDIDATE_SELECTED_SENDGRID_TEMPLATE_ID=11
TAAS_NOTIFICATION_RESOURCE_BOOKING_PLACED_SENDGRID_TEMPLATE_ID=12
TAAS_NOTIFICATION_INTERVIEW_SCHEDULE_REMINDER_SENDGRID_TEMPLATE_ID=13
TAAS_NOTIFICATION_INTERVIEW_EXPIRED_GUEST_SENDGRID_TEMPLATE_ID=14
TAAS_NOTIFICATION_INTERVIEW_EXPIRED_HOST_SENDGRID_TEMPLATE_ID=15
TAAS_NOTIFICATION_INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID=16
TAAS_NOTIFICATION_INTERVIEW_LINK_FOR_HOST_SENDGRID_TEMPLATE_ID=17
TAAS_NOTIFICATION_INTERVIEW_LINK_FOR_GUEST_SENDGRID_TEMPLATE_ID=18
TAAS_NOTIFICATION_INTERVIEW_RESCHEDULED_HOST_SENDGRID_TEMPLATE_ID=19
TAAS_NOTIFICATION_INTERVIEW_RESCHEDULED_GUEST_SENDGRID_TEMPLATE_ID=20
TAAS_NOTIFICATION_INTERVIEW_CANCELLED_HOST_SENDGRID_TEMPLATE_ID=21
TAAS_NOTIFICATION_INTERVIEW_CANCELLED_GUEST_SENDGRID_TEMPLATE_ID=22
```
2. Config `SLACK_WEBHOOK_URL` env, if you want to send slack notifications

Expand Down
4 changes: 3 additions & 1 deletion scripts/demo-email-notifications/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async function resetNotificationRecords () {
localLogger.info('reset coming up interview records')
const interview = await Interview.findById('976d23a9-5710-453f-99d9-f57a588bb610')
const startTimestamp = moment().add(moment.duration(config.INTERVIEW_COMING_UP_REMIND_TIME[0])).add(config.INTERVIEW_COMING_UP_MATCH_WINDOW).toDate()
await interview.update({ startTimestamp, duration: 30, status: Interviews.Status.Scheduled, guestNames: ['test1', 'test2'], hostName: 'hostName' })
await interview.update({ startTimestamp, duration: 30, status: Interviews.Status.Scheduled, guestNames: ['test1', 'test2'], hostName: 'hostName', guestTimezone: 'Europe/London' })

// reset completed interview records
localLogger.info('reset completed interview records')
Expand All @@ -61,6 +61,8 @@ async function resetNotificationRecords () {
await completedInterview.update({ startTimestamp: completedStartTimestamp, duration, endTimeStamp: completedEndTimestamp, status: Interviews.Status.Scheduled, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })
const completedInterview2 = await Interview.findById('3144fa65-ea1a-4bec-81b0-7cb1c8845826')
await completedInterview2.update({ startTimestamp: completedStartTimestamp, duration, endTimeStamp: completedEndTimestamp, status: Interviews.Status.Scheduled, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })
const jobCandidateForInterview = await JobCandidate.findById('a4ea7bcf-5b99-4381-b99c-a9bd05d83a36')
await jobCandidateForInterview.update({ status: 'interview' })

// reset post interview candidate action reminder records
localLogger.info('reset post interview candidate action reminder records')
Expand Down
23 changes: 12 additions & 11 deletions src/services/NotificationsSchedulerService.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ async function getProjectWithId (projectId) {

/**
* extract the members of projects and build recipients list out of them
* we can use `userId` to identify recipients
* we can use `email` to identify recipients
* @param project the project
* @returns {string[]} array of recipients
*/
function buildProjectTeamRecipients (project) {
const recipients = _.unionBy(_.map(project.members, m => _.pick(m, 'userId')), 'userId')
const recipients = _.unionBy(_.map(project.members, m => _.pick(m, 'email')), 'email')
Copy link
Contributor

Choose a reason for hiding this comment

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

@yoution Emails could be sent by userId. I'm not sure that project members would always have email addresses. Can we keep userId here, or this breaks something?

if (_.isEmpty(recipients)) {
localLogger.error(`No recipients for projectId:${project.id}`, 'buildProjectTeamRecipients')
}
Expand Down Expand Up @@ -276,11 +276,11 @@ async function sendInterviewComingUpNotifications () {
const data = await getDataForInterview(interview)
if (!data) { continue }

if (!_.isEmpty(interview.hostEmail)) {
if (!_.isEmpty(data.hostEmail)) {
data.startTime = formatInterviewTime(interview, { forInterviewHost: true })
sendNotification({}, {
template: 'taas.notification.interview-coming-up-host',
recipients: [{ email: interview.hostEmail }],
recipients: [{ email: data.hostEmail }],
data
})

Expand All @@ -289,12 +289,12 @@ async function sendInterviewComingUpNotifications () {
localLogger.error(`Interview id: ${interview.id} host email not present`, 'sendInterviewComingUpNotifications')
}

if (!_.isEmpty(interview.guestEmails)) {
if (!_.isEmpty(data.guestEmail)) {
data.startTime = formatInterviewTime(interview, { forInterviewGuest: true })
// send guest emails
sendNotification({}, {
template: 'taas.notification.interview-coming-up-guest',
recipients: interview.guestEmails.map((email) => ({ email })),
recipients: [{ email: data.guestEmail }],
data
})

Expand Down Expand Up @@ -354,22 +354,23 @@ async function sendInterviewCompletedNotifications () {

let sentCount = 0
for (const interview of interviews) {
if (_.isEmpty(interview.hostEmail)) {
localLogger.error(`Interview id: ${interview.id} host email not present`)
continue
}
if (!jcMap[interview.jobCandidateId] || jcMap[interview.jobCandidateId].status !== constants.JobCandidateStatus.INTERVIEW) {
localLogger.error(`Interview id: ${interview.id} job candidate status is not ${constants.JobCandidateStatus.INTERVIEW}`)
continue
}

const data = await getDataForInterview(interview, jcMap[interview.jobCandidateId])

if (_.isEmpty(data.hostEmail)) {
localLogger.error(`Interview id: ${interview.id} host email not present`)
continue
}
if (!data) { continue }
data.startTime = formatInterviewTime(interview, { forInterviewHost: true })

sendNotification({}, {
template: 'taas.notification.interview-awaits-resolution',
recipients: [{ email: interview.hostEmail }],
recipients: [{ email: data.hostEmail }],
data
})

Expand Down