From 78fc74f669596a05f3d4c92ab398a495dbec57a8 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Mon, 12 Sep 2022 18:53:38 +0600 Subject: [PATCH 1/7] fix: task.memberId getting reset * keep winners.userId in sync with task.memberId for pureV5Tasks --- .circleci/config.yml | 4 +-- src/common/helper.js | 2 +- src/routes.js | 2 +- src/services/ChallengeService.js | 47 +++++++++++++++++++++++++------- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b49f0029..5ae70314 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,9 +70,7 @@ workflows: branches: only: - develop - - fix/challenge-timelines-edit-routes - - test/performance-profile - - July2022Updates + - fix/task-memberId-reset # Production builds are exectuted only on tagged commits to the # master branch. diff --git a/src/common/helper.js b/src/common/helper.js index c349ecfb..0db4a781 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -889,7 +889,7 @@ async function listChallengesByMember (memberId) { // get search is paginated, we need to get all pages' data let page = 1 while (true) { - let result = {}; + let result = {} try { result = await axios.get(`${config.RESOURCES_API_URL}/${memberId}/challenges`, { headers: { Authorization: `Bearer ${token}` }, diff --git a/src/routes.js b/src/routes.js index 3c778369..b02f79fe 100644 --- a/src/routes.js +++ b/src/routes.js @@ -70,7 +70,7 @@ module.exports = { '/challenges/:challengeId/statistics': { get: { controller: 'ChallengeController', - method: 'getChallengeStatistics', + method: 'getChallengeStatistics' } }, '/challenges/:challengeId/notifications': { diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index ed15a9a7..d3353fe7 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -274,7 +274,7 @@ async function searchChallenges (currentUser, criteria) { { wildcard: { name: `*${criteria.search}*` } }, { wildcard: { name: `${criteria.search}*` } }, { wildcard: { name: `*${criteria.search}` } }, - { match_phrase: { tags: criteria.search } }, + { match_phrase: { tags: criteria.search } } ] } }) } else { @@ -1649,6 +1649,39 @@ async function update (currentUser, challengeId, data, isFull) { await validateWinners(data.winners, challengeId) } + // Only m2m tokens are allowed to modify the `task.*` information on a challenge + if (!_.isUndefined(_.get(data, 'task')) && !currentUser.isMachine) { + if (!_.isUndefined(_.get(challenge, 'task'))) { + logger.info(`User ${currentUser.handle || currentUser.sub} is not allowed to modify the task information on challenge ${challengeId}`) + data.task = challenge.task + logger.info(`Task information on challenge ${challengeId} is reset to ${JSON.stringify(challenge.task)}. Original data: ${JSON.stringify(data.task)}`) + } else { + delete data.task + } + } + + // task.memberId goes out of sync due to another processor setting "task.memberId" but subsequent immediate update to the task + // will not have the memberId set. So we need to set it using winners to ensure it is always in sync. The proper fix is to correct + // the sync issue in the processor. However this is quick fix that works since winner.userId is task.memberId. + if (_.get(challenge, 'legacy.pureV5Task') && !_.isUndefined(data.winners)) { + const winnerMemberId = _.get(data.winners, '[0].userId') + logger.info(`Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}`) + + if (winnerMemberId != null && data.task.memberId !== winnerMemberId) { + logger.info(`Task ${challengeId} has a winner ${winnerMemberId}`) + data.task = { + isTask: true, + isAssigned: true, + memberId: winnerMemberId + } + logger.warn(`task.memberId mismatched with winner memberId. task.memberId is updated to ${winnerMemberId}`) + } else { + logger.info(`task ${challengeId} has no winner set yet.`) + } + } else { + logger.info(`${challengeId} is not a pureV5 challenge or has no winners set yet.`) + } + data.updated = moment().utc() data.updatedBy = currentUser.handle || currentUser.sub const updateDetails = {} @@ -1709,6 +1742,9 @@ async function update (currentUser, challengeId, data, isFull) { op = '$PUT' } else if (_.isUndefined(challenge[key]) || challenge[key] !== value) { op = '$PUT' + } else if (_.get(challenge, 'legacy.pureV5Task') && key === 'task') { + // always update task for pureV5 challenges + op = '$PUT' } if (op) { @@ -1848,15 +1884,6 @@ async function update (currentUser, challengeId, data, isFull) { const { track, type } = await validateChallengeData(_.pick(challenge, ['trackId', 'typeId'])) - // Only m2m tokens are allowed to modify the `task.*` information on a challenge - if (!_.isUndefined(_.get(data, 'task')) && !currentUser.isMachine) { - if (!_.isUndefined(_.get(challenge, 'task'))) { - data.task = challenge.task - } else { - delete data.task - } - } - if (_.get(type, 'isTask')) { if (!_.isEmpty(_.get(data, 'task.memberId'))) { const challengeResources = await helper.getChallengeResources(challengeId) From 3fec2c0568af6507f260e90f72099f9848b82f36 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Mon, 12 Sep 2022 19:21:10 +0600 Subject: [PATCH 2/7] fix: null check --- src/services/ChallengeService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index d3353fe7..b2ed2acb 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1665,9 +1665,9 @@ async function update (currentUser, challengeId, data, isFull) { // the sync issue in the processor. However this is quick fix that works since winner.userId is task.memberId. if (_.get(challenge, 'legacy.pureV5Task') && !_.isUndefined(data.winners)) { const winnerMemberId = _.get(data.winners, '[0].userId') - logger.info(`Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}`) + logger.info(`Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}. Task ${_.get(challenge, 'task')}`) - if (winnerMemberId != null && data.task.memberId !== winnerMemberId) { + if (winnerMemberId != null && _.get(data, 'task.memberId') !== winnerMemberId) { logger.info(`Task ${challengeId} has a winner ${winnerMemberId}`) data.task = { isTask: true, From e610d8225f89cffe138daee932707840602b40d7 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Mon, 12 Sep 2022 19:23:40 +0600 Subject: [PATCH 3/7] chore: logs --- src/services/ChallengeService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index b2ed2acb..ee691b2c 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1665,7 +1665,7 @@ async function update (currentUser, challengeId, data, isFull) { // the sync issue in the processor. However this is quick fix that works since winner.userId is task.memberId. if (_.get(challenge, 'legacy.pureV5Task') && !_.isUndefined(data.winners)) { const winnerMemberId = _.get(data.winners, '[0].userId') - logger.info(`Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}. Task ${_.get(challenge, 'task')}`) + logger.info(`Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}. Task ${_.get(data, 'task')} - ${_.get(challenge, 'task')}`) if (winnerMemberId != null && _.get(data, 'task.memberId') !== winnerMemberId) { logger.info(`Task ${challengeId} has a winner ${winnerMemberId}`) From 8ee65fa325afef7bc8e5c3dec47ab7ce3e2f0cd9 Mon Sep 17 00:00:00 2001 From: Thomas Kranitsas Date: Wed, 23 Nov 2022 13:53:35 +0200 Subject: [PATCH 4/7] Remove post mortem phase from First 2 Finish challenge --- config/default.js | 3 +++ src/services/ChallengeService.js | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/config/default.js b/config/default.js index bd24f029..babe7a5e 100644 --- a/config/default.js +++ b/config/default.js @@ -69,6 +69,9 @@ module.exports = { OBSERVER_ROLE_ID: process.env.OBSERVER_ROLE_ID || '2a4dc376-a31c-4d00-b173-13934d89e286', CLIENT_MANAGER_ROLE_ID: process.env.OBSERVER_ROLE_ID || '9b2f1905-8128-42da-85df-ed64410f4781', + // topgear billing accounts + TOPGEAR_BILLING_ACCOUNTS_ID: process.env.TOPGEAR_BILLING_ACCOUNTS_ID ? process.env.TOPGEAR_BILLING_ACCOUNTS_ID.split(',') : [], + // health check timeout in milliseconds HEALTH_CHECK_TIMEOUT: process.env.HEALTH_CHECK_TIMEOUT || 3000, diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index ee691b2c..ab680cac 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1450,6 +1450,17 @@ async function update (currentUser, challengeId, data, isFull) { _.set(data, 'billing.billingAccountId', billingAccountId) _.set(data, 'billing.markup', markup || 0) } + if (billingAccountId && _.includes(config.TOPGEAR_BILLING_ACCOUNTS_ID, _.toString(billingAccountId))) { + if (_.isEmpty(data.metadata)) { + data.metadata = [] + } + if (!_.find(data.metadata, e => e.name === 'postMortemRequired')) { + data.metadata.push({ + name: 'postMortemRequired', + value: 'false' + }) + } + } if (data.status) { if (data.status === constants.challengeStatuses.Active) { if (!_.get(challenge, 'legacy.pureV5Task') && !_.get(challenge, 'legacy.pureV5') && _.isUndefined(_.get(challenge, 'legacyId'))) { From bcffb0f67761b8cc4e366f8dafd8a03563897cbc Mon Sep 17 00:00:00 2001 From: Thomas Kranitsas Date: Fri, 25 Nov 2022 10:52:57 +0200 Subject: [PATCH 5/7] do not overwrite metadata, instead extend the array --- src/services/ChallengeService.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index ab680cac..651febc4 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1914,6 +1914,16 @@ async function update (currentUser, challengeId, data, isFull) { delete data.attachments delete data.terms + const finalMetadata = [...challenge.metadata || []] + _.each(data.metadata || [], (rec) => { + const existingMeta = _.findIndex(finalMetadata, m => m.name === rec.name) + if (existingMeta > -1) { + finalMetadata[existingMeta].value = rec.value + } else { + finalMetadata.push(rec) + } + }) + data.metdata = finalMetadata _.assign(challenge, data) if (!_.isUndefined(newAttachments)) { challenge.attachments = newAttachments From da7634a6cde664ea3d8fc66b14d9f0eb45e2e200 Mon Sep 17 00:00:00 2001 From: Thomas Kranitsas Date: Fri, 25 Nov 2022 12:35:52 +0200 Subject: [PATCH 6/7] fix typo --- src/services/ChallengeService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index 651febc4..b86fa3f7 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1923,7 +1923,7 @@ async function update (currentUser, challengeId, data, isFull) { finalMetadata.push(rec) } }) - data.metdata = finalMetadata + data.metadata = finalMetadata _.assign(challenge, data) if (!_.isUndefined(newAttachments)) { challenge.attachments = newAttachments From 4adb972e33e2aa1476b1aea0835ff5d9a58d47cb Mon Sep 17 00:00:00 2001 From: Thomas Kranitsas Date: Mon, 28 Nov 2022 11:14:23 +0200 Subject: [PATCH 7/7] move metadata code --- src/services/ChallengeService.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index b86fa3f7..60a5489f 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1695,6 +1695,16 @@ async function update (currentUser, challengeId, data, isFull) { data.updated = moment().utc() data.updatedBy = currentUser.handle || currentUser.sub + const finalMetadata = [...challenge.metadata || []] + _.each(data.metadata || [], (rec) => { + const existingMeta = _.findIndex(finalMetadata, m => m.name === rec.name) + if (existingMeta > -1) { + finalMetadata[existingMeta].value = rec.value + } else { + finalMetadata.push(rec) + } + }) + data.metadata = finalMetadata const updateDetails = {} const auditLogs = [] let phasesHaveBeenModified = false @@ -1914,16 +1924,6 @@ async function update (currentUser, challengeId, data, isFull) { delete data.attachments delete data.terms - const finalMetadata = [...challenge.metadata || []] - _.each(data.metadata || [], (rec) => { - const existingMeta = _.findIndex(finalMetadata, m => m.name === rec.name) - if (existingMeta > -1) { - finalMetadata[existingMeta].value = rec.value - } else { - finalMetadata.push(rec) - } - }) - data.metadata = finalMetadata _.assign(challenge, data) if (!_.isUndefined(newAttachments)) { challenge.attachments = newAttachments