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

Commit 94c3a9b

Browse files
author
James Cori
committed
Merge branch 'develop'
2 parents 84d63ad + 3d7c879 commit 94c3a9b

File tree

6 files changed

+283
-49
lines changed

6 files changed

+283
-49
lines changed

config/default.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ module.exports = {
4949
// Topcoder APIs
5050
V5_CHALLENGE_API_URL: process.env.V5_CHALLENGE_API_URL || 'http://localhost:4000/v5/challenges',
5151
V5_RESOURCES_API_URL: process.env.V5_RESOURCES_API_URL || 'http://localhost:4000/v5/resources',
52+
V5_TERMS_API_URL: process.env.V5_TERMS_API_URL || 'http://localhost:4000/v5/terms',
53+
V5_RESOURCE_ROLES_API_URL: process.env.V5_RESOURCE_ROLES_API_URL || 'http://localhost:4000/v5/resource-roles',
54+
5255
V5_CHALLENGE_TYPE_API_URL: process.env.V5_CHALLENGE_TYPE_API_URL || 'http://localhost:4000/v5/challenge-types',
5356
V4_CHALLENGE_TYPE_API_URL: process.env.V4_CHALLENGE_TYPE_API_URL || 'http://localhost:4000/v4/challenge-types',
5457
V4_CHALLENGE_API_URL: process.env.V4_CHALLENGE_API_URL || 'http://localhost:4000/v4/challenges',
@@ -65,5 +68,9 @@ module.exports = {
6568
SUBMISSION_PHASE_ID: process.env.SUBMISSION_PHASE_ID || '6950164f-3c5e-4bdc-abc8-22aaf5a1bd49',
6669
CHECKPOINT_SUBMISSION_PHASE_ID: process.env.CHECKPOINT_SUBMISSION_PHASE_ID || 'd8a2cdbe-84d1-4687-ab75-78a6a7efdcc8',
6770

71+
V5_TERMS_NDA_ID: process.env.V5_TERMS_NDA_ID || '77f558c1-56fb-427c-b974-61ea0a060ca7',
72+
LEGACY_TERMS_NDA_ID: process.env.LEGACY_TERMS_NDA_ID || 21343,
73+
LEGACY_SUBMITTER_ROLE_ID: process.env.LEGACY_SUBMITTER_ROLE_ID || 1,
74+
6875
COPILOT_PAYMENT_TYPE: process.env.COPILOT_PAYMENT_TYPE || 'copilot'
6976
}

src/app.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
require('./bootstrap')
6+
const _ = require('lodash')
67
const config = require('config')
78
const Kafka = require('no-kafka')
89
const healthcheck = require('@topcoder-platform/topcoder-healthcheck-dropin')
@@ -45,9 +46,25 @@ const dataHandler = (messageSet, topic, partition) => Promise.each(messageSet, a
4546
return
4647
}
4748

49+
// do not trust the message payload
50+
// the message.payload will be replaced with the data from the API
51+
try {
52+
const challengeUuid = _.get(messageJSON, 'payload.id')
53+
if (_.isEmpty(challengeUuid)) {
54+
throw new Error('Invalid payload')
55+
}
56+
const m2mToken = await helper.getM2MToken()
57+
const v5Challenge = await helper.getRequest(`${config.V5_CHALLENGE_API_URL}/${challengeUuid}`, m2mToken)
58+
messageJSON.payload = v5Challenge.body
59+
} catch (err) {
60+
logger.debug('Failed to fetch challenge information')
61+
logger.logFullError(err)
62+
}
63+
4864
try {
4965
if (topic === config.CREATE_CHALLENGE_TOPIC) {
50-
await ProcessorService.processCreate(messageJSON)
66+
// create shut off. Only works with challenges of status draft, which happens on update
67+
// await ProcessorService.processCreate(messageJSON)
5168
} else {
5269
await ProcessorService.processUpdate(messageJSON)
5370
}

src/common/helper.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const request = require('superagent')
99
const m2mAuth = require('tc-core-library-js').auth.m2m
1010
const busApi = require('@topcoder-platform/topcoder-bus-api-wrapper')
1111
const constants = require('../constants')
12+
const logger = require('../common/logger')
1213
const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL']))
1314

1415
const Pool = ifxnjs.Pool
@@ -64,6 +65,7 @@ async function getM2MToken () {
6465
* @returns {Object} the response
6566
*/
6667
async function patchRequest (url, body, m2mToken) {
68+
logger.debug(`Patch Request Body: ${JSON.stringify(body)}`)
6769
return request
6870
.patch(url)
6971
.send(body)

src/services/ProcessorService.js

Lines changed: 122 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ const logger = require('../common/logger')
1111
const helper = require('../common/helper')
1212
const constants = require('../constants')
1313
const groupService = require('./groupsService')
14+
const termsService = require('./termsService')
1415
const copilotPaymentService = require('./copilotPaymentService')
15-
// TODO: Remove this
16-
// const showdown = require('showdown')
17-
// const converter = new showdown.Converter()
1816

1917
/**
2018
* Get group information by V5 UUID
@@ -26,30 +24,85 @@ async function getGroup (v5GroupId, m2mToken) {
2624
return response.body
2725
}
2826

27+
/**
28+
* Get terms information by V5 UUID
29+
* @param {String} v5TermsId the v5 terms UUID
30+
* @param {String} m2mToken token for accessing the API
31+
*/
32+
async function getV5Terms (v5TermsId, m2mToken) {
33+
const response = await helper.getRequest(`${config.V5_TERMS_API_URL}/${v5TermsId}`, m2mToken)
34+
return response.body
35+
}
36+
37+
// /**
38+
// * Get resource role information by V5 UUID
39+
// * @param {String} v5RoleId the v5 role UUID
40+
// * @param {String} m2mToken token for accessing the API
41+
// */
42+
// async function getV5Role (v5RoleId, m2mToken) {
43+
// const response = await helper.getRequest(`${config.V5_RESOURCE_ROLES_API_URL}?id=${v5RoleId}`, m2mToken)
44+
// return response.body[0]
45+
// }
46+
2947
/**
3048
* Associate challenge groups
3149
* @param {Array<String>} toBeAdded the array of groups to be added
3250
* @param {Array<String>} toBeDeleted the array of groups to be deleted
33-
* @param {String|Number} challengeId the legacy challenge ID
51+
* @param {String|Number} legacyChallengeId the legacy challenge ID
3452
*/
35-
async function associateChallengeGroups (toBeAdded = [], toBeDeleted = [], challengeId) {
53+
async function associateChallengeGroups (toBeAdded = [], toBeDeleted = [], legacyChallengeId) {
3654
for (const group of toBeAdded) {
37-
await groupService.addGroupToChallenge(challengeId, group)
55+
await groupService.addGroupToChallenge(legacyChallengeId, group)
3856
}
3957
for (const group of toBeDeleted) {
40-
await groupService.removeGroupFromChallenge(challengeId, group)
58+
await groupService.removeGroupFromChallenge(legacyChallengeId, group)
59+
}
60+
}
61+
62+
/**
63+
* Associate challenge terms
64+
* @param {Array<Object{termsId, roleId}>} toBeAdded the array of terms to be added
65+
* @param {Array<Object{termsId, roleId}>} toBeDeleted the array of terms to be deleted
66+
* @param {String|Number} legacyChallengeId the legacy challenge ID
67+
*/
68+
async function associateChallengeTerms (v5Terms, legacyChallengeId) {
69+
const nda = _.find(v5Terms, e => e.id === config.V5_TERMS_NDA_ID)
70+
const legacyTermsArray = await termsService.getTermsForChallenge(legacyChallengeId)
71+
const legacyNDA = _.find(legacyTermsArray, e => _.toNumber(e.id) === _.toNumber(config.LEGACY_TERMS_NDA_ID))
72+
73+
// logger.debug(`V5 Terms ${JSON.stringify(v5Terms)}`)
74+
// logger.debug(`V5 NDA Found ${nda} ${JSON.stringify(nda)}`)
75+
76+
// logger.debug(`Legacy Terms ${JSON.stringify(legacyTermsArray)}`)
77+
// logger.debug(`Legacy NDA Found ${JSON.stringify(legacyNDA)}`)
78+
79+
if (nda && nda.id && !legacyNDA) {
80+
logger.debug('Associate Challenge Terms - v5 NDA exist, not in legacy. Adding to Legacy.')
81+
const m2mToken = await helper.getM2MToken()
82+
const v5Term = await getV5Terms(nda.id, m2mToken)
83+
return termsService.addTermsToChallenge(legacyChallengeId, v5Term.legacyId, config.LEGACY_SUBMITTER_ROLE_ID)
4184
}
85+
86+
if (!nda && legacyNDA && legacyNDA.id) {
87+
logger.debug('Associate Challenge Terms - Legacy NDA exist, not in V5. Removing from Legacy.')
88+
return termsService.removeTermsFromChallenge(legacyChallengeId, legacyNDA.id, config.LEGACY_SUBMITTER_ROLE_ID)
89+
}
90+
91+
logger.debug('Associate Challenge Terms - Nothing to Do')
4292
}
4393

4494
/**
4595
* Set the copilot payment on legacy
4696
* @param {Number|String} legacyChallengeId the legacy challenge ID
4797
* @param {Array} prizeSets the prizeSets array
98+
* @param {String} createdBy the created by handle
99+
* @param {String} updatedBy the updated by handle
48100
*/
49-
async function setCopilotPayment (legacyChallengeId, prizeSets = []) {
101+
async function setCopilotPayment (legacyChallengeId, prizeSets = [], createdBy, updatedBy) {
50102
try {
51103
const copilotPayment = _.get(_.find(prizeSets, p => p.type === config.COPILOT_PAYMENT_TYPE), 'prizes[0].value', null)
52-
await copilotPaymentService.setCopilotPayment(legacyChallengeId, copilotPayment)
104+
logger.debug(`Setting Copilot Payment: ${copilotPayment} for legacyId ${legacyChallengeId}`)
105+
await copilotPaymentService.setCopilotPayment(legacyChallengeId, copilotPayment, createdBy, updatedBy)
53106
} catch (e) {
54107
logger.error('Failed to set the copilot payment!')
55108
logger.debug(e)
@@ -137,9 +190,10 @@ async function getLegacyTrackInformation (trackId, typeId, tags, m2mToken) {
137190
* @param {String} m2mToken the m2m token
138191
* @param {Boolean} isCreated flag indicate the DTO is used in creating challenge
139192
* @param {Array} informixGroupIds IDs from Informix associated with the group
193+
* @param {Array<Object>} informixTermsIds IDs from Informix [{termsId, roleId}]
140194
* @returns the DTO for saving a draft contest.(refer SaveDraftContestDTO in ap-challenge-microservice)
141195
*/
142-
async function parsePayload (payload, m2mToken, isCreated = true, informixGroupIds) {
196+
async function parsePayload (payload, m2mToken, isCreated = true, informixGroupIds, informixTermsArray) {
143197
try {
144198
let projectId
145199
if (_.get(payload, 'legacy.directProjectId')) {
@@ -256,6 +310,40 @@ async function parsePayload (payload, m2mToken, isCreated = true, informixGroupI
256310
} else if (informixGroupIds && informixGroupIds.length > 0) {
257311
data.groupsToBeDeleted = _.map(informixGroupIds, g => _.toString(g))
258312
}
313+
314+
// if (payload.terms && _.get(payload, 'terms.length', 0) > 0) {
315+
// const oldTerms = informixGroupIds
316+
// const newTerms = []
317+
318+
// for (const v5TermsObject of payload.terms) {
319+
// try {
320+
// const termsInfo = await getV5Terms(v5TermsObject.id, m2mToken)
321+
// if (!_.isEmpty(_.get(termsInfo, 'legacyId'))) {
322+
// const roleInfo = await getV5Role(v5TermsObject.roleId, m2mToken)
323+
// if (!_.isEmpty(_.get(roleInfo, 'legacyId'))) {
324+
// newTerms.push({ id: _.get(termsInfo, 'legacyId'), roleId: _.get(roleInfo, 'legacyId') })
325+
// }
326+
// }
327+
// } catch (e) {
328+
// logger.warn(`Failed to load details for terms ${v5TermsObject}`)
329+
// }
330+
// }
331+
// data.termsToBeAdded = _.difference(newTerms, oldTerms)
332+
// data.termsToBeDeleted = _.difference(oldTerms, newTerms)
333+
// if (data.termsToBeAdded.length > 0) {
334+
// logger.debug(`parsePayload :: Adding Terms ${JSON.stringify(data.termsToBeAdded)}`)
335+
// }
336+
// if (data.termsToBeDeleted.length > 0) {
337+
// logger.debug(`parsePayload :: Deleting Terms ${JSON.stringify(data.termsToBeDeleted)}`)
338+
// }
339+
// }
340+
// // TODO Do not remove terms
341+
// // } else if (informixTermsArray && informixTermsArray.length > 0) {
342+
// // data.termsToBeDeleted = _.map(informixTermsArray, o => ({ id: o.id, roleId: o.roleId }))
343+
// // }
344+
// logger.debug(`parsePayload V5 Terms ${JSON.stringify(payload.terms)}`)
345+
// logger.debug(`parsePayload legacy Terms ${JSON.stringify(informixTermsArray)}`)
346+
259347
return data
260348
} catch (err) {
261349
// Debugging
@@ -309,7 +397,8 @@ async function processCreate (message) {
309397
const newChallenge = await helper.postRequest(`${config.V4_CHALLENGE_API_URL}`, { param: _.omit(saveDraftContestDTO, ['groupsToBeAdded', 'groupsToBeDeleted']) }, m2mToken)
310398
await helper.forceV4ESFeeder(newChallenge.body.result.content.id)
311399
await associateChallengeGroups(saveDraftContestDTO.groupsToBeAdded, saveDraftContestDTO.groupsToBeDeleted, newChallenge.body.result.content.id)
312-
await setCopilotPayment(newChallenge.body.result.content.id, _.get(message, 'payload.prizeSets'))
400+
// await associateChallengeTerms(saveDraftContestDTO.termsToBeAdded, saveDraftContestDTO.termsToBeRemoved, newChallenge.body.result.content.id)
401+
await setCopilotPayment(newChallenge.body.result.content.id, _.get(message, 'payload.prizeSets'), _.get(message, 'payload.createdBy'), _.get(message, 'payload.updatedBy'))
313402
await helper.patchRequest(`${config.V5_CHALLENGE_API_URL}/${challengeUuid}`, {
314403
legacy: {
315404
...message.payload.legacy,
@@ -402,34 +491,37 @@ async function processUpdate (message) {
402491
}
403492
} catch (e) {
404493
// postponne kafka event
405-
logger.info('Challenge does not exist yet. Will post the same message back to the bus API')
406-
logger.error(`Error: ${JSON.stringify(e)}`)
407-
408-
const retryCountIdentifier = `${config.KAFKA_GROUP_ID.split(' ').join('_')}_retry_count`
409-
let currentRetryCount = parseInt(_.get(message.payload, retryCountIdentifier, 1), 10)
410-
if (currentRetryCount <= config.MAX_RETRIES) {
411-
await new Promise((resolve) => {
412-
setTimeout(async () => {
413-
currentRetryCount += 1
414-
await helper.postBusEvent(config.UPDATE_CHALLENGE_TOPIC, { ...message.payload, [retryCountIdentifier]: currentRetryCount })
415-
resolve()
416-
}, config.RETRY_TIMEOUT * currentRetryCount)
417-
})
418-
} else {
419-
logger.error(`Failed to process message after ${config.MAX_RETRIES} retries. Aborting...`)
420-
}
421-
return
494+
logger.warn(`Error getting challenge by id, RETRY TURNED OFF ${JSON.stringify(e)}`)
495+
// logger.info('Challenge does not exist yet. Will post the same message back to the bus API')
496+
// logger.error(`Error: ${JSON.stringify(e)}`)
497+
498+
// const retryCountIdentifier = `${config.KAFKA_GROUP_ID.split(' ').join('_')}_retry_count`
499+
// let currentRetryCount = parseInt(_.get(message.payload, retryCountIdentifier, 1), 10)
500+
// if (currentRetryCount <= config.MAX_RETRIES) {
501+
// await new Promise((resolve) => {
502+
// setTimeout(async () => {
503+
// currentRetryCount += 1
504+
// await helper.postBusEvent(config.UPDATE_CHALLENGE_TOPIC, { ...message.payload, [retryCountIdentifier]: currentRetryCount })
505+
// resolve()
506+
// }, config.RETRY_TIMEOUT * currentRetryCount)
507+
// })
508+
// } else {
509+
// logger.error(`Failed to process message after ${config.MAX_RETRIES} retries. Aborting...`)
510+
// }
511+
// return
422512
}
423513

424514
const v4GroupIds = await groupService.getGroupsForChallenge(message.payload.legacyId)
425515
logger.info(`GroupIDs Found in Informix: ${JSON.stringify(v4GroupIds)}`)
516+
// const v4TermsIds = await termsService.getTermsForChallenge(message.payload.legacyId)
426517

427518
const saveDraftContestDTO = await parsePayload(message.payload, m2mToken, false, v4GroupIds)
428519
// logger.debug('Parsed Payload', saveDraftContestDTO)
429520
try {
430521
await helper.putRequest(`${config.V4_CHALLENGE_API_URL}/${message.payload.legacyId}`, { param: _.omit(saveDraftContestDTO, ['groupsToBeAdded', 'groupsToBeDeleted']) }, m2mToken)
431522
await associateChallengeGroups(saveDraftContestDTO.groupsToBeAdded, saveDraftContestDTO.groupsToBeDeleted, message.payload.legacyId)
432-
await setCopilotPayment(message.payload.legacyId, _.get(message, 'payload.prizeSets'))
523+
await associateChallengeTerms(message.payload.terms, message.payload.legacyId)
524+
await setCopilotPayment(message.payload.legacyId, _.get(message, 'payload.prizeSets'), _.get(message, 'payload.createdBy'), _.get(message, 'payload.updatedBy'))
433525

434526
if (message.payload.status) {
435527
// logger.info(`The status has changed from ${challenge.currentStatus} to ${message.payload.status}`)
@@ -439,9 +531,7 @@ async function processUpdate (message) {
439531
logger.info('Activated!')
440532
}
441533
if (message.payload.status === constants.challengeStatuses.Completed && challenge.currentStatus !== constants.challengeStatuses.Completed) {
442-
const challengeUuid = message.payload.id
443-
const v5Challenge = await helper.getRequest(`${config.V5_CHALLENGE_API_URL}/${challengeUuid}`, m2mToken)
444-
if (v5Challenge.body.task.isTask) {
534+
if (message.payload.task.isTask) {
445535
logger.info('Challenge is a TASK')
446536
if (!message.payload.winners || message.payload.winners.length === 0) {
447537
throw new Error('Cannot close challenge without winners')

0 commit comments

Comments
 (0)