Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

Commit 556a1a1

Browse files
committed
Merge branch 'develop'
2 parents 3b9047f + 7d94bea commit 556a1a1

File tree

4 files changed

+109
-50
lines changed

4 files changed

+109
-50
lines changed

config/default.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,11 @@ module.exports = {
3232
V5_CHALLENGE_TYPE_API_URL: process.env.V5_CHALLENGE_TYPE_API_URL || 'http://localhost:4000/v5/challenge-types',
3333
V4_CHALLENGE_API_URL: process.env.V4_CHALLENGE_API_URL || 'http://localhost:4000/v4/challenges',
3434
V4_TECHNOLOGIES_API_URL: process.env.V4_TECHNOLOGIES_API_URL || 'http://localhost:4000/v4/technologies',
35-
V4_PLATFORMS_API_URL: process.env.V4_PLATFORMS_API_URL || 'http://localhost:4000/v4/platforms'
35+
V4_PLATFORMS_API_URL: process.env.V4_PLATFORMS_API_URL || 'http://localhost:4000/v4/platforms',
36+
V5_PROJECTS_API_URL: process.env.V5_PROJECTS_API_URL || 'https://api.topcoder-dev.com/v5/projects',
37+
38+
// PHASE IDs
39+
REGISTRATION_PHASE_ID: process.env.REGISTRATION_PHASE_ID || 'a93544bc-c165-4af4-b55e-18f3593b457a',
40+
SUBMISSION_PHASE_ID: process.env.SUBMISSION_PHASE_ID || '6950164f-3c5e-4bdc-abc8-22aaf5a1bd49',
41+
CHECKPOINT_SUBMISSION_PHASE_ID: process.env.CHECKPOINT_SUBMISSION_PHASE_ID || 'd8a2cdbe-84d1-4687-ab75-78a6a7efdcc8'
3642
}

src/constants.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,28 @@ const prizeSetTypes = {
77
CheckPoint: 'Check Point'
88
}
99

10-
const phaseTypes = {
11-
registration: 'registration',
12-
submission: 'submission',
13-
checkpoint: 'checkpoint'
14-
}
15-
1610
const EVENT_ORIGINATOR = 'legacy-challenge-processor'
1711

1812
const EVENT_MIME_TYPE = 'application/json'
1913

2014
const createChallengeStatusesMap = {
2115
Active: 1,
22-
Draft: 2
16+
Draft: 2,
17+
New: 2
18+
}
19+
20+
const challengeStatuses = {
21+
New: 'New',
22+
Draft: 'Draft',
23+
Canceled: 'Canceled',
24+
Active: 'Active',
25+
Completed: 'Completed'
2326
}
2427

2528
module.exports = {
2629
prizeSetTypes,
27-
phaseTypes,
2830
EVENT_ORIGINATOR,
2931
EVENT_MIME_TYPE,
30-
createChallengeStatusesMap
32+
createChallengeStatusesMap,
33+
challengeStatuses
3134
}

src/services/ProcessorService.js

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ async function getPlatforms (m2mToken) {
4141
*/
4242
async function getChallengeById (m2mToken, legacyId) {
4343
const response = await helper.getRequest(`${config.V4_CHALLENGE_API_URL}/${legacyId}`, m2mToken)
44+
return _.get(response, 'body.result.content[0]')
45+
}
46+
47+
/**
48+
* Get Project from V5 API
49+
* @param {String} m2mToken token for accessing the API
50+
* @param {Number} projectId project id
51+
* @returns {Object} project response body
52+
*/
53+
async function getDirectProjectId (m2mToken, projectId) {
54+
const response = await helper.getRequest(`${config.V5_PROJECTS_API_URL}/${projectId}`, m2mToken)
4455
return response.body
4556
}
4657

@@ -53,29 +64,36 @@ async function getChallengeById (m2mToken, legacyId) {
5364
*/
5465
async function parsePayload (payload, m2mToken, isCreated = true) {
5566
try {
67+
let projectId
68+
if (_.get(payload, 'legacy.directProjectId')) {
69+
projectId = payload.legacy.directProjectId
70+
} else {
71+
projectId = _.get((await getDirectProjectId(m2mToken, payload.projectId)), 'directProjectId')
72+
if (!projectId) throw new Error(`Could not find Direct Project ID for Project ${payload.projectId}`)
73+
}
5674
const data = {
57-
track: payload.track, // FIXME: thomas
75+
track: _.get(payload, 'legacy.track'), // FIXME: thomas
5876
name: payload.name,
59-
reviewType: payload.reviewType,
60-
projectId: payload.projectId,
77+
reviewType: _.get(payload, 'legacy.reviewType'),
78+
projectId,
6179
status: payload.status
6280
}
63-
if (payload.forumId) {
64-
data.forumId = payload.forumId
81+
if (_.get(payload, 'legacy.forumId')) {
82+
data.forumId = payload.legacy.forumId
6583
}
6684
if (payload.copilotId) {
6785
data.copilotId = payload.copilotId
6886
}
6987
if (isCreated) {
7088
// hard code some required properties for v4 api
71-
data.confidentialityType = 'public'
89+
data.confidentialityType = _.get(payload, 'legacy.confidentialityType', 'public')
7290
data.submissionGuidelines = 'Please read above'
7391
data.submissionVisibility = true
7492
data.milestoneId = 1
7593
}
7694
if (payload.typeId) {
7795
const typeRes = await helper.getRequest(`${config.V5_CHALLENGE_TYPE_API_URL}/${payload.typeId}`, m2mToken)
78-
data.subTrack = typeRes.body.name // FIXME: thomas
96+
data.subTrack = typeRes.body.abbreviation // FIXME: thomas
7997
data.legacyTypeId = typeRes.body.legacyId
8098
}
8199
if (payload.description) {
@@ -93,16 +111,16 @@ async function parsePayload (payload, m2mToken, isCreated = true) {
93111
}
94112
}
95113
if (payload.phases) {
96-
const registrationPhase = _.find(payload.phases, p => p.name.toLowerCase() === constants.phaseTypes.registration)
97-
const submissionPhase = _.find(payload.phases, p => p.name.toLowerCase() === constants.phaseTypes.submission)
114+
const registrationPhase = _.find(payload.phases, p => p.phaseId === config.REGISTRATION_PHASE_ID)
115+
const submissionPhase = _.find(payload.phases, p => p.phaseId === config.SUBMISSION_PHASE_ID)
98116
data.registrationStartsAt = new Date().toISOString()
99117
data.registrationEndsAt = new Date(Date.now() + registrationPhase.duration).toISOString()
100118
data.registrationDuration = registrationPhase.duration
101119
data.submissionEndsAt = new Date(Date.now() + submissionPhase.duration).toISOString()
102120
data.submissionDuration = submissionPhase.duration
103121

104122
// Only Design can have checkpoint phase and checkpoint prizes
105-
const checkpointPhase = _.find(payload.phases, p => p.name.toLowerCase() === constants.phaseTypes.checkpoint)
123+
const checkpointPhase = _.find(payload.phases, p => p.phaseId === config.CHECKPOINT_SUBMISSION_PHASE_ID)
106124
if (checkpointPhase) {
107125
data.checkpointSubmissionStartsAt = new Date().toISOString()
108126
data.checkpointSubmissionEndsAt = new Date(Date.now() + checkpointPhase.duration).toISOString()
@@ -163,6 +181,10 @@ async function parsePayload (payload, m2mToken, isCreated = true) {
163181
* @param {Object} message the kafka message
164182
*/
165183
async function processCreate (message) {
184+
if (message.payload.status === constants.challengeStatuses.New) {
185+
logger.debug(`Will skip creating on legacy as status is ${constants.challengeStatuses.New}`)
186+
return
187+
}
166188
const m2mToken = await helper.getM2MToken()
167189

168190
const saveDraftContestDTO = await parsePayload(message.payload, m2mToken)
@@ -172,7 +194,15 @@ async function processCreate (message) {
172194
logger.debug('processCreate :: beforeTry')
173195
try {
174196
const newChallenge = await helper.postRequest(`${config.V4_CHALLENGE_API_URL}`, { param: saveDraftContestDTO }, m2mToken)
175-
await helper.patchRequest(`${config.V5_CHALLENGE_API_URL}/${challengeUuid}`, { legacyId: newChallenge.body.result.content.id }, m2mToken)
197+
await helper.patchRequest(`${config.V5_CHALLENGE_API_URL}/${challengeUuid}`, {
198+
legacy: {
199+
...message.payload.legacy,
200+
directProjectId: newChallenge.body.result.content.projectId,
201+
forumId: _.get(newChallenge, 'body.result.content.forumId', message.payload.legacy.forumId),
202+
informixModified: _.get(newChallenge, 'body.result.content.updatedAt', new Date())
203+
},
204+
legacyId: newChallenge.body.result.content.id
205+
}, m2mToken)
176206
logger.debug('End of processCreate')
177207
} catch (e) {
178208
logger.error('processCreate Catch', e)
@@ -188,26 +218,29 @@ processCreate.schema = {
188218
'mime-type': Joi.string().required(),
189219
payload: Joi.object().keys({
190220
id: Joi.string().required(),
191-
typeId: Joi.string().required(),
192-
track: Joi.string().required(),
221+
typeId: Joi.string(),
222+
legacy: Joi.object().keys({
223+
track: Joi.string().required(),
224+
reviewType: Joi.string().required(),
225+
confidentialityType: Joi.string(),
226+
directProjectId: Joi.number(),
227+
forumId: Joi.number().integer().positive()
228+
}),
193229
name: Joi.string().required(),
194-
description: Joi.string().required(),
230+
description: Joi.string(),
195231
privateDescription: Joi.string(),
196232
phases: Joi.array().items(Joi.object().keys({
197233
id: Joi.string().required(),
198-
name: Joi.string().required(),
199234
duration: Joi.number().positive().required()
200-
}).unknown(true)).min(1).required(),
235+
}).unknown(true)),
201236
prizeSets: Joi.array().items(Joi.object().keys({
202237
type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(),
203238
prizes: Joi.array().items(Joi.object().keys({
204239
value: Joi.number().positive().required()
205240
}).unknown(true)).min(1).required()
206-
}).unknown(true)).min(1).required(),
207-
reviewType: Joi.string().required(),
208-
tags: Joi.array().items(Joi.string().required()).min(1).required(), // tag names
241+
}).unknown(true)),
242+
tags: Joi.array().items(Joi.string().required()), // tag names
209243
projectId: Joi.number().integer().positive().required(),
210-
forumId: Joi.number().integer().positive(),
211244
copilotId: Joi.number().integer().positive().optional(),
212245
status: Joi.string().valid(_.values(Object.keys(constants.createChallengeStatusesMap))).required()
213246
}).unknown(true).required()
@@ -219,24 +252,35 @@ processCreate.schema = {
219252
* @param {Object} message the kafka message
220253
*/
221254
async function processUpdate (message) {
255+
if (message.payload.status === constants.challengeStatuses.New) {
256+
logger.debug(`Will skip creating on legacy as status is ${constants.challengeStatuses.New}`)
257+
return
258+
} else if (!message.payload.legacyId) {
259+
logger.debug('Legacy ID does not exist. Will create...')
260+
return processCreate(message)
261+
}
222262
const m2mToken = await helper.getM2MToken()
223263

224264
const saveDraftContestDTO = await parsePayload(message.payload, m2mToken, false)
225265
logger.debug('Parsed Payload', saveDraftContestDTO)
226266
try {
227267
// ensure challenge existed
228268
const challenge = await getChallengeById(m2mToken, message.payload.legacyId)
229-
// we can't switch the challenge type
230-
if (message.payload.track) {
231-
const newTrack = message.payload.track
232-
// track information is stored in subTrack of V4 API
233-
if (challenge.result.content.track !== newTrack) {
234-
// refer ContestDirectManager.prepare in ap-challenge-microservice
235-
throw new Error('You can\'t change challenge track')
236-
}
269+
if (!challenge) {
270+
throw new Error(`Could not find challenge ${message.payload.legacyId}`)
237271
}
272+
// we can't switch the challenge type
273+
// TODO: track is missing from the response.
274+
// if (message.payload.legacy.track) {
275+
// const newTrack = message.payload.legacy.track
276+
// // track information is stored in subTrack of V4 API
277+
// if (challenge.track !== newTrack) {
278+
// // refer ContestDirectManager.prepare in ap-challenge-microservice
279+
// throw new Error('You can\'t change challenge track')
280+
// }
281+
// }
238282

239-
await helper.putRequest(`${config.V4_CHALLENGE_API_URL}/${message.payload.legacyId}`, { param: saveDraftContestDTO })
283+
await helper.putRequest(`${config.V4_CHALLENGE_API_URL}/${message.payload.legacyId}`, { param: saveDraftContestDTO }, m2mToken)
240284
} catch (e) {
241285
logger.error('processUpdate Catch', e)
242286
throw e
@@ -250,27 +294,31 @@ processUpdate.schema = {
250294
timestamp: Joi.date().required(),
251295
'mime-type': Joi.string().required(),
252296
payload: Joi.object().keys({
253-
legacyId: Joi.number().integer().positive().required(),
297+
legacyId: Joi.number().integer().positive(),
298+
legacy: Joi.object().keys({
299+
track: Joi.string().required(),
300+
reviewType: Joi.string().required(),
301+
confidentialityType: Joi.string(),
302+
directProjectId: Joi.number(),
303+
forumId: Joi.number().integer().positive(),
304+
informixModified: Joi.string()
305+
}),
254306
typeId: Joi.string(),
255-
track: Joi.string(),
256307
name: Joi.string(),
257308
description: Joi.string(),
258309
privateDescription: Joi.string(),
259310
phases: Joi.array().items(Joi.object().keys({
260311
id: Joi.string().required(),
261-
name: Joi.string().required(),
262312
duration: Joi.number().positive().required()
263-
}).unknown(true)).min(1),
313+
}).unknown(true)),
264314
prizeSets: Joi.array().items(Joi.object().keys({
265315
type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(),
266316
prizes: Joi.array().items(Joi.object().keys({
267317
value: Joi.number().positive().required()
268-
}).unknown(true)).min(1).required()
318+
}).unknown(true))
269319
}).unknown(true)).min(1),
270-
reviewType: Joi.string(),
271320
tags: Joi.array().items(Joi.string().required()).min(1), // tag names
272-
projectId: Joi.number().integer().positive(),
273-
forumId: Joi.number().integer().positive()
321+
projectId: Joi.number().integer().positive().allow(null)
274322
}).unknown(true).required()
275323
}).required()
276324
}

test/common/testData.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ module.exports = {
1212
payload: {
1313
id: '1a4ef3a8-ed35-40d1-b8a6-7371a700d011',
1414
typeId: '2f4ef3a8-ed35-40d1-b8a6-7371a700d098',
15-
track: 'CODE',
15+
legacy: {
16+
track: 'CODE',
17+
reviewType: 'COMMUNITY',
18+
forumId: 33059
19+
},
1620
name: 'test-for-legacy-challenge-processor',
1721
description: '<p>test</p>',
1822
phases: [
@@ -24,11 +28,9 @@ module.exports = {
2428
{ type: 'Challenge prizes', prizes: [{ type: 'first-place', value: 1000 }, { type: 'second-place', value: 500 }] },
2529
{ type: 'Check Point', prizes: [{ type: 'first-place', value: 200 }, { type: 'second-place', value: 200 }, { type: 'third-place', value: 200 }] }
2630
],
27-
reviewType: 'COMMUNITY',
2831
markdown: false,
2932
tags: ['Node.js', 'NodeJS', 'MongoDB', 'AWS'],
3033
projectId: 5087,
31-
forumId: 33059,
3234
status: 'Draft'
3335
}
3436
},

0 commit comments

Comments
 (0)