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

Commit 0fb6673

Browse files
Update timelines and member payments directly in ifx
1 parent 99386a2 commit 0fb6673

File tree

4 files changed

+258
-7
lines changed

4 files changed

+258
-7
lines changed

src/constants.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,22 @@ const challengeStatuses = {
4545
CancelledZeroRegistrations: 'Cancelled - Zero Registrations'
4646
}
4747

48+
const PhaseStatusTypes = {
49+
Open: 2,
50+
Closed: 3
51+
}
52+
53+
const prizeTypesIds = {
54+
Contest: 15,
55+
Checkpoint: 14
56+
}
57+
4858
module.exports = {
4959
prizeSetTypes,
5060
EVENT_ORIGINATOR,
5161
EVENT_MIME_TYPE,
5262
createChallengeStatusesMap,
53-
challengeStatuses
63+
challengeStatuses,
64+
PhaseStatusTypes,
65+
prizeTypesIds
5466
}

src/services/ProcessorService.js

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,71 @@ const constants = require('../constants')
1313
const groupService = require('./groupsService')
1414
const termsService = require('./termsService')
1515
const copilotPaymentService = require('./copilotPaymentService')
16+
const timelineService = require('./timelineService')
17+
const paymentService = require('./paymentService')
18+
19+
/**
20+
* Sync the information from the v5 phases into legacy
21+
* @param {Number} legacyId the legacy challenge ID
22+
* @param {Array} v4Phases the v4 phases
23+
* @param {Array} v5Phases the v5 phases
24+
*/
25+
async function syncChallengePhases (legacyId, v5Phases) {
26+
const phaseTypes = await timelineService.getPhaseTypes()
27+
const phasesFromIFx = await timelineService.getChallengePhases(legacyId)
28+
for (const phase of phasesFromIFx) {
29+
const phaseName = _.get(_.find(phaseTypes, pt => pt.phase_type_id === phase.phase_type_id), 'name')
30+
const v5Equivalent = _.find(v5Phases, p => p.name === phaseName)
31+
if (v5Equivalent) {
32+
// Compare duration and status
33+
if (v5Equivalent.duration * 1000 !== phase.duration ||
34+
(v5Equivalent.isOpen && _.toInteger(phase.phase_status_id) === constants.PhaseStatusTypes.Closed) ||
35+
(!v5Equivalent.isOpen && _.toInteger(phase.phase_status_id) === constants.PhaseStatusTypes.Open)) {
36+
// update phase
37+
await timelineService.updatePhase(
38+
phase.project_phase_id,
39+
legacyId,
40+
v5Equivalent.scheduledStartDate,
41+
v5Equivalent.scheduledEndDate,
42+
v5Equivalent.duration * 1000,
43+
v5Equivalent.isOpen ? constants.PhaseStatusTypes.Open : constants.PhaseStatusTypes.Closed)
44+
}
45+
}
46+
}
47+
}
48+
49+
/**
50+
* Update the payments from v5 prize sets into legacy
51+
* @param {Array} v4Prizes the v4 prizes
52+
* @param {Number} v4NumOfCheckpointPrizes the number of checkpoints (v4)
53+
* @param {Number} v4CheckpointPrize the dollar ammount of each checkpoint prize (v4)
54+
* @param {Array} v5PrizeSets the v5 prize sets
55+
*/
56+
async function updateMemberPayments (legacyId, v5PrizeSets) {
57+
const prizesFromIfx = await paymentService.getChallengePrizes(legacyId, constants.prizeTypesIds.Contest)
58+
const [checkpointPrizesFromIfx] = await paymentService.getChallengePrizes(legacyId, constants.prizeTypesIds.Checkpoint)
59+
const v5Prizes = _.map(_.get(_.find(v5PrizeSets, p => p.type === constants.prizeSetTypes.ChallengePrizes), 'prizes', []), prize => prize.value)
60+
const v5CheckPointPrizes = _.map(_.get(_.find(v5PrizeSets, p => p.type === constants.prizeSetTypes.CheckPoint), 'prizes', []), prize => prize.value)
61+
// compare prizes
62+
if (v5Prizes && v5Prizes.length > 0) {
63+
v5Prizes.sort((a, b) => b - a)
64+
for (let i = 0; i < v5Prizes.length; i += 1) {
65+
const ifxPrize = _.find(prizesFromIfx, p => p.place === i + 1)
66+
if (ifxPrize) {
67+
if (_.toInteger(ifxPrize.prize_amount) !== v5Prizes[i]) {
68+
await paymentService.updatePrize(ifxPrize.prize_id, legacyId, v5Prizes[i], 1)
69+
}
70+
}
71+
}
72+
}
73+
// compare checkpoint prizes
74+
if (v5CheckPointPrizes && v5CheckPointPrizes.length > 0) {
75+
// we assume that all checkpoint prizes will be the same
76+
if (v5CheckPointPrizes.length !== checkpointPrizesFromIfx.number_of_submissions || v5CheckPointPrizes[0] !== _.toInteger(checkpointPrizesFromIfx.prize_amount)) {
77+
await paymentService.updatePrize(checkpointPrizesFromIfx.prize_id, legacyId, v5CheckPointPrizes[0], v5CheckPointPrizes.length)
78+
}
79+
}
80+
}
1681

1782
/**
1883
* Get group information by V5 UUID
@@ -444,8 +509,8 @@ async function processUpdate (message) {
444509
logger.debug(`Will skip creating on legacy as status is ${constants.challengeStatuses.New}`)
445510
return
446511
} else if (!message.payload.legacyId) {
447-
logger.debug('Legacy ID does not exist. Will create...')
448-
return processCreate(message)
512+
logger.debug('Legacy ID does not exist. Will create the challenge first using the V4 API...')
513+
await processCreate(message)
449514
}
450515
const m2mToken = await helper.getM2MToken()
451516

@@ -485,11 +550,12 @@ async function processUpdate (message) {
485550
const saveDraftContestDTO = await parsePayload(message.payload, m2mToken, false, v4GroupIds)
486551
// logger.debug('Parsed Payload', saveDraftContestDTO)
487552
try {
488-
await helper.putRequest(`${config.V4_CHALLENGE_API_URL}/${message.payload.legacyId}`, { param: _.omit(saveDraftContestDTO, ['groupsToBeAdded', 'groupsToBeDeleted']) }, m2mToken)
489-
await associateChallengeGroups(saveDraftContestDTO.groupsToBeAdded, saveDraftContestDTO.groupsToBeDeleted, message.payload.legacyId)
490-
await associateChallengeTerms(message.payload.terms, message.payload.legacyId)
491-
await setCopilotPayment(message.payload.legacyId, _.get(message, 'payload.prizeSets'), _.get(message, 'payload.createdBy'), _.get(message, 'payload.updatedBy'))
553+
if (challenge) {
554+
// Only make the PUT request to the API if the challenge was available on the V4 API otherwise this will throw an error
555+
await helper.putRequest(`${config.V4_CHALLENGE_API_URL}/${message.payload.legacyId}`, { param: _.omit(saveDraftContestDTO, ['groupsToBeAdded', 'groupsToBeDeleted']) }, m2mToken)
556+
}
492557

558+
// Handle activating challenges and closing out tasks
493559
if (message.payload.status) {
494560
// logger.info(`The status has changed from ${challenge.currentStatus} to ${message.payload.status}`)
495561
if (message.payload.status === constants.challengeStatuses.Active && challenge.currentStatus !== constants.challengeStatuses.Active) {
@@ -511,6 +577,15 @@ async function processUpdate (message) {
511577
}
512578
}
513579
}
580+
581+
// Direct IFX modifications
582+
await syncChallengePhases(message.payload.legacyId, message.payload.phases)
583+
await updateMemberPayments(message.payload.legacyId, message.payload.prizeSets)
584+
await associateChallengeGroups(saveDraftContestDTO.groupsToBeAdded, saveDraftContestDTO.groupsToBeDeleted, message.payload.legacyId)
585+
await associateChallengeTerms(message.payload.terms, message.payload.legacyId)
586+
await setCopilotPayment(message.payload.legacyId, _.get(message, 'payload.prizeSets'), _.get(message, 'payload.createdBy'), _.get(message, 'payload.updatedBy'))
587+
588+
// Force the V4 ES feeder
514589
await helper.forceV4ESFeeder(message.payload.legacyId)
515590
} catch (e) {
516591
logger.error('processUpdate Catch', e)

src/services/paymentService.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Payment Service
3+
* Interacts with InformixDB
4+
*/
5+
const logger = require('../common/logger')
6+
const util = require('util')
7+
const helper = require('../common/helper')
8+
9+
const QUERY_GET_CHALLENGE_PRIZES = 'SELECT prize_id, place, prize_amount, number_of_submissions FROM prize WHERE prize_type_id = %d and project_id = %d'
10+
const QUERY_UPDATE_CHALLENGE_PRIZE = 'UPDATE prize SET prize_amount = ?, number_of_submissions = ? WHERE prize_id = %d and project_id = %d'
11+
12+
/**
13+
* Prepare Informix statement
14+
* @param {Object} connection the Informix connection
15+
* @param {String} sql the sql
16+
* @return {Object} Informix statement
17+
*/
18+
async function prepare (connection, sql) {
19+
// logger.debug(`Preparing SQL ${sql}`)
20+
const stmt = await connection.prepareAsync(sql)
21+
return Promise.promisifyAll(stmt)
22+
}
23+
24+
/**
25+
* Gets the challenge phases from ifx
26+
* @param {Number} challengeLegacyId the legacy challenge ID
27+
* @param {Number} prizeTypeId the legacy challenge ID
28+
*/
29+
async function getChallengePrizes (challengeLegacyId, prizeTypeId) {
30+
const connection = await helper.getInformixConnection()
31+
let result = null
32+
try {
33+
result = await connection.queryAsync(util.format(QUERY_GET_CHALLENGE_PRIZES, prizeTypeId, challengeLegacyId))
34+
} catch (e) {
35+
logger.error(`Error in 'getChallengePrizes' ${e}`)
36+
throw e
37+
} finally {
38+
await connection.closeAsync()
39+
}
40+
return result
41+
}
42+
43+
/**
44+
* Update a prize in IFX
45+
* @param {Number} phaseId the phase ID
46+
* @param {Number} challengeLegacyId the legacy challenge ID
47+
* @param {Number} prizeAmount the prize amount
48+
* @param {Number} numberOfSubmissions the number of submissions to receive the prize
49+
*/
50+
async function updatePrize (prizeId, challengeLegacyId, prizeAmount, numberOfSubmissions) {
51+
const connection = await helper.getInformixConnection()
52+
let result = null
53+
try {
54+
// await connection.beginTransactionAsync()
55+
const query = await prepare(connection, util.format(QUERY_UPDATE_CHALLENGE_PRIZE, prizeId, challengeLegacyId))
56+
result = await query.executeAsync([prizeAmount, numberOfSubmissions])
57+
// await connection.commitTransactionAsync()
58+
} catch (e) {
59+
logger.error(`Error in 'updatePrize' ${e}, rolling back transaction`)
60+
await connection.rollbackTransactionAsync()
61+
throw e
62+
} finally {
63+
logger.info(`Phase ${prizeId} has been updated`)
64+
await connection.closeAsync()
65+
}
66+
return result
67+
}
68+
69+
module.exports = {
70+
getChallengePrizes,
71+
updatePrize
72+
}

src/services/timelineService.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* Timeline Service
3+
* Interacts with InformixDB
4+
*/
5+
const logger = require('../common/logger')
6+
const util = require('util')
7+
const helper = require('../common/helper')
8+
9+
const QUERY_GET_PHASE_TYPES = 'SELECT phase_type_id, name FROM phase_type_lu'
10+
const QUERY_GET_CHALLENGE_PHASES = 'SELECT project_phase_id, scheduled_start_time, scheduled_end_time, duration, phase_status_id, phase_type_id FROM project_phase WHERE project_id = %d'
11+
const QUERY_UPDATE_CHALLENGE_PHASE = 'UPDATE project_phase SET scheduled_start_time = ?, scheduled_end_time = ?, duration = ?, phase_status_id = ? WHERE project_phase_id = %d and project_id = %d'
12+
13+
/**
14+
* Prepare Informix statement
15+
* @param {Object} connection the Informix connection
16+
* @param {String} sql the sql
17+
* @return {Object} Informix statement
18+
*/
19+
async function prepare (connection, sql) {
20+
// logger.debug(`Preparing SQL ${sql}`)
21+
const stmt = await connection.prepareAsync(sql)
22+
return Promise.promisifyAll(stmt)
23+
}
24+
25+
/**
26+
* Gets the phase types from ifx
27+
*/
28+
async function getPhaseTypes () {
29+
const connection = await helper.getInformixConnection()
30+
let result = null
31+
try {
32+
result = await connection.queryAsync(QUERY_GET_PHASE_TYPES)
33+
} catch (e) {
34+
logger.error(`Error in 'getPhaseTypes' ${e}`)
35+
throw e
36+
} finally {
37+
await connection.closeAsync()
38+
}
39+
return result
40+
}
41+
42+
/**
43+
* Gets the challenge phases from ifx
44+
* @param {Number} challengeLegacyId the legacy challenge ID
45+
*/
46+
async function getChallengePhases (challengeLegacyId) {
47+
const connection = await helper.getInformixConnection()
48+
let result = null
49+
try {
50+
result = await connection.queryAsync(util.format(QUERY_GET_CHALLENGE_PHASES, challengeLegacyId))
51+
} catch (e) {
52+
logger.error(`Error in 'getChallengePhases' ${e}`)
53+
throw e
54+
} finally {
55+
await connection.closeAsync()
56+
}
57+
return result
58+
}
59+
60+
/**
61+
* Update a phase in IFX
62+
* @param {Number} phaseId the phase ID
63+
* @param {Number} challengeLegacyId the legacy challenge ID
64+
* @param {Date} startTime the scheduled start date
65+
* @param {Date} endTime the scheduled end date
66+
* @param {Date} duration the duration
67+
* @param {Number} statusTypeId the status type ID
68+
*/
69+
async function updatePhase (phaseId, challengeLegacyId, startTime, endTime, duration, statusTypeId) {
70+
const connection = await helper.getInformixConnection()
71+
let result = null
72+
try {
73+
// await connection.beginTransactionAsync()
74+
const query = await prepare(connection, util.format(QUERY_UPDATE_CHALLENGE_PHASE, phaseId, challengeLegacyId))
75+
result = await query.executeAsync([startTime, endTime, duration, statusTypeId])
76+
// await connection.commitTransactionAsync()
77+
} catch (e) {
78+
logger.error(`Error in 'updatePhase' ${e}, rolling back transaction`)
79+
await connection.rollbackTransactionAsync()
80+
throw e
81+
} finally {
82+
logger.info(`Phase ${phaseId} has been updated`)
83+
await connection.closeAsync()
84+
}
85+
return result
86+
}
87+
88+
module.exports = {
89+
getChallengePhases,
90+
getPhaseTypes,
91+
updatePhase
92+
}

0 commit comments

Comments
 (0)