Skip to content

implement new roles #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ export const PROJECT_MEMBER_ROLE = {
CUSTOMER: 'customer',
COPILOT: 'copilot',
ACCOUNT_MANAGER: 'account_manager',
PROGRAM_MANAGER: 'program_manager',
ACCOUNT_EXECUTIVE: 'account_executive',
SOLUTION_ARCHITECT: 'solution_architect',
PROJECT_MANAGER: 'project_manager',
};

export const PROJECT_MEMBER_MANAGER_ROLES = [
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.OBSERVER,
PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER,
PROJECT_MEMBER_ROLE.ACCOUNT_EXECUTIVE,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
];

export const USER_ROLE = {
Expand All @@ -42,6 +50,12 @@ export const USER_ROLE = {
COPILOT: 'Connect Copilot',
CONNECT_ADMIN: 'Connect Admin',
COPILOT_MANAGER: 'Connect Copilot Manager',
BUSINESS_DEVELOPMENT_REPRESENTATIVE: 'Business Development Representative',
PRESALES: 'Presales',
ACCOUNT_EXECUTIVE: 'Account Executive',
PROGRAM_MANAGER: 'Program Manager',
SOLUTION_ARCHITECT: 'Solution Architect',
PROJECT_MANAGER: 'Project Manager',
};

export const ADMIN_ROLES = [USER_ROLE.CONNECT_ADMIN, USER_ROLE.TOPCODER_ADMIN];
Expand All @@ -51,6 +65,13 @@ export const MANAGER_ROLES = [
USER_ROLE.MANAGER,
USER_ROLE.TOPCODER_ACCOUNT_MANAGER,
USER_ROLE.COPILOT_MANAGER,
USER_ROLE.BUSINESS_DEVELOPMENT_REPRESENTATIVE,
USER_ROLE.PRESALES,
USER_ROLE.ACCOUNT_EXECUTIVE,

USER_ROLE.PROGRAM_MANAGER,
USER_ROLE.SOLUTION_ARCHITECT,
USER_ROLE.PROJECT_MANAGER,
];

export const EVENT = {
Expand Down
16 changes: 14 additions & 2 deletions src/events/projectMembers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ const projectMemberAddedHandler = Promise.coroutine(function* a(logger, msg, cha
const newMember = JSON.parse(msg.content.toString());
const projectId = newMember.projectId;
const directUpdatePromise = Promise.coroutine(function* () { // eslint-disable-line func-names
if (_.indexOf([PROJECT_MEMBER_ROLE.COPILOT, PROJECT_MEMBER_ROLE.MANAGER], newMember.role) > -1) {
if (_.indexOf([
PROJECT_MEMBER_ROLE.COPILOT,
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
], newMember.role) > -1) {
// add copilot/update manager permissions operation promise
const directProjectId = yield models.Project.getDirectProjectId(projectId);
if (directProjectId) {
Expand Down Expand Up @@ -116,7 +122,13 @@ const projectMemberRemovedHandler = Promise.coroutine(function* (logger, msg, ch
const projectId = member.projectId;
// remove copilot/manager operation promise
const updateDirectProjectPromise = Promise.coroutine(function* () { // eslint-disable-line func-names
if (_.indexOf([PROJECT_MEMBER_ROLE.COPILOT, PROJECT_MEMBER_ROLE.MANAGER], member.role) > -1) {
if (_.indexOf([
PROJECT_MEMBER_ROLE.COPILOT,
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
], member.role) > -1) {
const directProjectId = yield models.Project.getDirectProjectId(projectId);
if (directProjectId) {
const token = yield util.getM2MToken();
Expand Down
3 changes: 3 additions & 0 deletions src/permissions/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export
ROLES_COPILOT_AND_ABOVE: {
topcoderRoles: ADMIN_ROLES,
projectRoles: [
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.COPILOT,
],
Expand Down
8 changes: 7 additions & 1 deletion src/permissions/project.delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ module.exports = freq => new Promise((resolve, reject) => {
const hasAccess = util.hasAdminRole(req) ||
!_.isUndefined(_.find(members, m => m.userId === req.authUser.userId &&
((m.role === PROJECT_MEMBER_ROLE.CUSTOMER && m.isPrimary) ||
m.role === PROJECT_MEMBER_ROLE.MANAGER)));
[
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
].includes(m.role)
)));

if (!hasAccess) {
// user is not an admin nor is a registered project member
Expand Down
7 changes: 6 additions & 1 deletion src/permissions/projectMember.delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ module.exports = freq => new Promise((resolve, reject) => {
const memberToBeRemoved = _.find(members, m => m.id === prjMemberId);
// check if auth user has acecss to this project
const hasAccess = util.hasAdminRole(req)
|| (authMember && memberToBeRemoved && (authMember.role === PROJECT_MEMBER_ROLE.MANAGER ||
|| (authMember && memberToBeRemoved && ([
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
].includes(authMember.role) ||
(authMember.role === PROJECT_MEMBER_ROLE.CUSTOMER && authMember.isPrimary &&
memberToBeRemoved.role === PROJECT_MEMBER_ROLE.CUSTOMER) ||
memberToBeRemoved.userId === req.authUser.userId));
Expand Down
2 changes: 1 addition & 1 deletion src/routes/projectMemberInvites/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ module.exports = [
}
return Promise.all(promises).then((rolesList) => {
if (!!invite.userIds && _.includes(PROJECT_MEMBER_MANAGER_ROLES, invite.role)) {
req.log.debug('Chekcing if userId is allowed as manager');
req.log.debug('Checking if userId is allowed as manager');
const forbidUserList = [];
_.zip(invite.userIds, rolesList).forEach((data) => {
const [userId, roles] = data;
Expand Down
64 changes: 60 additions & 4 deletions src/routes/projectMembers/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ const createProjectMemberValidations = {
param: Joi.object()
.keys({
role: Joi.any()
.valid(PROJECT_MEMBER_ROLE.MANAGER, PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER, PROJECT_MEMBER_ROLE.COPILOT),
.valid(
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER,
PROJECT_MEMBER_ROLE.COPILOT,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
PROJECT_MEMBER_ROLE.ACCOUNT_EXECUTIVE,
),
}),
},
};
Expand All @@ -39,9 +47,45 @@ module.exports = [
return next(err);
}

if (PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT === targetRole &&
!util.hasRoles(req, [USER_ROLE.SOLUTION_ARCHITECT])) {
const err = new Error(`Only solution architect is able to join as ${targetRole}`);
err.status = 401;
return next(err);
}

if (PROJECT_MEMBER_ROLE.PROJECT_MANAGER === targetRole &&
!util.hasRoles(req, [USER_ROLE.PROJECT_MANAGER])) {
const err = new Error(`Only project manager is able to join as ${targetRole}`);
err.status = 401;
return next(err);
}

if (PROJECT_MEMBER_ROLE.PROGRAM_MANAGER === targetRole &&
!util.hasRoles(req, [USER_ROLE.PROGRAM_MANAGER])) {
const err = new Error(`Only program manager is able to join as ${targetRole}`);
err.status = 401;
return next(err);
}

if (PROJECT_MEMBER_ROLE.ACCOUNT_EXECUTIVE === targetRole &&
!util.hasRoles(req, [USER_ROLE.ACCOUNT_EXECUTIVE])) {
const err = new Error(`Only account executive is able to join as ${targetRole}`);
err.status = 401;
return next(err);
}

if (PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER === targetRole &&
!util.hasRoles(req, [USER_ROLE.MANAGER, USER_ROLE.TOPCODER_ACCOUNT_MANAGER])) {
const err = new Error(`Only manager or account manager is able to join as ${targetRole}`);
!util.hasRoles(req, [
USER_ROLE.MANAGER,
USER_ROLE.TOPCODER_ACCOUNT_MANAGER,
USER_ROLE.BUSINESS_DEVELOPMENT_REPRESENTATIVE,
USER_ROLE.PRESALES,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fikzzzy it looks like we have to add to this list all new USER_ROLES. As before we had there both USER_ROLE.MANAGER and USER_ROLE.TOPCODER_ACCOUNT_MANAGER.

])) {
const err = new Error(
`Only manager, account manager, business development representative,
or presales are able to join as ${targetRole}`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fikzzzy if we add more roles above, we also have to update this message.

);
err.status = 401;
return next(err);
}
Expand All @@ -53,10 +97,22 @@ module.exports = [
}
} else if (util.hasRoles(req, [USER_ROLE.MANAGER, USER_ROLE.CONNECT_ADMIN])) {
targetRole = PROJECT_MEMBER_ROLE.MANAGER;
} else if (util.hasRoles(req, [USER_ROLE.TOPCODER_ACCOUNT_MANAGER])) {
} else if (util.hasRoles(req, [
USER_ROLE.TOPCODER_ACCOUNT_MANAGER,
USER_ROLE.BUSINESS_DEVELOPMENT_REPRESENTATIVE,
USER_ROLE.PRESALES,
])) {
targetRole = PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER;
} else if (util.hasRoles(req, [USER_ROLE.COPILOT, USER_ROLE.CONNECT_ADMIN])) {
targetRole = PROJECT_MEMBER_ROLE.COPILOT;
} else if (util.hasRoles(req, [USER_ROLE.ACCOUNT_EXECUTIVE])) {
targetRole = PROJECT_MEMBER_ROLE.ACCOUNT_EXECUTIVE;
} else if (util.hasRoles(req, [USER_ROLE.PROGRAM_MANAGER])) {
targetRole = PROJECT_MEMBER_ROLE.PROGRAM_MANAGER;
} else if (util.hasRoles(req, [USER_ROLE.SOLUTION_ARCHITECT])) {
targetRole = PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT;
} else if (util.hasRoles(req, [USER_ROLE.PROJECT_MANAGER])) {
targetRole = PROJECT_MEMBER_ROLE.PROJECT_MANAGER;
} else {
const err = new Error('Only copilot or manager is able to call this endpoint');
err.status = 401;
Expand Down
13 changes: 11 additions & 2 deletions src/routes/projectMembers/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@ const updateProjectMemberValdiations = {
body: {
param: Joi.object().keys({
isPrimary: Joi.boolean(),
role: Joi.any().valid(PROJECT_MEMBER_ROLE.CUSTOMER, PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER, PROJECT_MEMBER_ROLE.COPILOT, PROJECT_MEMBER_ROLE.OBSERVER).required(),
role: Joi.any().valid(
PROJECT_MEMBER_ROLE.CUSTOMER,
PROJECT_MEMBER_ROLE.MANAGER,
PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER,
PROJECT_MEMBER_ROLE.COPILOT,
PROJECT_MEMBER_ROLE.OBSERVER,
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
PROJECT_MEMBER_ROLE.ACCOUNT_EXECUTIVE,
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
).required(),
}),
},
};
Expand Down
3 changes: 1 addition & 2 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import config from 'config';
import urlencode from 'urlencode';
import elasticsearch from 'elasticsearch';
import Promise from 'bluebird';
import models from './models';
// import AWS from 'aws-sdk';

import { ADMIN_ROLES, TOKEN_SCOPES, EVENT, PROJECT_MEMBER_ROLE, VALUE_TYPE, ESTIMATION_TYPE } from './constants';

const exec = require('child_process').exec;
const models = require('./models').default;
const tcCoreLibAuth = require('tc-core-library-js').auth;

const m2m = tcCoreLibAuth.m2m(config);
Expand Down Expand Up @@ -474,7 +474,6 @@ _.assignIn(util, {
req.log.debug('creating member', member);
let newMember = null;
// register member

return models.ProjectMember.create(member)
.then((_newMember) => {
newMember = _newMember.get({ plain: true });
Expand Down