diff --git a/.circleci/config.yml b/.circleci/config.yml index 8f587714..e2ac728e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -149,7 +149,7 @@ workflows: context : org-global filters: branches: - only: ['develop', 'migration-setup', 'PM-1612'] + only: ['develop', 'migration-setup', 'PM-1612', 'fix-project-exposing'] - deployProd: context : org-global filters: diff --git a/src/routes/copilotOpportunity/get.js b/src/routes/copilotOpportunity/get.js index e4bad5c8..f71394fd 100644 --- a/src/routes/copilotOpportunity/get.js +++ b/src/routes/copilotOpportunity/get.js @@ -1,3 +1,4 @@ +import { USER_ROLE } from '../../constants'; import models from '../../models'; import util from '../../util'; @@ -8,9 +9,11 @@ module.exports = [ return util.handleError('Invalid opportunity ID', null, req, next, 400); } + const isAdminOrManager = util.hasRoles(req, [USER_ROLE.CONNECT_ADMIN, USER_ROLE.TOPCODER_ADMIN, USER_ROLE.PROJECT_MANAGER]); + return models.CopilotOpportunity.findOne({ where: { id }, - include: [ + include: isAdminOrManager ? [ { model: models.CopilotRequest, as: 'copilotRequest', @@ -27,17 +30,25 @@ module.exports = [ }, ] }, + ]: [ + { + model: models.CopilotRequest, + as: 'copilotRequest', + }, ], }) .then((copilotOpportunity) => { const plainOpportunity = copilotOpportunity.get({ plain: true }); - const memberIds = plainOpportunity.project.members && plainOpportunity.project.members.map((member) => member.userId); + const memberIds = (plainOpportunity.project && plainOpportunity.project.members && plainOpportunity.project.members.map((member) => member.userId)) || []; let canApplyAsCopilot = false; if (req.authUser) { canApplyAsCopilot = !memberIds.includes(req.authUser.userId) } - // This shouldn't be exposed to the clientside - delete plainOpportunity.project.members; + + if (plainOpportunity.project) { + // This shouldn't be exposed to the clientside + delete plainOpportunity.project.members; + } const formattedOpportunity = Object.assign({ members: memberIds, canApplyAsCopilot, @@ -45,6 +56,10 @@ module.exports = [ plainOpportunity.copilotRequest ? plainOpportunity.copilotRequest.data : {}, { copilotRequest: undefined }, ); + + if (!isAdminOrManager) { + delete formattedOpportunity.projectId; + } res.json(formattedOpportunity); }) .catch((err) => { diff --git a/src/routes/copilotOpportunity/list.js b/src/routes/copilotOpportunity/list.js index 9a806290..9206157c 100644 --- a/src/routes/copilotOpportunity/list.js +++ b/src/routes/copilotOpportunity/list.js @@ -2,7 +2,7 @@ import _ from 'lodash'; import models from '../../models'; import util from '../../util'; -import DEFAULT_PAGE_SIZE from '../../constants'; +import DEFAULT_PAGE_SIZE, { USER_ROLE } from '../../constants'; module.exports = [ (req, res, next) => { @@ -15,6 +15,7 @@ module.exports = [ return util.handleError('Invalid sort criteria', null, req, next); } const sortParams = sort.split(' '); + const isAdminOrManager = util.hasRoles(req, [USER_ROLE.CONNECT_ADMIN, USER_ROLE.TOPCODER_ADMIN, USER_ROLE.PROJECT_MANAGER]); // Extract pagination parameters const page = parseInt(req.query.page, 10) || 1; @@ -42,7 +43,7 @@ module.exports = [ baseOrder.push([sortParams[0], sortParams[1]]); return models.CopilotOpportunity.findAll({ - include: [ + include: isAdminOrManager ?[ { model: models.CopilotRequest, as: 'copilotRequest', @@ -52,6 +53,11 @@ module.exports = [ as: 'project', attributes: ['name'], }, + ] : [ + { + model: models.CopilotRequest, + as: 'copilotRequest', + } ], order: baseOrder, limit, @@ -60,10 +66,18 @@ module.exports = [ .then((copilotOpportunities) => { const formattedOpportunities = copilotOpportunities.map((opportunity) => { const plainOpportunity = opportunity.get({ plain: true }); - return Object.assign({}, plainOpportunity, + + const formatted = Object.assign({}, plainOpportunity, plainOpportunity.copilotRequest ? plainOpportunity.copilotRequest.data : {}, { copilotRequest: undefined }, ); + + // For users who are not admin or manager, we dont want to expose + // the project id + if (!isAdminOrManager) { + delete formatted.projectId; + } + return formatted; }); return util.setPaginationHeaders(req, res, { count: copilotOpportunities.count, diff --git a/src/routes/copilotRequest/list.js b/src/routes/copilotRequest/list.js index ef36d26b..92b73614 100644 --- a/src/routes/copilotRequest/list.js +++ b/src/routes/copilotRequest/list.js @@ -4,7 +4,7 @@ import { Op, Sequelize } from 'sequelize'; import models from '../../models'; import util from '../../util'; import { PERMISSION } from '../../permissions/constants'; -import { DEFAULT_PAGE_SIZE } from '../../constants'; +import { DEFAULT_PAGE_SIZE, USER_ROLE } from '../../constants'; module.exports = [ (req, res, next) => { @@ -17,6 +17,8 @@ module.exports = [ return next(err); } + const isAdminOrManager = util.hasRoles(req, [USER_ROLE.CONNECT_ADMIN, USER_ROLE.TOPCODER_ADMIN, USER_ROLE.PROJECT_MANAGER]); + const page = parseInt(req.query.page, 10) || 1; const pageSize = parseInt(req.query.pageSize, 10) || DEFAULT_PAGE_SIZE; const offset = (page - 1) * pageSize; @@ -46,7 +48,7 @@ module.exports = [ let order = [[sortParams[0], sortParams[1]]]; const relationBasedSortParams = ['projectName']; const jsonBasedSortParams = ['opportunityTitle', 'projectType']; - if (relationBasedSortParams.includes(sortParams[0])) { + if (relationBasedSortParams.includes(sortParams[0]) && isAdminOrManager) { order = [ [{model: models.Project, as: 'project'}, 'name', sortParams[1]], ['id', 'DESC'] @@ -64,9 +66,11 @@ module.exports = [ return models.CopilotRequest.findAndCountAll({ where: whereCondition, - include: [ + include: isAdminOrManager ? [ { model: models.CopilotOpportunity, as: 'copilotOpportunity', required: false }, { model: models.Project, as: 'project', required: false }, + ] : [ + { model: models.CopilotOpportunity, as: 'copilotOpportunity', required: false }, ], order, limit: pageSize,