Skip to content

[PROD] Next Release #520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 48 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
624b03a
feat: add transaction for WorkPeriodService, WorkPeriodPaymentService…
yoution Jul 31, 2021
20586db
Merge pull request #493 from yoution/feature/shapeup4-cqrs-update
Aug 16, 2021
abba8ff
fix: resolve conflict
yoution Aug 16, 2021
12ba53a
Merge pull request #495 from yoution/feature/shapeup4-cqrs-update
Aug 16, 2021
08a29fd
feat: add transaction for the rest models
yoution Aug 19, 2021
bc2f369
fix candidate viewed by client notification
maxceem Aug 23, 2021
d62a190
fix not duplicate view candidate notifications
maxceem Aug 23, 2021
dc63758
Merge pull request #514 from yoution/feature/shapeup4-cqrs-update
Aug 25, 2021
be037a0
correcting typo
Aug 25, 2021
f4ff0cd
deploying on dev env
Aug 26, 2021
d6529d8
resolving conflict manually
Aug 26, 2021
51de894
Merge branch 'dev' into feature/shapeup4-cqrs-update
yoution Aug 30, 2021
17fff02
fix: issue #523
yoution Aug 31, 2021
6b4c2c1
Update default.js
sachin-maheshwari Aug 31, 2021
e7fcf75
Merge branch 'feature/shapeup4-cqrs-update' into feature/shapeup4-cqr…
Aug 31, 2021
6114255
Merge pull request #527 from yoution/feature/shapeup4-cqrs-update
Aug 31, 2021
3d9d221
Split email template and update text (#529)
xxcxy Sep 1, 2021
6b5a972
move email templates into a separate folder
maxceem Sep 1, 2021
5b39bc8
improve interview email notifications logic
maxceem Sep 1, 2021
8858bd2
remove redundant env variable
maxceem Sep 1, 2021
80baf96
Merge branch 'dev' into feature/shapeup4-cqrs-update
Sep 2, 2021
a279cb7
Revert "remove redundant env variable"
maxceem Sep 2, 2021
8f17ec7
Revert "move email templates into a separate folder"
maxceem Sep 2, 2021
d0905bb
Revert "Split email template and update text (#529)"
maxceem Sep 2, 2021
afc7308
Pointing to v5 skills api instead of v5.1
Sep 2, 2021
efe574e
Merge pull request #532 from topcoder-platform/feature/revert-splitti…
maxceem Sep 2, 2021
da35ed5
Merge branch 'dev' into feature/shapeup4-cqrs-update
maxceem Sep 2, 2021
7a27e8d
improve scheduled notifications robustness
maxceem Sep 2, 2021
736cf4e
Merge pull request #536 from topcoder-platform/feature/improve-schedu…
maxceem Sep 2, 2021
1be8ba4
Merge branch 'dev' into feature/shapeup4-cqrs-update
maxceem Sep 2, 2021
1117c3e
issue:538, more debugging
Sep 3, 2021
66759e2
issue:538, more debug
Sep 3, 2021
1d6f81c
issue:538, typo
Sep 3, 2021
7790f34
Add files via upload
nkumar-topcoder Sep 6, 2021
dc52288
[skip ci]
nkumar-topcoder Sep 6, 2021
1b22c8a
Merge pull request #521 from topcoder-platform/feature/shapeup4-cqrs-…
nkumar-topcoder Sep 8, 2021
7b95462
Merge pull request #533 from topcoder-platform/hotfix/removing-beta-a…
Sep 8, 2021
2f3cea5
fix: issue #543
yoution Sep 8, 2021
81b5573
Interview completed email notification should not be sent if action w…
xxcxy Sep 9, 2021
339068d
do not find jc twice
xxcxy Sep 9, 2021
ae96099
fix Issues with Post Interview Action Reminder email notification whe…
xxcxy Sep 9, 2021
003fdc4
Merge pull request #544 from yoution/issue-543
maxceem Sep 9, 2021
cf8f6fe
fix notification demo data
xxcxy Sep 9, 2021
3c04b80
Merge pull request #545 from xxcxy/fix-issues-541
maxceem Sep 9, 2021
9ace73e
Merge branch 'dev' into fix-issues-540
maxceem Sep 9, 2021
5f47181
Merge pull request #547 from xxcxy/fix-issues-540
maxceem Sep 9, 2021
3635527
fix: issue #550
yoution Sep 13, 2021
f2b8e9e
Merge pull request #551 from yoution/issue-550
maxceem Sep 13, 2021
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
3 changes: 1 addition & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ workflows:
branches:
only:
- dev
- change-validatations-in-job-jc
- feature/enriching-skills-data-with-api-2
- feature/shapeup4-cqrs-update

# Production builds are exectuted only on tagged commits to the
# master branch.
Expand Down
3 changes: 3 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ module.exports = {
KAFKA_ERROR_TOPIC: process.env.KAFKA_ERROR_TOPIC || 'common.error.reporting',
// The originator value for the kafka messages
KAFKA_MESSAGE_ORIGINATOR: process.env.KAFKA_MESSAGE_ORIGINATOR || 'taas-api',

// topics for error
TAAS_ERROR_TOPIC: process.env.TAAS_ERROR_TOPIC || 'taas.action.error',
// topics for job service
// the create job entity Kafka message topic
TAAS_JOB_CREATE_TOPIC: process.env.TAAS_JOB_CREATE_TOPIC || 'taas.job.create',
Expand Down
10 changes: 5 additions & 5 deletions data/demo-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"a2b4bc11-c641-4a19-9eb7-33980378f82e"
],
"status": "in-review",
"isApplicationPageActive": false,
"isApplicationPageActive": true,
"minSalary": 100,
"maxSalary": 200,
"hoursPerWeek": 20,
Expand Down Expand Up @@ -51,7 +51,7 @@
"a2b4bc11-c641-4a19-9eb7-33980378f82e"
],
"status": "in-review",
"isApplicationPageActive": false,
"isApplicationPageActive": true,
"minSalary": 100,
"maxSalary": 200,
"hoursPerWeek": 80,
Expand Down Expand Up @@ -83,7 +83,7 @@
"a2b4bc11-c641-4a19-9eb7-33980378f82e"
],
"status": "in-review",
"isApplicationPageActive": false,
"isApplicationPageActive": true,
"minSalary": 100,
"maxSalary": 200,
"hoursPerWeek": 90,
Expand Down Expand Up @@ -115,7 +115,7 @@
"a2b4bc11-c641-4a19-9eb7-33980378f82e"
],
"status": "in-review",
"isApplicationPageActive": false,
"isApplicationPageActive": true,
"minSalary": 100,
"maxSalary": 200,
"hoursPerWeek": 20,
Expand Down Expand Up @@ -148,7 +148,7 @@
"0b104b7c-0792-4118-8bc7-a274e9ee19e3"
],
"status": "closed",
"isApplicationPageActive": false,
"isApplicationPageActive": true,
"minSalary": null,
"maxSalary": null,
"hoursPerWeek": null,
Expand Down
6 changes: 6 additions & 0 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ paths:
schema:
type: integer
description: The project id.
- in: query
name: isApplicationPageActive
required: false
schema:
type: boolean
description: Is application page active.
- in: query
name: projectIds
required: false
Expand Down
Binary file modified docs/taas-ER-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 10 additions & 10 deletions scripts/demo-email-notifications/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ async function resetNotificationRecords () {
// reset completed interview records
localLogger.info('reset completed interview records')
const pastTime = moment.duration(config.INTERVIEW_COMPLETED_PAST_TIME)
const endTimestamp = moment().subtract(pastTime).add(config.INTERVIEW_COMPLETED_MATCH_WINDOW).toDate()
const completedStartTimestamp = moment().subtract(pastTime).add(config.INTERVIEW_COMPLETED_MATCH_WINDOW).toDate()
const completedInterview = await Interview.findById('9efd72c3-1dc7-4ce2-9869-8cca81d0adeb')
const duration = 30
const completedStartTimestamp = moment().subtract(pastTime).subtract(30, 'm').toDate()
await completedInterview.update({ startTimestamp: completedStartTimestamp, duration, endTimestamp, status: Interviews.Status.Scheduled, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })
const completedEndTimestamp = moment(completedStartTimestamp).clone().add(30, 'm').toDate()
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' })

// reset post interview candidate action reminder records
localLogger.info('reset post interview candidate action reminder records')
const jobCandidate = await JobCandidate.findById('881a19de-2b0c-4bb9-b36a-4cb5e223bdb5')
const jobCandidate = await JobCandidate.findById('827ee401-df04-42e1-abbe-7b97ce7937ff')
await jobCandidate.update({ status: 'interview' })
const c2Interview = await Interview.findById('077aa2ca-5b60-4ad9-a965-1b37e08a5046')
await c2Interview.update({ startTimestamp: moment().subtract(moment.duration(config.POST_INTERVIEW_ACTION_MATCH_WINDOW)).subtract(30, 'm').toDate(), duration, endTimestamp, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })
const jobCandidateWithinOneDay = await JobCandidate.findById('827ee401-df04-42e1-abbe-7b97ce7937ff')
await jobCandidateWithinOneDay.update({ status: 'interview' })
const interviewWithinOneDay = await Interview.findById('3144fa65-ea1a-4bec-81b0-7cb1c8845826')
await interviewWithinOneDay.update({ startTimestamp: completedStartTimestamp, duration, endTimestamp, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })
const c2Interview = await Interview.findById('3144fa65-ea1a-4bec-81b0-7cb1c8845826')
await c2Interview.update({ startTimestamp: moment().subtract(moment.duration(config.POST_INTERVIEW_ACTION_MATCH_WINDOW)).subtract(30, 'm').toDate(), duration, endTimeStamp: completedEndTimestamp, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })
const c2InterviewR2 = await Interview.findById('b1f7ba76-640f-47e2-9463-59e51b51ec60')
await c2InterviewR2.update({ status: 'Scheduled', startTimestamp: moment().subtract(moment.duration(config.POST_INTERVIEW_ACTION_MATCH_WINDOW)).subtract(30, 'm').toDate(), duration, endTimeStamp: completedEndTimestamp, guestNames: ['guest1', 'guest2'], hostName: 'hostName' })

// reset upcoming resource booking expiration records
localLogger.info('reset upcoming resource booking expiration records')
Expand Down
25 changes: 23 additions & 2 deletions src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,26 @@ async function postEvent (topic, payload, options = {}) {
await eventDispatcher.handleEvent(topic, { value: payload, options })
}

/**
* Send error event to Kafka
* @params {String} topic the topic name
* @params {Object} payload the payload
* @params {String} action for which operation error occurred
*/
async function postErrorEvent (topic, payload, action) {
_.set(payload, 'apiAction', action)
const client = getBusApiClient()
const message = {
topic,
originator: config.KAFKA_MESSAGE_ORIGINATOR,
timestamp: new Date().toISOString(),
'mime-type': 'application/json',
payload
}
logger.debug(`Publish error to Kafka topic ${topic}, ${JSON.stringify(message, null, 2)}`)
await client.postEvent(message)
}

/**
* Test if an error is document missing exception
*
Expand Down Expand Up @@ -1220,7 +1240,7 @@ async function getTopcoderSkills (criteria) {
const token = await getM2MUbahnToken()
try {
const res = await request
.get(`${config.TC_BETA_API}/skills`)
.get(`${config.TC_API}/skills`)
.query({
taxonomyId: config.TOPCODER_TAXONOMY_ID,
...criteria
Expand Down Expand Up @@ -1272,7 +1292,7 @@ async function getAllTopcoderSkills (criteria) {
async function getSkillById (skillId) {
const token = await getM2MUbahnToken()
const res = await request
.get(`${config.TC_BETA_API}/skills/${skillId}`)
.get(`${config.TC_API}/skills/${skillId}`)
.set('Authorization', `Bearer ${token}`)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
Expand Down Expand Up @@ -2094,6 +2114,7 @@ module.exports = {
getM2MToken,
getM2MUbahnToken,
postEvent,
postErrorEvent,
getBusApiClient,
isDocumentMissingException,
getProjects,
Expand Down
127 changes: 127 additions & 0 deletions src/esProcessors/InterviewProcessor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* Interview Processor
*/

const _ = require('lodash')
const helper = require('../common/helper')
const config = require('config')

const esClient = helper.getESClient()

/**
* Updates jobCandidate via a painless script
*
* @param {String} jobCandidateId job candidate id
* @param {String} script script definition
*/
async function updateJobCandidateViaScript (jobCandidateId, script) {
await esClient.update({
index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
id: jobCandidateId,
body: { script },
refresh: 'wait_for'
})
}

/**
* Process request interview entity.
* Creates an interview record under jobCandidate.
*
* @param {Object} interview interview object
*/
async function processRequestInterview (interview) {
// add interview in collection if there's already an existing collection
// or initiate a new one with this interview
const script = {
source: `
ctx._source.containsKey("interviews")
? ctx._source.interviews.add(params.interview)
: ctx._source.interviews = [params.interview]
`,
params: { interview }
}
await updateJobCandidateViaScript(interview.jobCandidateId, script)
}

/**
* Process update interview entity
* Updates the interview record under jobCandidate.
*
* @param {Object} interview interview object
*/
async function processUpdateInterview (interview) {
// if there's an interview with this id,
// update it
const script = {
source: `
if (ctx._source.containsKey("interviews")) {
def target = ctx._source.interviews.find(i -> i.id == params.interview.id);
if (target != null) {
for (prop in params.interview.entrySet()) {
target[prop.getKey()] = prop.getValue()
}
}
}
`,
params: { interview }
}
await updateJobCandidateViaScript(interview.jobCandidateId, script)
}

/**
* Process bulk (partially) update interviews entity.
* Currently supports status, updatedAt and updatedBy fields.
* Update Joi schema to allow more fields.
* (implementation should already handle new fields - just updating Joi schema should be enough)
*
* payload format:
* {
* "jobCandidateId": {
* "interviewId": { ...fields },
* "interviewId2": { ...fields },
* ...
* },
* "jobCandidateId2": { // like above... },
* ...
* }
*
* @param {Object} jobCandidates job candidates
*/
async function processBulkUpdateInterviews (jobCandidates) {
// script to update & params
const script = {
source: `
def completedInterviews = params.jobCandidates[ctx._id];
for (interview in completedInterviews.entrySet()) {
def interviewId = interview.getKey();
def affectedFields = interview.getValue();
def target = ctx._source.interviews.find(i -> i.id == interviewId);
if (target != null) {
for (field in affectedFields.entrySet()) {
target[field.getKey()] = field.getValue();
}
}
}
`,
params: { jobCandidates }
}
// update interviews
await esClient.updateByQuery({
index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
body: {
script,
query: {
ids: {
values: _.keys(jobCandidates)
}
}
},
refresh: true
})
}

module.exports = {
processRequestInterview,
processUpdateInterview,
processBulkUpdateInterviews
}
54 changes: 54 additions & 0 deletions src/esProcessors/JobCandidateProcessor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Jobcandidate Processor
*/

const config = require('config')
const helper = require('../common/helper')

const esClient = helper.getESClient()

/**
* Process create entity
* @param {Object} entity entity object
*/
async function processCreate (entity) {
await esClient.create({
index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
id: entity.id,
body: entity,
refresh: 'wait_for'
})
}

/**
* Process update entity
* @param {Object} entity entity object
*/
async function processUpdate (entity) {
await esClient.update({
index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
id: entity.id,
body: {
doc: entity
},
refresh: 'wait_for'
})
}

/**
* Process delete entity
* @param {Object} entity entity object
*/
async function processDelete (entity) {
await esClient.delete({
index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
id: entity.id,
refresh: 'wait_for'
})
}

module.exports = {
processCreate,
processUpdate,
processDelete
}
Loading