Skip to content

Commit 2754bc4

Browse files
committed
feat: add interview scheduler
1. Add Sequelize schema for Interview model. 2. Add `create-interviews-table` migration. 3. Add ES mapping for interviews. 4. Update existing index/re-index, and import/export scripts for the applied changes. 5. Add/implement the following endpoints. * `PATCH /jobCandidates/:jobCandidateId/requestInterview` * `PATCH /jobCandidates/:jobCandidateId/updateInterview/:round` * `GET /jobCandidates/:jobCandidateId/interviews` * `GET /jobCandidates/:jobCandidateId/interviews/:round` 6. Update the existing JobCandidate endpoints for applied changes. 7. Set up an hourly scheduled job to check & update Completed interviews. 8. Update `TeamService.sendEmail` for the interview scheduling feature. 9. Update POSTMAN collection & environment. 10. Update Swagger.
1 parent 3f1d9b0 commit 2754bc4

28 files changed

+11904
-4913
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
AUTH0_AUDIENCE_UBAHN=
3535
AUTH0_CLIENT_ID=
3636
AUTH0_CLIENT_SECRET=
37-
37+
# necessary if you'll utilize email functionality of interviews
38+
INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID=
39+
INTERVIEW_INVITATION_SENDER_EMAIL=
3840
# Locally deployed services (via docker-compose)
3941
ES_HOST=dockerhost:9200
4042
DATABASE_URL=postgres://postgres:postgres@dockerhost:5432/postgres

app-constants.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,33 @@ const Scopes = {
3939
CREATE_WORK_PERIOD: 'create:taas-workPeriods',
4040
UPDATE_WORK_PERIOD: 'update:taas-workPeriods',
4141
DELETE_WORK_PERIOD: 'delete:taas-workPeriods',
42-
ALL_WORK_PERIOD: 'all:taas-workPeriods'
42+
ALL_WORK_PERIOD: 'all:taas-workPeriods',
43+
// interview
44+
READ_INTERVIEW: 'read:taas-interviews',
45+
CREATE_INTERVIEW: 'create:taas-interviews',
46+
UPDATE_INTERVIEW: 'update:taas-interviews',
47+
ALL_INTERVIEW: 'all:taas-interviews'
48+
}
49+
50+
// Interview related constants
51+
const Interviews = {
52+
Status: {
53+
Scheduling: 'Scheduling',
54+
Scheduled: 'Scheduled',
55+
RequestedForReschedule: 'Requested for reschedule',
56+
Rescheduled: 'Rescheduled',
57+
Completed: 'Completed',
58+
Cancelled: 'Cancelled'
59+
},
60+
XaiTemplate: {
61+
'30MinInterview': '30-min-interview',
62+
'60MinInterview': '60-min-interview'
63+
}
4364
}
4465

4566
module.exports = {
4667
UserRoles,
4768
FullManagePermissionRoles,
48-
Scopes
69+
Scopes,
70+
Interviews
4971
}

app.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ const express = require('express')
99
const cors = require('cors')
1010
const HttpStatus = require('http-status-codes')
1111
const interceptor = require('express-interceptor')
12+
const schedule = require('node-schedule')
1213
const logger = require('./src/common/logger')
1314
const eventHandlers = require('./src/eventHandlers')
15+
const interviewService = require('./src/services/InterviewService')
1416

1517
// setup express app
1618
const app = express()
@@ -93,6 +95,8 @@ app.use((err, req, res, next) => {
9395
const server = app.listen(app.get('port'), () => {
9496
logger.info({ component: 'app', message: `Express server listening on port ${app.get('port')}` })
9597
eventHandlers.init()
98+
// schedule updateCompletedInterviews to run every hour
99+
schedule.scheduleJob('0 0 * * * *', interviewService.updateCompletedInterviews)
96100
})
97101

98102
if (process.env.NODE_ENV === 'test') {

config/default.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ module.exports = {
119119
TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update',
120120
// the delete work period entity Kafka message topic
121121
TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete',
122+
// topics for interview service
123+
// the request interview Kafka message topic
124+
TAAS_INTERVIEW_REQUEST_TOPIC: process.env.TAAS_INTERVIEW_REQUEST_TOPIC || 'taas.interview.requested',
125+
// the interview update Kafka message topic
126+
TAAS_INTERVIEW_UPDATE_TOPIC: process.env.TAAS_INTERVIEW_UPDATE_TOPIC || 'taas.interview.update',
127+
// the interview bulk update Kafka message topic
128+
TAAS_INTERVIEW_BULK_UPDATE_TOPIC: process.env.TAAS_INTERVIEW_BULK_UPDATE_TOPIC || 'taas.interview.bulkUpdate',
122129

123130
// the Kafka message topic for sending email
124131
EMAIL_TOPIC: process.env.EMAIL_TOPIC || 'external.action.email',
@@ -128,10 +135,18 @@ module.exports = {
128135
// the emails address for receiving the issue report
129136
// REPORT_ISSUE_EMAILS may contain comma-separated list of email which is converted to array
130137
REQUEST_EXTENSION_EMAILS: (process.env.REQUEST_EXTENSION_EMAILS || '').split(','),
138+
// the emails address for interview invitation
139+
// INTERVIEW_INVITATION_CC_LIST may contain comma-separated list of email which is converted to array
140+
// scheduler@x.ai should be in the CC list
141+
INTERVIEW_INVITATION_CC_LIST: (process.env.INTERVIEW_INVITATION_CC_LIST || 'scheduler@x.ai').split(','),
131142
// SendGrid email template ID for reporting issue
132143
REPORT_ISSUE_SENDGRID_TEMPLATE_ID: process.env.REPORT_ISSUE_SENDGRID_TEMPLATE_ID,
133144
// SendGrid email template ID for requesting extension
134145
REQUEST_EXTENSION_SENDGRID_TEMPLATE_ID: process.env.REQUEST_EXTENSION_SENDGRID_TEMPLATE_ID,
146+
// SendGrid email template ID for interview invitation
147+
INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID: process.env.INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID,
148+
// The sender (aka `from`) email for invitation.
149+
INTERVIEW_INVITATION_SENDER_EMAIL: process.env.INTERVIEW_INVITATION_SENDER_EMAIL,
135150
// the URL where TaaS App is hosted
136151
TAAS_APP_URL: process.env.TAAS_APP_URL || 'https://platform.topcoder-dev.com/taas/myteams'
137152
}

config/email_template.config.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,29 @@ module.exports = {
5959
'{{text}}',
6060
recipients: config.REPORT_ISSUE_EMAILS,
6161
sendgridTemplateId: config.REQUEST_EXTENSION_SENDGRID_TEMPLATE_ID
62+
},
63+
64+
/* Request interview for a job candidate
65+
*
66+
* - interviewType: the x.ai interview type. Example: "30-min-interview"
67+
* - candidateName: Full name of candidate. Example: "John Doe"
68+
* - jobName: The title of the job. Example: "TaaS API Misc Updates"
69+
* - customMessage: if it's needed, a custom message can be added to the end of email. Example: "I would like to invite you for an interview..."
70+
*
71+
* Template (defined in SendGrid):
72+
* Subject: '/{{interviewType}} tech interview with {{candidateName}} for {{jobName}} is requested by the Customer'
73+
* Body:
74+
* 'The customer has requested /{{interviewType}} with {{candidateName}} for {{jobName}}.'
75+
* + 'In a few minutes you will receive an invitation from our scheduling tool. Please proceed with the invitation to agree on timing.'
76+
* + '<br /><br />{{customMessage}}'
77+
*
78+
* Note, that the template should be defined in SendGrid.
79+
* The subject & body above (identical to actual SendGrid template) is for reference purposes.
80+
* We won't pass subject & body but only substitutions (replacements in template subject/body).
81+
*/
82+
'interview-invitation': {
83+
from: config.INTERVIEW_INVITATION_SENDER_EMAIL,
84+
cc: config.INTERVIEW_INVITATION_CC_LIST,
85+
sendgridTemplateId: config.INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID
6286
}
6387
}

data/demo-data.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)