From f441ffc3cd0f9d0c17a4f38ead7bcaad0d37fda6 Mon Sep 17 00:00:00 2001 From: Bogdanova Olga Date: Thu, 5 Nov 2020 15:44:55 +0300 Subject: [PATCH] Issues-94: Updating group category --- src/constants.js | 2 +- src/modules/update_challenge/helpers.js | 1 - src/services/vanilla.js | 89 ++++++++++++++----------- src/utils/topcoder-api.util.js | 87 ++++++++++++------------ src/utils/vanilla-client.util.js | 14 +++- 5 files changed, 107 insertions(+), 86 deletions(-) diff --git a/src/constants.js b/src/constants.js index f9d70ad..87a7697 100644 --- a/src/constants.js +++ b/src/constants.js @@ -40,7 +40,7 @@ module.exports = { KICK: 'kick' }, TOPCODER: { - ROLE_COPILOT : 'copilot' + ROLE_COPILOT: 'copilot' }, VANILLA: { CHALLENGES_FORUM: 'Challenges Forums', diff --git a/src/modules/update_challenge/helpers.js b/src/modules/update_challenge/helpers.js index 2867157..db7a2b3 100644 --- a/src/modules/update_challenge/helpers.js +++ b/src/modules/update_challenge/helpers.js @@ -1,5 +1,4 @@ const config = require('config') -const _ = require('lodash') /** * Processes a payload from the topic, to be consumed by the handler diff --git a/src/services/vanilla.js b/src/services/vanilla.js index 1f2c08b..e63debc 100644 --- a/src/services/vanilla.js +++ b/src/services/vanilla.js @@ -35,24 +35,24 @@ async function manageVanillaUser (data) { } const topcoderProfile = JSON.parse(topcoderProfileResponseStr).result.content[0] - const {text: topcoderRolesResponseStr} = await topcoderApi.getRoles(topcoderProfile.id) + const { text: topcoderRolesResponseStr } = await topcoderApi.getRoles(topcoderProfile.id) const topcoderRolesResponse = JSON.parse(topcoderRolesResponseStr).result.content const topcoderRoleNames = _.map(topcoderRolesResponse, 'roleName') - const{ body: allVanillaRoles } = await vanillaClient.getAllRoles() + const { body: allVanillaRoles } = await vanillaClient.getAllRoles() // Add all missing Topcoder roles await addTopcoderRoles(allVanillaRoles, topcoderRoleNames) const { body: allNewVanillaRoles } = await vanillaClient.getAllRoles() - let allTopcoderRoles = _.filter(allNewVanillaRoles, { type: 'topcoder' }) + const allTopcoderRoles = _.filter(allNewVanillaRoles, { type: 'topcoder' }) - let nonTopcoderRoles = _.filter(allNewVanillaRoles, role => role['type'] != 'topcoder') - let nonTopcoderRoleIDs = _.map(nonTopcoderRoles, 'roleID') + const nonTopcoderRoles = _.filter(allNewVanillaRoles, role => role.type !== 'topcoder') + const nonTopcoderRoleIDs = _.map(nonTopcoderRoles, 'roleID') - let userTopcoderRoles = _.filter(allTopcoderRoles, role => topcoderRoleNames.includes(role['name'])) - let userTopcoderRoleIDs = _.map(userTopcoderRoles, 'roleID') + const userTopcoderRoles = _.filter(allTopcoderRoles, role => topcoderRoleNames.includes(role.name)) + const userTopcoderRoleIDs = _.map(userTopcoderRoles, 'roleID') if (!vanillaUser) { logger.info(`The '${username}' user wasn't found in Vanilla`) @@ -79,7 +79,7 @@ async function manageVanillaUser (data) { vanillaUser = user // Sync Topcoder roles - const allCurrentUserRoleIDs = _.map(vanillaUser.roles, 'roleID'); + const allCurrentUserRoleIDs = _.map(vanillaUser.roles, 'roleID') const currentVanillaRoleIDs = _.intersection(allCurrentUserRoleIDs, nonTopcoderRoleIDs) const userData = { roleID: [...currentVanillaRoleIDs, ...userTopcoderRoleIDs] @@ -119,15 +119,15 @@ async function manageVanillaUser (data) { } } -async function addTopcoderRoles(allVanillaRoles, topcoderRoleNames) { +async function addTopcoderRoles (allVanillaRoles, topcoderRoleNames) { const allTopcoderRoles = _.filter(allVanillaRoles, { type: 'topcoder' }) - const userTopcoderRoles = _.filter(allTopcoderRoles, role => topcoderRoleNames.includes(role['name'])) + const userTopcoderRoles = _.filter(allTopcoderRoles, role => topcoderRoleNames.includes(role.name)) const userTopcoderRoleIDs = _.map(userTopcoderRoles, 'roleID') - if(topcoderRoleNames.length != userTopcoderRoleIDs.length) { - const missingRoles = _.difference(topcoderRoleNames, _.map(userTopcoderRoles, 'name')) + if (topcoderRoleNames.length !== userTopcoderRoleIDs.length) { + const missingRoles = _.difference(topcoderRoleNames, _.map(userTopcoderRoles, 'name')) logger.info('Missing roles:' + JSON.stringify(missingRoles)) - for(const missingRole of missingRoles) { + for (const missingRole of missingRoles) { await vanillaClient.createRole({ canSession: 1, description: 'Added by Challenge Forum Processor', @@ -168,7 +168,7 @@ async function createVanillaGroup (challenge) { throw new Error('Multiple discussions with type=\'challenge\' and provider=\'vanilla\' are not supported.') } - const {body: project} = await topcoderApi.getProject(challenge.projectId) + const { body: project } = await topcoderApi.getProject(challenge.projectId) const copilots = _.filter(project.members, { role: constants.TOPCODER.ROLE_COPILOT }) const challengesForums = _.filter(template.categories, ['name', constants.VANILLA.CHALLENGES_FORUM]) if (!challengesForums) { @@ -228,7 +228,7 @@ async function createVanillaGroup (challenge) { // Create the root challenge category const { body: challengeCategory } = await vanillaClient.createCategory({ - name: challengeDetailsDiscussion.name, + name: challenge.name, urlcode: `${challenge.id}`, parentCategoryID: parentCategory[0].categoryID, displayAs: groupTemplate.categories ? constants.VANILLA.CATEGORY_DISPLAY_STYLE.CATEGORIES : constants.VANILLA.CATEGORY_DISPLAY_STYLE.DISCUSSIONS @@ -236,7 +236,7 @@ async function createVanillaGroup (challenge) { logger.info(`The '${challengeCategory.name}' category was created`) - if(groupTemplate.categories) { + if (groupTemplate.categories) { for (const item of groupTemplate.categories) { const urlCodeTemplate = _.template(item.urlcode) const { body: childCategory } = await vanillaClient.createCategory({ @@ -245,16 +245,16 @@ async function createVanillaGroup (challenge) { parentCategoryID: challengeCategory.categoryID }) logger.info(`The '${item.name}' category was created`) - await createDiscussions(group, challenge, item.discussions, childCategory); + await createDiscussions(group, challenge, item.discussions, childCategory) } } - if(groupTemplate.discussions){ - await createDiscussions(group, challenge, groupTemplate.discussions, challengeCategory); + if (groupTemplate.discussions) { + await createDiscussions(group, challenge, groupTemplate.discussions, challengeCategory) } for (const copilot of copilots) { - await manageVanillaUser({challengeId: challenge.id, action: constants.USER_ACTIONS.INVITE, handle: copilot.handle}) + await manageVanillaUser({ challengeId: challenge.id, action: constants.USER_ACTIONS.INVITE, handle: copilot.handle }) } challengeDetailsDiscussion.url = `${challengeCategory.url}` @@ -274,34 +274,47 @@ async function updateVanillaGroup (challenge) { logger.info(`The challenge with challengeID=${challenge.id}:`) const { body: groups } = await vanillaClient.searchGroups(challenge.id) - if (groups.length == 0) { - throw new Error('The group wasn\'t found for this challenge') + if (groups.length === 0) { + throw new Error('The group wasn\'t found for this challenge') } if (groups.length > 1) { throw new Error('Multiple groups were found for this challenge') } - const {body: updatedGroup} = await vanillaClient.updateGroup(groups[0].groupID, {name: challenge.name}) - + const { body: updatedGroup } = await vanillaClient.updateGroup(groups[0].groupID, { name: challenge.name }) logger.info(`The group was updated: ${JSON.stringify(updatedGroup)}`) + + const { body: groupCategory } = await vanillaClient.getCategoryByUrlcode(`${challenge.id}`) + if (!groupCategory) { + throw new Error('Group category wasn\'t found for this challenge') + } + + const { body: groupCategoryForEdit } = await vanillaClient.getCategoryForEdit(groupCategory.categoryID) + if (!groupCategoryForEdit) { + throw new Error('Group category wasn\'t found for this challenge') + } + groupCategoryForEdit.name = challenge.name + + const { body: updatedGroupCategory } = await vanillaClient.updateCategory(groupCategoryForEdit.categoryID, groupCategoryForEdit) + logger.info(`The group category was updated: ${JSON.stringify(updatedGroupCategory)}`) } async function createDiscussions (group, challenge, templateDiscussions, vanillaCategory) { - for (const discussion of templateDiscussions) { - // create a discussion - const bodyTemplate = _.template(discussion.body) - await vanillaClient.createDiscussion({ - body: bodyTemplate({ challenge: challenge }), - name: discussion.title, - groupID: group.groupID, - categoryID: vanillaCategory.categoryID, - format: constants.VANILLA.DISCUSSION_FORMAT.WYSIWYG, - closed: discussion.closed, - pinned: discussion.announce - }) - logger.info(`The '${discussion.title}' discussion/announcement was created`) - } + for (const discussion of templateDiscussions) { + // create a discussion + const bodyTemplate = _.template(discussion.body) + await vanillaClient.createDiscussion({ + body: bodyTemplate({ challenge: challenge }), + name: discussion.title, + groupID: group.groupID, + categoryID: vanillaCategory.categoryID, + format: constants.VANILLA.DISCUSSION_FORMAT.WYSIWYG, + closed: discussion.closed, + pinned: discussion.announce + }) + logger.info(`The '${discussion.title}' discussion/announcement was created`) + } } module.exports = { diff --git a/src/utils/topcoder-api.util.js b/src/utils/topcoder-api.util.js index c92b0db..72969fe 100644 --- a/src/utils/topcoder-api.util.js +++ b/src/utils/topcoder-api.util.js @@ -1,33 +1,33 @@ -const config = require("config"); -const _ = require("lodash"); -const m2mAuth = require("tc-core-library-js").auth.m2m; -const request = require("superagent"); -const logger = require("./logger.util"); +const config = require('config') +const _ = require('lodash') +const m2mAuth = require('tc-core-library-js').auth.m2m +const request = require('superagent') +const logger = require('./logger.util') -let m2m = null; +let m2m = null /** * Function to get M2M token */ -async function getM2MToken() { +async function getM2MToken () { if (_.isNull(m2m)) { m2m = m2mAuth( _.pick(config.TOPCODER, [ - "AUTH0_URL", - "AUTH0_AUDIENCE", - "TOKEN_CACHE_TIME", - "AUTH0_PROXY_SERVER_URL", + 'AUTH0_URL', + 'AUTH0_AUDIENCE', + 'TOKEN_CACHE_TIME', + 'AUTH0_PROXY_SERVER_URL' ]) - ); + ) } logger.info( `Getting M2M token for client ID=${config.TOPCODER.AUTH0_CLIENT_ID}` - ); + ) return m2m.getMachineToken( config.TOPCODER.AUTH0_CLIENT_ID, config.TOPCODER.AUTH0_CLIENT_SECRET - ); + ) } /** @@ -36,27 +36,27 @@ async function getM2MToken() { * @param {String} path Complete path of the API URL * @param {Object} reqBody Body of the request */ -async function reqToAPI(reqType, path, reqBody) { - const token = await getM2MToken(); - const authHeader = token ? { Authorization: `Bearer ${token}` } : {}; +async function reqToAPI (reqType, path, reqBody) { + const token = await getM2MToken() + const authHeader = token ? { Authorization: `Bearer ${token}` } : {} - const validReqTypes = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"]; - const hasBody = ["POST", "PUT", "PATCH"]; + const validReqTypes = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'] + const hasBody = ['POST', 'PUT', 'PATCH'] if (_.indexOf(validReqTypes, _.upperCase(reqType)) === -1) { - throw new Error("Invalid request type"); + throw new Error('Invalid request type') } - const reqMethod = request[_.lowerCase(reqType)]; + const reqMethod = request[_.lowerCase(reqType)] if (_.indexOf(hasBody, _.upperCase(reqType)) === -1) { return reqMethod(path) .set(authHeader) - .set("Content-Type", "application/json"); + .set('Content-Type', 'application/json') } else { return reqMethod(path) .set(authHeader) - .set("Content-Type", "application/json") - .send(reqBody); + .set('Content-Type', 'application/json') + .send(reqBody) } } @@ -64,57 +64,56 @@ async function reqToAPI(reqType, path, reqBody) { * Gets the user's handle given the user's ID * @param {String} userId User's ID (6-digit numeric) */ -async function getUserDetailsById(userId) { - const path = `${config.TOPCODER.API_URL}/v3/users?filter=id%3D${userId}`; - return reqToAPI("GET", path); +async function getUserDetailsById (userId) { + const path = `${config.TOPCODER.API_URL}/v3/users?filter=id%3D${userId}` + return reqToAPI('GET', path) } /** * Gets the user by Topcoder's handle * @param {String} handle */ -async function getUserDetailsByHandle(handle) { - const path = `${config.TOPCODER.API_URL}/v3/users?filter=handle%3D${handle}`; - return reqToAPI("GET", path); +async function getUserDetailsByHandle (handle) { + const path = `${config.TOPCODER.API_URL}/v3/users?filter=handle%3D${handle}` + return reqToAPI('GET', path) } /** * Gets the challenge * @param {String} challengeId Challenge's ID (uuid) */ -async function getChallenge(challengeId) { - const path = `${config.TOPCODER.API_URL}/v5/challenges/${challengeId}`; - return reqToAPI("GET", path); +async function getChallenge (challengeId) { + const path = `${config.TOPCODER.API_URL}/v5/challenges/${challengeId}` + return reqToAPI('GET', path) } /** * Update the challenge * @param {String} challengeId Challenge's ID (uuid) */ -async function updateChallenge(challengeId, data) { - const path = `${config.TOPCODER.API_URL}/v5/challenges/${challengeId}`; - return reqToAPI("PATCH", path, data); +async function updateChallenge (challengeId, data) { + const path = `${config.TOPCODER.API_URL}/v5/challenges/${challengeId}` + return reqToAPI('PATCH', path, data) } /** * Gets the roles for an user * @param {int} userId User's ID */ -async function getRoles(userId) { - const path = `${config.TOPCODER.API_URL}/v3/roles?filter=subjectID%3D${userId}`; - return reqToAPI("GET", path); +async function getRoles (userId) { + const path = `${config.TOPCODER.API_URL}/v3/roles?filter=subjectID%3D${userId}` + return reqToAPI('GET', path) } /** * Gets the project * @param {int} projectId Project's Id (int) */ -async function getProject(projectId) { - const path = `${config.TOPCODER.API_URL}/v5/projects/${projectId}`; - return reqToAPI("GET", path); +async function getProject (projectId) { + const path = `${config.TOPCODER.API_URL}/v5/projects/${projectId}` + return reqToAPI('GET', path) } - module.exports = { getUserDetailsById, getUserDetailsByHandle, @@ -122,4 +121,4 @@ module.exports = { updateChallenge, getRoles, getProject -}; +} diff --git a/src/utils/vanilla-client.util.js b/src/utils/vanilla-client.util.js index 27d1e5f..a76c9cc 100644 --- a/src/utils/vanilla-client.util.js +++ b/src/utils/vanilla-client.util.js @@ -24,6 +24,11 @@ function getVanillaClient () { throw err }) }, + updateCategory: (categoryId, data) => { + return request.patch(`${config.VANILLA.API_URL}/categories/${categoryId}`) + .query({ access_token: config.VANILLA.ADMIN_ACCESS_TOKEN }) + .send(data) + }, getCategories: (parentCategoryID) => { const queryParams = { access_token: config.VANILLA.ADMIN_ACCESS_TOKEN } if (_.isNumber(parentCategoryID)) { @@ -39,9 +44,14 @@ function getVanillaClient () { return request.get(`${config.VANILLA.API_URL}/categories`) .query(queryParams) }, - getGroupCategory: () => { + getCategoryByUrlcode: (urlcode) => { + const queryParams = { access_token: config.VANILLA.ADMIN_ACCESS_TOKEN } + return request.get(`${config.VANILLA.API_URL}/categories/urlcode/${urlcode}`) + .query(queryParams) + }, + getCategoryForEdit: (categoryId) => { const queryParams = { access_token: config.VANILLA.ADMIN_ACCESS_TOKEN } - return request.get(`${config.VANILLA.API_URL}/groups/category`) + return request.get(`${config.VANILLA.API_URL}/categories/${categoryId}/edit`) .query(queryParams) }, watchCategory: (categoryId, userId, data) => {