Skip to content

Commit a0df5a7

Browse files
committed
Merge branch 'develop'
2 parents 958667d + 7d0f8df commit a0df5a7

File tree

6 files changed

+163
-28
lines changed

6 files changed

+163
-28
lines changed

config/template.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
},
3232
{
3333
"title": "Please give us feedback on this challenge!",
34-
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc.",
34+
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc.\n\n https://www.surveymonkey.com/r/3SYYTHP?Challenge_ID=<%- challenge.id %>",
3535
"announce": 0,
3636
"closed": 0
3737
}
@@ -74,7 +74,7 @@
7474
},
7575
{
7676
"title": "Please give us feedback on this challenge!",
77-
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc.",
77+
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc. \n\n https://www.surveymonkey.com/r/3SYYTHP?Challenge_ID=<%- challenge.id %>",
7878
"announce": 0,
7979
"closed": 0
8080
}
@@ -119,7 +119,7 @@
119119
},
120120
{
121121
"title": "Please give us feedback on this challenge!",
122-
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc.",
122+
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc. \n\n https://www.surveymonkey.com/r/3SYYTHP?Challenge_ID=<%- challenge.id %>",
123123
"announce": 0,
124124
"closed": 0
125125
},
@@ -166,7 +166,7 @@
166166
},
167167
{
168168
"title": "Please give us feedback on this challenge!",
169-
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc.",
169+
"body": "Hi Competitors,\n\nAt topcoder, we are always trying to continuously improve how we are running competitions and tasks for our competitors. Part of this involves getting feedback from you on how well our tasks and challenges are being managed.\n\nPlease take 2-3 minutes to fill out this survey. The results will be used to identify areas of improvement, follow on training, procedural changes, etc. \n\n https://www.surveymonkey.com/r/3SYYTHP?Challenge_ID=<%- challenge.id %>",
170170
"announce": 0,
171171
"closed": 0
172172
}

src/constants.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ module.exports = {
4444
COPILOT: 'copilot',
4545
MANAGER: 'manager',
4646
CUSTOMER: 'customer'
47+
},
48+
CHALLENGE_ROLES: {
49+
COPILOT: 'Copilot',
50+
MANAGER: 'Manager',
51+
SUBMITTER: 'Submitter'
4752
}
4853
},
4954
VANILLA: {

src/modules/user_management/handler.js

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
const config = require('config')
2+
const _ = require('lodash')
23
const util = require('util')
34
const constants = require('../../constants')
45
const logger = require('../../utils/logger.util')
56
const { manageRocketUser } = require('../../services/rokect')
67
const { manageVanillaUser } = require('../../services/vanilla')
78
const {
89
getTopcoderUserHandle: getUserHandle,
10+
getAllChallengeRolesForUser,
11+
getProjectRoleForUser,
912
processPayload
1013
} = require('./helpers')
1114

@@ -34,6 +37,23 @@ function canProcessEvent (payload, topic) {
3437
return true
3538
}
3639

40+
async function processPayloadItem (item, topic) {
41+
const data = processPayload(item, topic)
42+
try {
43+
data.handle = data.handle || (await getUserHandle(data.userId))
44+
data.projectRole = (await getProjectRoleForUser(data.challengeId, data.userId))
45+
data.challengeRoles = (await getAllChallengeRolesForUser(data.challengeId, data.userId))
46+
} catch (err) {
47+
logger.error(util.inspect(err))
48+
}
49+
for (const service of services) {
50+
await service(data)
51+
.catch(err => {
52+
logger.error(util.inspect(err))
53+
})
54+
}
55+
}
56+
3757
/**
3858
* Handle a set of messages from the Kafka topic
3959
* @param {Array} messageSet
@@ -48,19 +68,12 @@ async function handler (messageSet, topic) {
4868
if (!canProcessEvent(item, topic)) {
4969
continue
5070
}
51-
52-
const data = processPayload(item, topic)
53-
try {
54-
data.handle = data.handle || (await getUserHandle(data.userId))
55-
} catch (err) {
56-
logger.error(util.inspect(err))
57-
continue
58-
}
59-
for (const service of services) {
60-
await service(data)
61-
.catch(err => {
62-
logger.error(util.inspect(err))
63-
})
71+
if (_.isArray(item)) {
72+
for (const i of item) {
73+
await processPayloadItem(i, topic)
74+
}
75+
} else {
76+
await processPayloadItem(item, topic)
6477
}
6578
}
6679
}

src/modules/user_management/helpers.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,62 @@ async function getTopcoderUserHandle (userId) {
6161
return userHandle
6262
}
6363

64+
/**
65+
* Get a list of role names for User
66+
* @param challengeId
67+
* @param userId
68+
* @returns {Promise<*[]>}
69+
*/
70+
async function getAllChallengeRolesForUser (challengeId, userId) {
71+
const { body: challengeRoles, status: challengeRolesStatus } = await topcoderApi.getAllChallengeRoles(challengeId)
72+
if (challengeRolesStatus !== 200) {
73+
throw new Error('Couldn\'t load Topcoder Challenge Roles', challengeRoles)
74+
}
75+
const roles = _.filter(challengeRoles, { memberId: userId })
76+
77+
const { body: resourceRoles, status: allRolesStatus } = await topcoderApi.getAllRoles()
78+
if (allRolesStatus !== 200) {
79+
throw new Error('Couldn\'t load Topcoder Resource Roles', resourceRoles)
80+
}
81+
82+
if (_.isEmpty(resourceRoles)) {
83+
throw new Error(`No Resource Roles for ${challengeId}`)
84+
}
85+
86+
_.map(roles, function (obj) {
87+
// add the properties from second array matching the roleId
88+
return _.assign(obj, _.find(resourceRoles, { id: obj.roleId }))
89+
})
90+
91+
// Get all role names
92+
return _.map(roles, 'name')
93+
}
94+
95+
async function getProjectRoleForUser (challengeId, userId) {
96+
const { body: challenge, status: challengeStatus } = await topcoderApi.getChallenge(challengeId)
97+
if (challengeStatus !== 200) {
98+
throw new Error(`Couldn't load Topcoder Challenge by challengeId ${challengeId}`)
99+
}
100+
const { body: project, status: projectStatus } = await topcoderApi.getProject(challenge.projectId)
101+
102+
if (projectStatus !== 200) {
103+
throw new Error(`Couldn't load Topcoder Project by projectId ${challenge.projectId}`)
104+
}
105+
106+
// userId - string , x.userId - int
107+
/* eslint-disable eqeqeq */
108+
const member = _.filter(project.members, x => x.userId == userId)
109+
// User doesn't have project roles
110+
if (_.isEmpty(member)) {
111+
return null
112+
} else {
113+
return member[0].role
114+
}
115+
}
116+
64117
module.exports = {
65118
getTopcoderUserHandle,
119+
getAllChallengeRolesForUser,
120+
getProjectRoleForUser,
66121
processPayload
67122
}

src/services/vanilla.js

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,18 @@ const utils = require('../utils/common.util')
1111
const template = require(config.TEMPLATES.TEMPLATE_FILE_PATH)
1212

1313
/**
14-
* Add/Remove a user to/from a category.
15-
*
14+
* Add/Remove a user to/from a group.
1615
* @param {Object} data the data from message payload
1716
* @returns {undefined}
1817
*/
1918
async function manageVanillaUser (data) {
20-
const { challengeId, action, handle: username, role: projectRole } = data
21-
logger.info(`Managing users for challengeID=${challengeId} ...`)
19+
const { challengeId, action, handle: username, projectRole, challengeRoles } = data
20+
logger.info(`Managing user for challengeID=${challengeId} [action=${action}, handle=${username}, projectRole=${JSON.stringify(projectRole)}, challengeRoles=${JSON.stringify(challengeRoles)}]...`)
2221
const { body: groups } = await vanillaClient.searchGroups(challengeId)
2322
const group = groups.length > 0 ? groups[0] : null
2423

25-
// Only members and copilots will receive notifications
26-
const watch = (!projectRole || projectRole === constants.TOPCODER.PROJECT_ROLES.COPILOT) ? 1 : 0
27-
const follow = 1
24+
const watch = shouldWatchCategories(projectRole, challengeRoles)
25+
const follow = shouldFollowCategories(projectRole, challengeRoles)
2826

2927
if (!group) {
3028
throw new Error('The group wasn\'t not found by challengeID')
@@ -77,7 +75,7 @@ async function manageVanillaUser (data) {
7775

7876
const { body: user } = await vanillaClient.addUser(userData)
7977
vanillaUser = user
80-
logger.info(`New user with UserID=${vanillaUser.userID} was added.`)
78+
logger.info(`New user [UserID=${vanillaUser.userID}, Name=${vanillaUser.name}] was added.`)
8179
} else {
8280
// Get a full user profile with roles
8381
const { body: user } = await vanillaClient.getUser(vanillaUser.userID)
@@ -90,6 +88,7 @@ async function manageVanillaUser (data) {
9088
roleID: [...currentVanillaRoleIDs, ...userTopcoderRoleIDs]
9189
}
9290
await vanillaClient.updateUser(vanillaUser.userID, userData)
91+
// logger.info(`Roles were synchronized for User [UserID=${vanillaUser.userID}, Name=${vanillaUser.name}].`)
9392
}
9493

9594
// Choose action to perform
@@ -100,12 +99,12 @@ async function manageVanillaUser (data) {
10099
watch: watch,
101100
follow: follow
102101
})
103-
logger.info(`The user '${vanillaUser.name}' was added to the group '${group.name}'`)
102+
logger.info(`User [UserID=${vanillaUser.userID}, Name=${vanillaUser.name} was added to Group [GroupID=${group.groupID}, Name=${group.name}, Watch=${watch}, Follow=${follow}]`)
104103
break
105104
}
106105
case constants.USER_ACTIONS.KICK: {
107106
await vanillaClient.removeUserFromGroup(group.groupID, vanillaUser.userID)
108-
logger.info(`The user '${vanillaUser.name}' was removed from the group '${group.name}'`)
107+
logger.info(`User [UserID=${vanillaUser.userID}, Name =${vanillaUser.name} was removed from Group [GroupID=${group.groupID}, Name=${group.name}]`)
109108
break
110109
}
111110
default:
@@ -256,7 +255,12 @@ async function createVanillaGroup (challenge) {
256255
}
257256

258257
for (const member of members) {
259-
await manageVanillaUser({ challengeId: challenge.id, action: constants.USER_ACTIONS.INVITE, handle: member.handle, role: member.role })
258+
await manageVanillaUser({
259+
challengeId: challenge.id,
260+
action: constants.USER_ACTIONS.INVITE,
261+
handle: member.handle,
262+
projectRole: member.role
263+
})
260264
}
261265

262266
challengeDetailsDiscussion.url = `${challengeCategory.url}`
@@ -319,6 +323,46 @@ async function createDiscussions (group, challenge, templateDiscussions, vanilla
319323
}
320324
}
321325

326+
/**
327+
* Auto-watch categories
328+
* @param projectRole string
329+
* @param challengeRoles array
330+
* @returns {boolean}
331+
*/
332+
function shouldWatchCategories (projectRole, challengeRoles) {
333+
// New user
334+
if (!projectRole && _.isEmpty(challengeRoles)) {
335+
return true
336+
}
337+
338+
// Project Copilots / Challenge Copilots and Submitters
339+
return (projectRole === constants.TOPCODER.PROJECT_ROLES.COPILOT ||
340+
(_.isArray(challengeRoles) && (_.includes(challengeRoles, constants.TOPCODER.CHALLENGE_ROLES.COPILOT) ||
341+
_.includes(challengeRoles, constants.TOPCODER.CHALLENGE_ROLES.SUBMITTER)))
342+
)
343+
}
344+
345+
/**
346+
* Auto-follow categories
347+
* @param projectRole string
348+
* @param challengeRoles array
349+
* @returns {boolean}
350+
*/
351+
function shouldFollowCategories (projectRole, challengeRoles) {
352+
// New user
353+
if (!projectRole && _.isEmpty(challengeRoles)) {
354+
return true
355+
}
356+
357+
// Project Copilots or Managers / Challenge Copilots, Managers and Submitters
358+
return projectRole === constants.TOPCODER.PROJECT_ROLES.COPILOT ||
359+
projectRole === constants.TOPCODER.PROJECT_ROLES.MANAGER ||
360+
(_.isArray(challengeRoles) && (_.includes(challengeRoles, constants.TOPCODER.CHALLENGE_ROLES.COPILOT) ||
361+
_.includes(challengeRoles, constants.TOPCODER.CHALLENGE_ROLES.MANAGER) ||
362+
_.includes(challengeRoles, constants.TOPCODER.CHALLENGE_ROLES.SUBMITTER))
363+
)
364+
}
365+
322366
module.exports = {
323367
manageVanillaUser,
324368
createVanillaGroup,

src/utils/topcoder-api.util.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,29 @@ async function getProject (projectId) {
110110
return reqToAPI('GET', path)
111111
}
112112

113+
/**
114+
* Gets the list of Resource Roles by challengeId
115+
*/
116+
async function getAllChallengeRoles (challengeId) {
117+
const path = `${config.TOPCODER.API_URL}/v5/resources?challengeId=${challengeId}`
118+
return reqToAPI('GET', path)
119+
}
120+
121+
/**
122+
* Gets the list of All Resource Roles
123+
*/
124+
async function getAllRoles () {
125+
const path = `${config.TOPCODER.API_URL}/v5/resource-roles`
126+
return reqToAPI('GET', path)
127+
}
128+
113129
module.exports = {
114130
getUserDetailsById,
115131
getUserDetailsByHandle,
116132
getChallenge,
117133
updateChallenge,
118134
getRoles,
135+
getAllRoles,
136+
getAllChallengeRoles,
119137
getProject
120138
}

0 commit comments

Comments
 (0)