Skip to content

Commit 130d37a

Browse files
committed
part1
1 parent f34e1a7 commit 130d37a

File tree

8 files changed

+114
-3
lines changed

8 files changed

+114
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ The following parameters can be set in config files or in env variables:
3333
- `topics.TAAS_WORK_PERIOD_CREATE_TOPIC`: the create work period entity Kafka message topic
3434
- `topics.TAAS_WORK_PERIOD_UPDATE_TOPIC`: the update work period entity Kafka message topic
3535
- `topics.TAAS_WORK_PERIOD_DELETE_TOPIC`: the delete work period entity Kafka message topic
36+
- `topics.TAAS_INTERVIEW_REQUEST_TOPIC`: the request interview entity Kafka message topic
3637
- `esConfig.HOST`: Elasticsearch host
3738
- `esConfig.AWS_REGION`: The Amazon region to use when using AWS Elasticsearch service
3839
- `esConfig.ELASTICCLOUD.id`: The elastic cloud id, if your elasticsearch instance is hosted on elastic cloud. DO NOT provide a value for ES_HOST if you are using this

config/default.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ module.exports = {
3131
// topics for work period service
3232
TAAS_WORK_PERIOD_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_CREATE_TOPIC || 'taas.workperiod.create',
3333
TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update',
34-
TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete'
34+
TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete',
35+
// topics for interview service
36+
TAAS_INTERVIEW_REQUEST_TOPIC: process.env.TAAS_INTERVIEW_REQUEST_TOPIC || 'taas.interview.request'
3537
},
3638

3739
esConfig: {

local/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ services:
1212
- "9092:9092"
1313
environment:
1414
KAFKA_ADVERTISED_HOST_NAME: localhost
15-
KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1"
15+
KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.interview.request:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1"
1616
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
1717
esearch:
1818
image: elasticsearch:7.7.1

src/app.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const JobProcessorService = require('./services/JobProcessorService')
1313
const JobCandidateProcessorService = require('./services/JobCandidateProcessorService')
1414
const ResourceBookingProcessorService = require('./services/ResourceBookingProcessorService')
1515
const WorkPeriodProcessorService = require('./services/WorkPeriodProcessorService')
16+
const InterviewProcessorService = require('./services/InterviewProcessorService')
1617
const Mutex = require('async-mutex').Mutex
1718
const events = require('events')
1819

@@ -43,7 +44,9 @@ const topicServiceMapping = {
4344
// work period
4445
[config.topics.TAAS_WORK_PERIOD_CREATE_TOPIC]: WorkPeriodProcessorService.processCreate,
4546
[config.topics.TAAS_WORK_PERIOD_UPDATE_TOPIC]: WorkPeriodProcessorService.processUpdate,
46-
[config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete
47+
[config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete,
48+
// interview
49+
[config.topics.TAAS_INTERVIEW_REQUEST_TOPIC]: InterviewProcessorService.processRequestInterview
4750
}
4851

4952
// Start kafka consumer

src/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
const Joi = require('@hapi/joi')
22
const config = require('config')
3+
const _ = require('lodash')
4+
const { Interview } = require('../src/common/constants')
35
const constants = require('./common/constants')
46

7+
const allowedInterviewStatuses = _.values(Interview.Status)
8+
59
global.Promise = require('bluebird')
610

711
Joi.rateType = () => Joi.string().valid('hourly', 'daily', 'weekly', 'monthly')
@@ -10,6 +14,7 @@ Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist
1014
Joi.workload = () => Joi.string().valid('full-time', 'fractional')
1115
Joi.title = () => Joi.string().max(128)
1216
Joi.paymentStatus = () => Joi.string().valid('pending', 'partially-completed', 'completed', 'cancelled')
17+
Joi.interviewStatus = () => Joi.string().valid(...allowedInterviewStatuses)
1318
// Empty string is not allowed by Joi by default and must be enabled with allow('').
1419
// See https://joi.dev/api/?v=17.3.0#string fro details why it's like this.
1520
// In many cases we would like to allow empty string to make it easier to create UI for editing data.

src/common/constants.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@ module.exports = {
1616
JobCandidateCreate: 'jobcandidate:create',
1717
JobCandidateUpdate: 'jobcandidate:update'
1818
}
19+
},
20+
Interview: {
21+
Status: {
22+
Requested: 'Requested'
23+
}
1924
}
2025
}

src/scripts/createIndex.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ async function createIndex () {
4646
status: { type: 'keyword' },
4747
externalId: { type: 'keyword' },
4848
resume: { type: 'text' },
49+
interviews: {
50+
type: 'nested',
51+
properties: {
52+
id: { type: 'keyword' },
53+
jobCandidateId: { type: 'keyword' },
54+
googleCalendarId: { type: 'keyword' },
55+
customMessage: { type: 'text' },
56+
xaiTemplate: { type: 'keyword' },
57+
round: { type: 'integer' },
58+
status: { type: 'keyword' },
59+
createdAt: { type: 'date' },
60+
createdBy: { type: 'keyword' },
61+
updatedAt: { type: 'date' },
62+
updatedBy: { type: 'keyword' }
63+
}
64+
},
4965
createdAt: { type: 'date' },
5066
createdBy: { type: 'keyword' },
5167
updatedAt: { type: 'date' },
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* Interview Processor Service
3+
*/
4+
5+
const Joi = require('@hapi/joi')
6+
const logger = require('../common/logger')
7+
const helper = require('../common/helper')
8+
const constants = require('../common/constants')
9+
const config = require('config')
10+
11+
const esClient = helper.getESClient()
12+
13+
/**
14+
* Updates jobCandidate via a painless script
15+
*
16+
* @param {String} jobCandidateId job candidate id
17+
* @param {String} script script definition
18+
* @param {String} transactionId transaction id
19+
*/
20+
async function updateJobCandidateViaScript (jobCandidateId, script, transactionId) {
21+
await esClient.updateExtra({
22+
index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
23+
id: jobCandidateId,
24+
transactionId,
25+
body: { script },
26+
refresh: constants.esRefreshOption
27+
})
28+
}
29+
30+
/**
31+
* Process request interview entity message.
32+
* Creates an interview record under jobCandidate.
33+
*
34+
* @param {Object} message the kafka message
35+
* @param {String} transactionId
36+
*/
37+
async function processRequestInterview (message, transactionId) {
38+
const interview = message.payload
39+
// add interview in collection if there's already an existing collection
40+
// or initiate a new one with this interview
41+
const script = {
42+
source: `
43+
ctx._source.containsKey("interviews")
44+
? ctx._source.interviews.add(params.interview)
45+
: ctx._source.interviews = [params.interview]
46+
`,
47+
params: { interview }
48+
}
49+
await updateJobCandidateViaScript(interview.jobCandidateId, script, transactionId)
50+
}
51+
52+
processRequestInterview.schema = {
53+
message: Joi.object().keys({
54+
topic: Joi.string().required(),
55+
originator: Joi.string().required(),
56+
timestamp: Joi.date().required(),
57+
'mime-type': Joi.string().required(),
58+
payload: Joi.object().keys({
59+
id: Joi.string().uuid().required(),
60+
jobCandidateId: Joi.string().uuid().required(),
61+
googleCalendarId: Joi.string().allow(null),
62+
customMessage: Joi.string().allow(null),
63+
xaiTemplate: Joi.string().required(),
64+
round: Joi.number().integer().positive().required(),
65+
status: Joi.interviewStatus().required(),
66+
createdAt: Joi.date().required(),
67+
createdBy: Joi.string().uuid().required(),
68+
updatedAt: Joi.date().allow(null),
69+
updatedBy: Joi.string().uuid().allow(null)
70+
}).required()
71+
}).required(),
72+
transactionId: Joi.string().required()
73+
}
74+
75+
module.exports = {
76+
processRequestInterview
77+
}
78+
79+
logger.buildService(module.exports, 'InterviewProcessorService')

0 commit comments

Comments
 (0)