diff --git a/src/constants.js b/src/constants.js index 032e1e8d..8e01042c 100644 --- a/src/constants.js +++ b/src/constants.js @@ -18,6 +18,7 @@ export const PROJECT_MEMBER_ROLE = { OBSERVER: 'observer', CUSTOMER: 'customer', COPILOT: 'copilot', + ACCOUNT_MANAGER: 'account_manager', }; export const PROJECT_MEMBER_MANAGER_ROLES = [PROJECT_MEMBER_ROLE.MANAGER, PROJECT_MEMBER_ROLE.OBSERVER]; @@ -31,7 +32,7 @@ export const USER_ROLE = { export const ADMIN_ROLES = [USER_ROLE.CONNECT_ADMIN, USER_ROLE.TOPCODER_ADMIN]; -export const MANAGER_ROLES = [...ADMIN_ROLES, USER_ROLE.MANAGER]; +export const MANAGER_ROLES = [...ADMIN_ROLES, USER_ROLE.MANAGER, PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER]; export const EVENT = { ROUTING_KEY: { diff --git a/src/routes/projectMembers/create.js b/src/routes/projectMembers/create.js index 96c34a85..40432300 100644 --- a/src/routes/projectMembers/create.js +++ b/src/routes/projectMembers/create.js @@ -1,9 +1,9 @@ - - import _ from 'lodash'; +import Joi from 'joi'; +import validate from 'express-validation'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; -import { USER_ROLE, PROJECT_MEMBER_ROLE, MANAGER_ROLES, INVITE_STATUS } from '../../constants'; +import { INVITE_STATUS, MANAGER_ROLES, PROJECT_MEMBER_ROLE, USER_ROLE } from '../../constants'; import models from '../../models'; /** @@ -13,14 +13,40 @@ import models from '../../models'; */ const permissions = tcMiddleware.permissions; +const createProjectMemberValidations = { + body: { + param: Joi.object() + .keys({ + role: Joi.any() + .valid(PROJECT_MEMBER_ROLE.MANAGER, PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER, PROJECT_MEMBER_ROLE.COPILOT), + }), + }, +}; + module.exports = [ // handles request validations + validate(createProjectMemberValidations), permissions('project.addMember'), (req, res, next) => { let targetRole; - if (util.hasRoles(req, [USER_ROLE.MANAGER])) { + if (_.get(req, 'body.param.role')) { + targetRole = _.get(req, 'body.param.role'); + + if ([PROJECT_MEMBER_ROLE.MANAGER, PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER].includes(targetRole) && + !util.hasRoles(req, [USER_ROLE.MANAGER])) { + const err = new Error(`Only manager is able to join as ${targetRole}`); + err.status = 401; + return next(err); + } + + if (targetRole === PROJECT_MEMBER_ROLE.COPILOT && !util.hasRoles(req, [USER_ROLE.COPILOT])) { + const err = new Error(`Only copilot is able to join as ${targetRole}`); + err.status = 401; + return next(err); + } + } else if (util.hasRoles(req, [USER_ROLE.MANAGER, USER_ROLE.CONNECT_ADMIN])) { targetRole = PROJECT_MEMBER_ROLE.MANAGER; - } else if (util.hasRoles(req, [USER_ROLE.COPILOT])) { + } else if (util.hasRoles(req, [USER_ROLE.COPILOT, USER_ROLE.CONNECT_ADMIN])) { targetRole = PROJECT_MEMBER_ROLE.COPILOT; } else { const err = new Error('Only copilot or manager is able to call this endpoint'); @@ -60,13 +86,17 @@ module.exports = [ .then((_invite) => { invite = _invite; if (!invite) { - return res.status(201).json(util.wrapResponse(req.id, newMember, 1, 201)); + return res.status(201) + .json(util.wrapResponse(req.id, newMember, 1, 201)); } return invite.update({ status: INVITE_STATUS.ACCEPTED, - }).then(() => res.status(201).json(util.wrapResponse(req.id, newMember, 1, 201))); + }) + .then(() => res.status(201) + .json(util.wrapResponse(req.id, newMember, 1, 201))); }); }); - }).catch(err => next(err)); + }) + .catch(err => next(err)); }, ]; diff --git a/src/routes/projectMembers/update.js b/src/routes/projectMembers/update.js index 97efadb1..7001133f 100644 --- a/src/routes/projectMembers/update.js +++ b/src/routes/projectMembers/update.js @@ -17,7 +17,7 @@ const updateProjectMemberValdiations = { param: Joi.object().keys({ isPrimary: Joi.boolean(), role: Joi.any().valid(PROJECT_MEMBER_ROLE.CUSTOMER, PROJECT_MEMBER_ROLE.MANAGER, - PROJECT_MEMBER_ROLE.COPILOT, PROJECT_MEMBER_ROLE.OBSERVER).required(), + PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER, PROJECT_MEMBER_ROLE.COPILOT, PROJECT_MEMBER_ROLE.OBSERVER).required(), }), }, };