Skip to content

Commit 18c8a80

Browse files
Merge pull request #572 from topcoder-platform/gigs-listing-rcrmstatus
RCRM Status, Status reason add columns and API Changes
2 parents 7450b35 + 474fde4 commit 18c8a80

File tree

10 files changed

+260
-8
lines changed

10 files changed

+260
-8
lines changed

docs/swagger.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ paths:
219219
schema:
220220
type: boolean
221221
description: The featured jobs
222+
- in: query
223+
name: rcrmStatus
224+
required: false
225+
schema:
226+
type: string
227+
enum: ["Open", "On Hold", "Canceled", "Draft", "Closed"]
222228
requestBody:
223229
content:
224230
application/json:
@@ -4128,6 +4134,32 @@ components:
41284134
type: string
41294135
example: "USD"
41304136
description: "the currency of job"
4137+
showInHotList:
4138+
type: boolean
4139+
default: false
4140+
description: "Whether to show job in hot list"
4141+
featured:
4142+
type: boolean
4143+
default: false
4144+
description: "Whether a job is a featured job"
4145+
hotListExcerpt:
4146+
type: string
4147+
default: ''
4148+
description: "A text to show for the hotlist excerpt"
4149+
jobTag:
4150+
type: string
4151+
default: ''
4152+
enum: ["New", "$$$", "Hot", ""]
4153+
description: "the job tag"
4154+
rcrmStatus:
4155+
type: string
4156+
default: null
4157+
enum: [null, "Open", "On Hold", "Canceled", "Draft", "Closed"]
4158+
description: "the job rcrm status"
4159+
rcrmReason:
4160+
type: string
4161+
default: null
4162+
description: "the possible rcrm reason for current status"
41314163
createdAt:
41324164
type: string
41334165
format: date-time
@@ -4247,6 +4279,15 @@ components:
42474279
type: string
42484280
enum: ["", "New", "$$$", "Hot"]
42494281
description: "The tag of a job"
4282+
rcrmStatus:
4283+
type: string
4284+
default: null
4285+
enum: [null, "Open", "On Hold", "Canceled", "Draft", "Closed"]
4286+
description: "the job rcrm status"
4287+
rcrmReason:
4288+
type: string
4289+
default: null
4290+
description: "the possible rcrm reason for current status"
42504291
isApplicationPageActive:
42514292
type: boolean
42524293
default: false
@@ -4803,6 +4844,15 @@ components:
48034844
type: string
48044845
enum: ["", "New", "$$$", "Hot"]
48054846
description: "The tag of a job"
4847+
rcrmStatus:
4848+
type: string
4849+
default: null
4850+
enum: [null, "Open", "On Hold", "Canceled", "Draft", "Closed"]
4851+
description: "the job rcrm status"
4852+
rcrmReason:
4853+
type: string
4854+
default: null
4855+
description: "the possible rcrm reason for current status"
48064856
isApplicationPageActive:
48074857
type: boolean
48084858
default: false
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const config = require('config')
2+
3+
/*
4+
* Add rcrm_status, rcrm_reason to the Job model.
5+
type: Sequelize.STRING(255),
6+
defaultValue: null,
7+
allowNull: true
8+
*/
9+
10+
module.exports = {
11+
up: async (queryInterface, Sequelize) => {
12+
const transaction = await queryInterface.sequelize.transaction()
13+
try {
14+
await queryInterface.addColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'rcrm_status',
15+
{ type: Sequelize.STRING(255), allowNull: true, defaultValue: null },
16+
{ transaction })
17+
await queryInterface.addColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'rcrm_reason',
18+
{ type: Sequelize.STRING(255), allowNull: true, defaultValue: null },
19+
{ transaction })
20+
await transaction.commit()
21+
} catch (err) {
22+
await transaction.rollback()
23+
throw err
24+
}
25+
},
26+
down: async (queryInterface, Sequelize) => {
27+
const transaction = await queryInterface.sequelize.transaction()
28+
try {
29+
await queryInterface.removeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'rcrm_status', { transaction })
30+
await queryInterface.removeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'rcrm_reason', { transaction })
31+
await transaction.commit()
32+
} catch (err) {
33+
await transaction.rollback()
34+
throw err
35+
}
36+
}
37+
}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
"demo-payment": "node scripts/demo-payment",
3434
"migrate:backup-withdrawn": "node scripts/withdrawn-migration/backup.js",
3535
"migrate:migration-withdrawn": "node scripts/withdrawn-migration/migration.js",
36-
"migrate:restore-withdrawn": "node scripts/withdrawn-migration/restore.js"
36+
"migrate:restore-withdrawn": "node scripts/withdrawn-migration/restore.js",
37+
"migrate:backup-rcrm-status": "node scripts/job-rcrm-status-migration/backup.js",
38+
"migrate:migration-rcrm-status": "node scripts/job-rcrm-status-migration/migration.js",
39+
"migrate:restore-rcrm-status": "node scripts/job-rcrm-status-migration/restore.js"
3740
},
3841
"keywords": [],
3942
"author": "",
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Back up the jobs that we will update it's status
3+
*/
4+
const fs = require('fs')
5+
const path = require('path')
6+
const request = require('superagent')
7+
const logger = require('../../src/common/logger')
8+
9+
const currentStep = 'Backup'
10+
11+
async function backup () {
12+
logger.info({ component: currentStep, message: '*************************** Backup process started ***************************' })
13+
const filePath = path.join(__dirname, '/temp/')
14+
if (fs.existsSync(filePath)) {
15+
fs.rmdirSync(filePath, { recursive: true })
16+
}
17+
fs.mkdirSync(filePath)
18+
let { body: jobs } = await request.get('https://www.topcoder-dev.com/api/recruit/jobs?job_status=1')
19+
jobs = jobs.map((item) => item.slug)
20+
if (jobs && jobs.length > 0) {
21+
try {
22+
fs.writeFileSync(filePath + 'jobs-backup.json', JSON.stringify(
23+
jobs
24+
))
25+
logger.info({ component: `${currentStep} Sub`, message: `There are ${jobs.length} jobs that need to be updated` })
26+
} catch (err) {
27+
logger.error({ component: currentStep, message: err.message })
28+
process.exit(1)
29+
}
30+
}
31+
logger.info({ component: `${currentStep}`, message: `Report: there are ${jobs.length} jobs in total` })
32+
logger.info({ component: currentStep, message: '*************************** Backup process finished ***************************' })
33+
}
34+
35+
backup().then(() => {
36+
logger.info({ component: currentStep, message: 'Execution Finished!' })
37+
process.exit()
38+
}).catch(err => {
39+
logger.error(err.message)
40+
process.exit(1)
41+
})
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Migration the job rcrm status into Open status
3+
*/
4+
const fs = require('fs')
5+
const path = require('path')
6+
const { Job } = require('../../src/models')
7+
const logger = require('../../src/common/logger')
8+
9+
const currentStep = 'Migration'
10+
11+
async function migration () {
12+
logger.info({ component: currentStep, message: '*************************** Migration process started ***************************' })
13+
const filePath = path.join(__dirname, '/temp/')
14+
const files = []
15+
fs.readdirSync(filePath).forEach(async (file) => {
16+
files.push(`${filePath}${file}`)
17+
})
18+
let totalSum = 0
19+
for (let j = 0; j < files.length; j++) {
20+
const data = fs.readFileSync(files[j], 'utf-8')
21+
const rcrmIds = JSON.parse(data)
22+
let summary = 0
23+
for (let i = 0; i < rcrmIds.length; i++) {
24+
const jbs = await Job.findAll({
25+
where: { externalId: rcrmIds[i] }
26+
})
27+
for (let j = 0; j < jbs.length; j++) {
28+
if (jbs[j]) {
29+
const oldStatus = jbs[j].rcrmStatus
30+
const updated = await jbs[j].update({ rcrmStatus: 'Open' })
31+
summary++
32+
totalSum++
33+
logger.info({ component: currentStep, message: `job with rcrmId ${rcrmIds[i]} status changed from ${oldStatus} to ${updated.status}` })
34+
}
35+
}
36+
};
37+
logger.info({ component: `${currentStep} Sub`, message: `Updated ${summary} jobs from ${files[j]}` })
38+
}
39+
logger.info({ component: currentStep, message: `Report: Totally Updated ${totalSum} jobs` })
40+
logger.info({ component: currentStep, message: '*************************** Migration process finished ***************************' })
41+
}
42+
43+
migration().then(() => {
44+
logger.info({ component: currentStep, message: 'Execution Finished!' })
45+
process.exit()
46+
}).catch(err => {
47+
logger.error(err.message)
48+
process.exit(1)
49+
})
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Restore the job rcrm status into Open status
3+
*/
4+
const fs = require('fs')
5+
const path = require('path')
6+
const { Job } = require('../../src/models')
7+
const logger = require('../../src/common/logger')
8+
9+
const currentStep = 'Restore'
10+
11+
async function restore () {
12+
logger.info({ component: currentStep, message: '*************************** Restore process started ***************************' })
13+
const filePath = path.join(__dirname, '/temp/')
14+
const files = []
15+
fs.readdirSync(filePath).forEach(async (file) => {
16+
files.push(`${filePath}${file}`)
17+
})
18+
let totalSum = 0
19+
for (let j = 0; j < files.length; j++) {
20+
const data = fs.readFileSync(files[j], 'utf-8')
21+
const rcrmIds = JSON.parse(data)
22+
let summary = 0
23+
for (let i = 0; i < rcrmIds.length; i++) {
24+
const jbs = await Job.findAll({
25+
where: { externalId: rcrmIds[i] }
26+
})
27+
for (let j = 0; j < jbs.length; j++) {
28+
if (jbs[j]) {
29+
const oldStatus = jbs[j].rcrmStatus
30+
const updated = await jbs[j].update({ rcrmStatus: null })
31+
summary++
32+
totalSum++
33+
logger.info({ component: currentStep, message: `job with rcrmId ${rcrmIds[i]} status changed from ${oldStatus} to ${updated.status}` })
34+
}
35+
}
36+
};
37+
logger.info({ component: `${currentStep} Sub`, message: `Updated ${summary} jobs from ${files[j]}` })
38+
}
39+
logger.info({ component: currentStep, message: `Report: Totally Restored ${totalSum} jobs` })
40+
logger.info({ component: currentStep, message: '*************************** Restore process finished ***************************' })
41+
}
42+
43+
restore().then(() => {
44+
logger.info({ component: currentStep, message: 'Execution Finished!' })
45+
process.exit()
46+
}).catch(err => {
47+
logger.error(err.message)
48+
process.exit(1)
49+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
["90269852","28960960","16341500556800013350dQL","16341323722130013350Qgs","16341323715070013350yCX","16341501858830013350JSx","16342073365140013350Omh","16342071086360013350TKd","29014265","16341982292150013350DhE","16341851836400013350YSd","16341851823530013350OHa","16341323716640013350BFn","16341517864620013350LvZ","16341438759150013350CTj","16341414354520013350czx","16329389793410013350nhr","16341285133710013350gRv","16327915384700013350wjq","16322342157030013350thK","16340504449290013350Zmk","16336199677990013350hWP","16340663860380013350dkg","16323945983630013350VIn","16340663745860013350Ogp","16340521190520013350Zyo","16329256769300013350wOD","16330142450080013350Zud","16336147040350013350Nbe","16335218110630009830oSa","16328384519390013350hzK","16337227842100013350BDn","16328401153230013350dVH","16339568564580013350cxO","16337126130130013350GNX","16337229047900013350rlK","16339461887230013350pHA","16339455520130013350SMw","16292946209270013350cqL","16317343900830013350iSB","16334323145940013350bqN","16333532888560013350VfJ","16335231874280013350PsN","16335233245550013350ybF","16335365496710013350mdw","16324274043560013350per","28968572","16328235118630013350TUH","16329413634180013350cbO","89425274","16322224121530013350BxF","16335010800170013350OlD","16335010785580013350ZMW","16335010794140013350qSN","16335010771830013350kvN","16335010773590013350kyi","16329269383370013350pcK","16334453262680013350ksT","16317088129440013350Yuq","16333604284300013350scM","16334117377520013350lxQ","16334117503830013350mot","16334040093120013350uQK","16333472255660013350DMW","16322834774440013350qgN","16322398868710013350TVc","16333463496610013350hPf","16333296533550013350VMv","16311102743050013350UOQ","16305004931790013350nDf","16329484262990013350Lxj","16329780377000013350gjy","16321575158770013350aMr","16330154680980013350guh","16330154680330013350xSz","16330153298270013350azs","16317282228550013350KNM","16329976194830013350YeO","16329926004110013350tBA","16329780351410013350mLA","16305004990960013350Ssa","16325262321460013350SVA","16311098213960013350dOG","89264852","16322413567270013350DGr","16305004975190013350PFT","16309630704830013350hEg","16328129817130013350NAX","16328127653330013350DdA","16328123904580013350LUi","16328103721410013350tQw","16328099924470013350xAs","90068402","16327519095440013350Pxc","16327519083280013350ehu","16327406515900013350pkn","16324784697460013350zYO","16327120198060013350ncx","16326943991890013350CEP","27288460","16311191494770013350NUc","16313030794420013350jid","16313049677110013350DaN","16311326832280013350lHd","16323409561830013350sZU","16323378537470013350LEP","16312171350470013350JFb","16322398849240013350gPZ","16318012800890013350XTH","16323155626160013350sIH","28317595","16318000891270013350pVC","16322398874030013350dvM","29006647","16315538849780013350xOe","16310329298030013350vqT","16311345128210013350uOw","16312910846980013350yXL","16319302023020013350VjQ","16318858946340013350azO","16318858943670013350UyO","16318065232030013350ocm","16317263340200013350OAu","16318005347030013350xIY","89358414","16317823615620013350XTK","16304287461100013350mlf","16317340318160013350Tvh","90162384","16316425217580013350jtR","16317111609390013350kBm","16313011847990013350euT","16316739298570013350ubh","16316427345940013350FdR","16316254338250013350pnL","16315761396170013350NdW","16315527065980013350goJ","16315527103010013350OJR","16315527070820013350lNq","16315377284630013350kKy","16311282358380013350yvA","16311123863240013350poV","16311065501620013350xXk","16297520948230013350jsO","29381105","29121022","16297515193190013350yKq","16307003081530013350IRF","16298349408110013350fVu","16298344596880013350BkO","16306692819950013350PDG","16306692838930013350ZSc","16305973203140013350VLM","16305382326930013350ZIQ","16287824631380013350wvk","90296729","16303059379040013350mEr","16305210643780013350wHi","16298350433530013350pao","16300042451840013350bRI","28604324","29029504","29105759","16285320575270013350CGO","16292061450370013350IBs","29235622","16291317250860013350FZU","16292936844360013350FUf","28877294","90202677","90216110","90417725","29212684","29365774","16286918867350013350JMe","16285323789010013350Eaf","29205040","26759080","16297498617830013350rVR","16297359818350013350zUS","29059994","90471527","16285337043140013350ZKp","16281924024020013350syz","90148955","25996360","89385155","89371784","89518920","89505539","89438649","89398527","29373439"]

src/bootstrap.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Joi.page = () => Joi.number().integer().min(1).default(1)
1313
Joi.perPage = () => Joi.number().integer().min(1).default(20)
1414
Joi.rateType = () => Joi.string().valid('hourly', 'daily', 'weekly', 'monthly', 'annual')
1515
Joi.jobStatus = () => Joi.string().valid('sourcing', 'in-review', 'assigned', 'closed', 'cancelled')
16+
Joi.jobRcrmStatus = () => Joi.string().valid('Open', 'On Hold', 'Canceled', 'Draft', 'Closed').allow(null)
1617
Joi.jobTag = () => Joi.string().valid('New', '$$$', 'Hot').allow('')
1718
Joi.resourceBookingStatus = () => Joi.string().valid('placed', 'closed', 'cancelled')
1819
Joi.workload = () => Joi.string().valid('full-time', 'fractional')

src/models/Job.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,18 @@ module.exports = (sequelize) => {
164164
allowNull: true,
165165
defaultValue: ''
166166
},
167+
rcrmStatus: {
168+
field: 'rcrm_status',
169+
type: Sequelize.STRING(255),
170+
allowNull: true,
171+
defaultValue: null
172+
},
173+
rcrmReason: {
174+
field: 'rcrm_reason',
175+
type: Sequelize.STRING(255),
176+
allowNull: true,
177+
defaultValue: null
178+
},
167179
createdBy: {
168180
field: 'created_by',
169181
type: Sequelize.UUID,

src/services/JobService.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,9 @@ createJob.schema = Joi.object()
235235
showInHotList: Joi.boolean().default(false),
236236
featured: Joi.boolean().default(false),
237237
hotListExcerpt: Joi.stringAllowEmpty().default(''),
238-
jobTag: Joi.jobTag().default('')
238+
jobTag: Joi.jobTag().default(''),
239+
rcrmStatus: Joi.jobRcrmStatus().default('Open'),
240+
rcrmReason: Joi.string().allow(null).default(null)
239241
})
240242
.required(),
241243
onTeamCreating: Joi.boolean().default(false)
@@ -335,7 +337,9 @@ partiallyUpdateJob.schema = Joi.object()
335337
showInHotList: Joi.boolean(),
336338
featured: Joi.boolean(),
337339
hotListExcerpt: Joi.stringAllowEmpty(),
338-
jobTag: Joi.jobTag()
340+
jobTag: Joi.jobTag(),
341+
rcrmStatus: Joi.jobRcrmStatus(),
342+
rcrmReason: Joi.string().allow(null)
339343
})
340344
.required()
341345
})
@@ -379,7 +383,9 @@ fullyUpdateJob.schema = Joi.object().keys({
379383
showInHotList: Joi.boolean().default(false),
380384
featured: Joi.boolean().default(false),
381385
hotListExcerpt: Joi.stringAllowEmpty().default(''),
382-
jobTag: Joi.jobTag().default('')
386+
jobTag: Joi.jobTag().default(''),
387+
rcrmStatus: Joi.jobRcrmStatus().default(null),
388+
rcrmReason: Joi.string().allow(null).default(null)
383389
}).required()
384390
}).required()
385391

@@ -482,10 +488,11 @@ async function searchJobs (currentUser, criteria, options = { returnAll: false }
482488
'maxSalary',
483489
'jobLocation',
484490
'specialJob',
485-
'featured'
491+
'featured',
492+
'rcrmStatus'
486493
]), (value, key) => {
487494
let must
488-
if (key === 'description' || key === 'title') {
495+
if (key === 'description' || key === 'title' || key === 'rcrmStatus') {
489496
must = {
490497
match: {
491498
[key]: {
@@ -618,7 +625,8 @@ async function searchJobs (currentUser, criteria, options = { returnAll: false }
618625
'rateType',
619626
'workload',
620627
'status',
621-
'featured'
628+
'featured',
629+
'rcrmStatus'
622630
]), (value, key) => {
623631
filter[Op.and].push({ [key]: value })
624632
})
@@ -742,7 +750,8 @@ searchJobs.schema = Joi.object().keys({
742750
maxSalary: Joi.number().integer(),
743751
jobLocation: Joi.string(),
744752
specialJob: Joi.boolean(),
745-
featured: Joi.boolean()
753+
featured: Joi.boolean(),
754+
rcrmStatus: Joi.string().valid('Open', 'On Hold', 'Canceled', 'Draft', 'Closed')
746755
}).required(),
747756
options: Joi.object()
748757
}).required()

0 commit comments

Comments
 (0)