From ec0fa1ddfebf0bc261fd48798510ef7ef740b032 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 13:55:58 +0200 Subject: [PATCH 01/10] feat: remove copilot members and invites --- docs/permissions.html | 82 +++++++++++++------ src/permissions/constants.js | 61 ++++++++------ src/permissions/index.js | 8 +- src/routes/projectMemberInvites/create.js | 12 ++- .../projectMemberInvites/create.spec.js | 26 +++++- src/routes/projectMemberInvites/delete.js | 9 +- .../projectMemberInvites/delete.spec.js | 25 +++++- src/routes/projectMembers/delete.js | 27 +++++- src/tests/util.js | 2 + 9 files changed, 191 insertions(+), 61 deletions(-) diff --git a/docs/permissions.html b/docs/permissions.html index 43823aa0..93903a34 100644 --- a/docs/permissions.html +++ b/docs/permissions.html @@ -523,19 +523,19 @@

- Update Project Member (to copilot) + Delete Project Member (customer)
-
UPDATE_PROJECT_MEMBER_TO_COPILOT
-
Who can update project member role to "copilot".
+
DELETE_PROJECT_MEMBER_CUSTOMER
+
Who can delete project members with "customer" role.
+ Any Project Member
Connect Admin administrator - Connect Copilot Manager
@@ -548,14 +548,19 @@

- Delete Project Member (customer) + Delete Project Member (topcoder)
-
DELETE_PROJECT_MEMBER_CUSTOMER
-
Who can delete project members with "customer" role.
+
DELETE_PROJECT_MEMBER_TOPCODER
+
Who can delete project members with some topcoder role like "manager" etc.
- Any Project Member + manager + account_manager + program_manager + account_executive + solution_architect + project_manager
@@ -573,24 +578,20 @@

- Delete Project Member (non-customer) + Delete Project Member (copilot)
-
DELETE_PROJECT_MEMBER_NON_CUSTOMER
-
Who can delete project members with non "customer" role.
+
DELETE_PROJECT_MEMBER_COPILOT
+
Who can delete project members with "copilot" role.
- manager - account_manager - program_manager - account_executive - solution_architect - project_manager + Any Project Member
Connect Admin administrator + Connect Copilot Manager
@@ -701,10 +702,10 @@

- Create Project Invite (non-customer) + Create Project Invite (topcoder)
-
CREATE_PROJECT_INVITE_NON_CUSTOMER
-
Who can invite project members with non "customer" role.
+
CREATE_PROJECT_INVITE_TOPCODER
+
Who can invite project members with topcoder role like "manager" etc.
@@ -731,9 +732,9 @@

- Create Project Invite (copilot) + Create Project Invite (copilot)
-
CREATE_PROJECT_INVITE_COPILOT_DIRECTLY
+
CREATE_PROJECT_INVITE_COPILOT
Who can invite user with "copilot" role directly without requesting.
@@ -876,10 +877,10 @@

- Delete Project Invite (not own, non-customer) + Delete Project Invite (not own, topcoder)
-
DELETE_PROJECT_INVITE_NOT_OWN_NON_CUSTOMER
-
Who can delete project invites for other members with non "customer" role.
+
DELETE_PROJECT_INVITE_NOT_OWN_TOPCODER
+
Who can delete project invites for other members with some topcoder role like "manager" etc.
@@ -903,6 +904,37 @@

+
+
+
+ Delete Project Invite (not own, copilot) +
+
DELETE_PROJECT_INVITE_NOT_OWN_COPILOT
+
Who can delete invites for other members with "copilot" role.
+
+
+
+ manager + account_manager + program_manager + account_executive + solution_architect + project_manager +
+ +
+ Connect Admin + administrator + Connect Copilot Manager +
+ +
+ all:connect_project + all:project-invites + write:project-invites +
+
+
diff --git a/src/permissions/constants.js b/src/permissions/constants.js index c69cf36f..ce9aeeee 100644 --- a/src/permissions/constants.js +++ b/src/permissions/constants.js @@ -306,19 +306,6 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export scopes: SCOPES_PROJECT_MEMBERS_WRITE, }, - UPDATE_PROJECT_MEMBER_TO_COPILOT: { - meta: { - title: 'Update Project Member (to copilot)', - group: 'Project Member', - description: 'Who can update project member role to "copilot".', - }, - topcoderRoles: [ - ...TOPCODER_ROLES_ADMINS, - USER_ROLE.COPILOT_MANAGER, - ], - scopes: SCOPES_PROJECT_MEMBERS_WRITE, - }, - DELETE_PROJECT_MEMBER_CUSTOMER: { meta: { title: 'Delete Project Member (customer)', @@ -330,17 +317,31 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export scopes: SCOPES_PROJECT_MEMBERS_WRITE, }, - DELETE_PROJECT_MEMBER_NON_CUSTOMER: { + DELETE_PROJECT_MEMBER_TOPCODER: { meta: { - title: 'Delete Project Member (non-customer)', + title: 'Delete Project Member (topcoder)', group: 'Project Member', - description: 'Who can delete project members with non "customer" role.', + description: 'Who can delete project members with some topcoder role like "manager" etc.', }, topcoderRoles: TOPCODER_ROLES_ADMINS, projectRoles: PROJECT_ROLES_MANAGEMENT, scopes: SCOPES_PROJECT_MEMBERS_WRITE, }, + DELETE_PROJECT_MEMBER_COPILOT: { + meta: { + title: 'Delete Project Member (copilot)', + group: 'Project Member', + description: 'Who can delete project members with "copilot" role.', + }, + topcoderRoles: [ + ...TOPCODER_ROLES_ADMINS, + USER_ROLE.COPILOT_MANAGER, + ], + projectRoles: ALL, + scopes: SCOPES_PROJECT_MEMBERS_WRITE, + }, + /* * Project Invite */ @@ -376,18 +377,18 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export scopes: SCOPES_PROJECT_INVITES_WRITE, }, - CREATE_PROJECT_INVITE_NON_CUSTOMER: { + CREATE_PROJECT_INVITE_TOPCODER: { meta: { - title: 'Create Project Invite (non-customer)', + title: 'Create Project Invite (topcoder)', group: 'Project Invite', - description: 'Who can invite project members with non "customer" role.', + description: 'Who can invite project members with topcoder role like "manager" etc.', }, topcoderRoles: TOPCODER_ROLES_ADMINS, projectRoles: PROJECT_ROLES_MANAGEMENT, scopes: SCOPES_PROJECT_INVITES_WRITE, }, - CREATE_PROJECT_INVITE_COPILOT_DIRECTLY: { + CREATE_PROJECT_INVITE_COPILOT: { meta: { title: 'Create Project Invite (copilot)', group: 'Project Invite', @@ -454,17 +455,31 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export scopes: SCOPES_PROJECT_INVITES_WRITE, }, - DELETE_PROJECT_INVITE_NOT_OWN_NON_CUSTOMER: { + DELETE_PROJECT_INVITE_NOT_OWN_TOPCODER: { meta: { - title: 'Delete Project Invite (not own, non-customer)', + title: 'Delete Project Invite (not own, topcoder)', group: 'Project Invite', - description: 'Who can delete project invites for other members with non "customer" role.', + description: 'Who can delete project invites for other members with some topcoder role like "manager" etc.', }, topcoderRoles: TOPCODER_ROLES_ADMINS, projectRoles: PROJECT_ROLES_MANAGEMENT, scopes: SCOPES_PROJECT_INVITES_WRITE, }, + DELETE_PROJECT_INVITE_NOT_OWN_COPILOT: { + meta: { + title: 'Delete Project Invite (not own, copilot)', + group: 'Project Invite', + description: 'Who can delete invites for other members with "copilot" role.', + }, + topcoderRoles: [ + ...TOPCODER_ROLES_ADMINS, + USER_ROLE.COPILOT_MANAGER, + ], + projectRoles: PROJECT_ROLES_MANAGEMENT, + scopes: SCOPES_PROJECT_INVITES_WRITE, + }, + DELETE_PROJECT_INVITE_REQUESTED: { meta: { title: 'Delete Project Invite (requested)', diff --git a/src/permissions/index.js b/src/permissions/index.js index 9344c0b1..3a3f6f1a 100644 --- a/src/permissions/index.js +++ b/src/permissions/index.js @@ -31,12 +31,13 @@ module.exports = () => { ])); Authorizer.setPolicy('projectMember.delete', generalPermission([ PERMISSION.DELETE_PROJECT_MEMBER_CUSTOMER, - PERMISSION.DELETE_PROJECT_MEMBER_NON_CUSTOMER, + PERMISSION.DELETE_PROJECT_MEMBER_TOPCODER, + PERMISSION.DELETE_PROJECT_MEMBER_COPILOT, ])); Authorizer.setPolicy('projectMemberInvite.create', generalPermission([ PERMISSION.CREATE_PROJECT_INVITE_CUSTOMER, - PERMISSION.CREATE_PROJECT_INVITE_NON_CUSTOMER, + PERMISSION.CREATE_PROJECT_INVITE_TOPCODER, ])); Authorizer.setPolicy('projectMemberInvite.view', generalPermission([ PERMISSION.READ_PROJECT_INVITE_OWN, @@ -49,7 +50,8 @@ module.exports = () => { Authorizer.setPolicy('projectMemberInvite.delete', generalPermission([ PERMISSION.DELETE_PROJECT_INVITE_OWN, PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_CUSTOMER, - PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_NON_CUSTOMER, + PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_COPILOT, + PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_TOPCODER, ])); Authorizer.setPolicy('projectAttachment.create', generalPermission(PERMISSION.CREATE_PROJECT_ATTACHMENT)); diff --git a/src/routes/projectMemberInvites/create.js b/src/routes/projectMemberInvites/create.js index 97e0cd25..1f113739 100644 --- a/src/routes/projectMemberInvites/create.js +++ b/src/routes/projectMemberInvites/create.js @@ -274,8 +274,14 @@ module.exports = [ } if ( - invite.role !== PROJECT_MEMBER_ROLE.CUSTOMER && - !util.hasPermissionByReq(PERMISSION.CREATE_PROJECT_INVITE_NON_CUSTOMER, req) + ( // if cannot invite non-customer user + invite.role !== PROJECT_MEMBER_ROLE.CUSTOMER && + !util.hasPermissionByReq(PERMISSION.CREATE_PROJECT_INVITE_TOPCODER, req) + ) && !( + // and if cannot invite copilot directly + invite.role === PROJECT_MEMBER_ROLE.COPILOT && + util.hasPermissionByReq(PERMISSION.CREATE_PROJECT_INVITE_COPILOT, req) + ) ) { const err = new Error(`You are not allowed to invite user as ${invite.role}.`); err.status = 403; @@ -373,7 +379,7 @@ module.exports = [ role: invite.role, // invite copilots directly if user has permissions status: (invite.role !== PROJECT_MEMBER_ROLE.COPILOT || - util.hasPermissionByReq(PERMISSION.CREATE_PROJECT_INVITE_COPILOT_DIRECTLY, req)) + util.hasPermissionByReq(PERMISSION.CREATE_PROJECT_INVITE_COPILOT, req)) ? INVITE_STATUS.PENDING : INVITE_STATUS.REQUESTED, createdBy: req.authUser.userId, diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 2ed2f15c..5eea05a0 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -736,7 +736,7 @@ describe('Project Member Invite create', () => { }); }); - it('should return 201 if try to create customer with COPILOT', (done) => { + it('should return 201 if try to create copilot invite with COPILOT role', (done) => { util.getUserRoles.restore(); sandbox.stub(util, 'getUserRoles', () => Promise.resolve(['Connect Copilot'])); request(server) @@ -764,6 +764,30 @@ describe('Project Member Invite create', () => { }); }); + it('should return 201 if try to create copilot invite by "Connect Copilot Manager"', (done) => { + util.getUserRoles.restore(); + sandbox.stub(util, 'getUserRoles', () => Promise.resolve([USER_ROLE.COPILOT])); + request(server) + .post(`/v5/projects/${project1.id}/invites`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilotManager}`, + }) + .send({ + handles: ['test_customer1'], + role: 'copilot', + }) + .expect('Content-Type', /json/) + .expect(201) + .end((err, res) => { + const resJson = res.body.success[0]; + should.exist(resJson); + resJson.role.should.equal('copilot'); + resJson.projectId.should.equal(project1.id); + resJson.userId.should.equal(40051331); + done(); + }); + }); + it('should return 403 and failed list when trying add already invited member by lowercase email', (done) => { request(server) .post(`/v5/projects/${project1.id}/invites`) diff --git a/src/routes/projectMemberInvites/delete.js b/src/routes/projectMemberInvites/delete.js index 2ec3536f..d8c8be91 100644 --- a/src/routes/projectMemberInvites/delete.js +++ b/src/routes/projectMemberInvites/delete.js @@ -44,8 +44,9 @@ module.exports = [ error = 'You don\'t have permissions to cancel requested invites.'; } else if ( invite.role !== PROJECT_MEMBER_ROLE.CUSTOMER + && invite.role !== PROJECT_MEMBER_ROLE.COPILOT && !ownInvite - && !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_NON_CUSTOMER, req) + && !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_TOPCODER, req) ) { error = 'You don\'t have permissions to cancel invites to Topcoder Team for other users.'; } else if ( @@ -54,6 +55,12 @@ module.exports = [ && !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_CUSTOMER, req) ) { error = 'You don\'t have permissions to cancel invites to Customer Team for other users.'; + } else if ( + invite.role === PROJECT_MEMBER_ROLE.COPILOT + && !ownInvite + && !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_INVITE_NOT_OWN_COPILOT, req) + ) { + error = 'You don\'t have permissions to cancel invites to Copilot Team for other users.'; } if (error) { diff --git a/src/routes/projectMemberInvites/delete.spec.js b/src/routes/projectMemberInvites/delete.spec.js index fbb601ec..d6bddd46 100644 --- a/src/routes/projectMemberInvites/delete.spec.js +++ b/src/routes/projectMemberInvites/delete.spec.js @@ -157,7 +157,20 @@ describe('Project member invite delete', () => { updatedAt: '2016-06-30 00:33:07+00', }); - return Promise.all([pm, invite4, invite5, invite6]); + const invite7 = models.ProjectMemberInvite.create({ + id: 7, + projectId: project2.id, + userId: testUtil.userIds.copilot, + email: null, + role: PROJECT_MEMBER_ROLE.COPILOT, + status: INVITE_STATUS.ACCEPTED, + createdBy: 1, + updatedBy: 1, + createdAt: '2016-06-30 00:33:07+00', + updatedAt: '2016-06-30 00:33:07+00', + }); + + return Promise.all([pm, invite4, invite5, invite6, invite7]); }); Promise.all([p1, p2]).then(() => done()); @@ -335,6 +348,16 @@ describe('Project member invite delete', () => { .end(() => done()); }); + it('should return 204 if "Connect Copilot Manager" cancels invitation for copilot', (done) => { + request(server) + .delete(`/v5/projects/${project1.id}/invites/7`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilotManager}`, + }) + .expect(204) + .end(() => done()); + }); + it('should return 204 if user cancels invitation', (done) => { request(server) .delete(`/v5/projects/${project1.id}/invites/5`) diff --git a/src/routes/projectMembers/delete.js b/src/routes/projectMembers/delete.js index 8c8e4d55..c654ecf6 100644 --- a/src/routes/projectMembers/delete.js +++ b/src/routes/projectMembers/delete.js @@ -31,12 +31,31 @@ module.exports = [ return Promise.reject(err); } + const isOwnMember = member.userId === req.authUser.userId; + if ( - member.userId !== req.authUser.userId && - member.role !== PROJECT_MEMBER_ROLE.CUSTOMER && - !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_MEMBER_NON_CUSTOMER, req) + !isOwnMember && + member.role !== PROJECT_MEMBER_ROLE.CUSTOMER && + member.role !== PROJECT_MEMBER_ROLE.COPILOT && + !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_MEMBER_TOPCODER, req) + ) { + const err = new Error('You don\'t have permissions to delete other members from Topcoder Team.'); + err.status = 403; + return Promise.reject(err); + } else if ( + !isOwnMember && + member.role === PROJECT_MEMBER_ROLE.CUSTOMER && + !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_MEMBER_CUSTOMER, req) + ) { + const err = new Error('You don\'t have permissions to delete other members with "customer" role.'); + err.status = 403; + return Promise.reject(err); + } else if ( + !isOwnMember && + member.role === PROJECT_MEMBER_ROLE.COPILOT && + !util.hasPermissionByReq(PERMISSION.DELETE_PROJECT_MEMBER_COPILOT, req) ) { - const err = new Error('You don\'t have permissions to delete other members with non-customer role.'); + const err = new Error('You don\'t have permissions to delete other members with "copilot" role.'); err.status = 403; return Promise.reject(err); } diff --git a/src/tests/util.js b/src/tests/util.js index e9a64bbb..4e50eb95 100644 --- a/src/tests/util.js +++ b/src/tests/util.js @@ -28,6 +28,8 @@ export default { admin: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw', // userId = 40051334, roles: [ 'Manager', 'Topcoder User' ],handle: 'test1',email: 'test@topcoder.com' manager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzQiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.J5VtOEQVph5jfe2Ji-NH7txEDcx_5gthhFeD-MzX9ck', + // userId = 40051337, roles: [ 'Connect Copilot Manager', 'Connect Manager', 'Topcoder User' ], handle: 'connect_copilot_manger', email: 'connect_copilot_manger@topcoder.com' + copilotManager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIiwiQ29ubmVjdCBDb3BpbG90IE1hbmFnZXIiXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXItZGV2LmNvbSIsImhhbmRsZSI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXIiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzM0IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXJAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.jamlfV2gDzPnCOiEIrkt0iWWkKW33KSGvfHoy02Iq_Y', // userId = 40051335, [ 'Topcoder User' ],handle: 'member2',email: 'test@topcoder.com' member2: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJtZW1iZXIyIiwiZXhwIjoyNTYzMDc2Njg5LCJ1c2VySWQiOiI0MDA1MTMzNSIsImlhdCI6MTQ2MzA3NjA4OSwiZW1haWwiOiJ0ZXN0QHRvcGNvZGVyLmNvbSIsImp0aSI6ImIzM2I3N2NkLWI1MmUtNDBmZS04MzdlLWJlYjhlMGFlNmE0YSJ9.Mh4bw3wm-cn5Kcf96gLFVlD0kySOqqk4xN3qnreAKL4', // userId = 40051336, [ 'Connect Admin' ], handle: 'connect_admin1', email: 'connect_admin1@topcoder.com' From 173d937966990eaee573f627f07775a25e2391af Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 14:16:36 +0200 Subject: [PATCH 02/10] fix: unit test --- src/routes/projectMemberInvites/create.spec.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 5eea05a0..40a259eb 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -779,12 +779,16 @@ describe('Project Member Invite create', () => { .expect('Content-Type', /json/) .expect(201) .end((err, res) => { - const resJson = res.body.success[0]; - should.exist(resJson); - resJson.role.should.equal('copilot'); - resJson.projectId.should.equal(project1.id); - resJson.userId.should.equal(40051331); - done(); + if (err) { + done(err); + } else { + const resJson = res.body.success[0]; + should.exist(resJson); + resJson.role.should.equal('copilot'); + resJson.projectId.should.equal(project1.id); + resJson.userId.should.equal(40051331); + done(); + } }); }); From d6346b4ea4a98ca56ef0ea3dea600eb480d219c0 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 14:57:23 +0200 Subject: [PATCH 03/10] fix: invite create unit test and debug --- docs/permissions.html | 9 --------- src/permissions/constants.js | 2 +- src/permissions/index.js | 1 + src/routes/projectMemberInvites/create.spec.js | 2 +- src/tests/util.js | 2 +- src/util.js | 2 ++ 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/docs/permissions.html b/docs/permissions.html index 93903a34..b827955d 100644 --- a/docs/permissions.html +++ b/docs/permissions.html @@ -681,15 +681,6 @@

Connect Admin administrator - Connect Manager - Connect Account Manager - Connect Copilot Manager - Business Development Representative - Presales - Account Executive - Program Manager - Solution Architect - Project Manager
diff --git a/src/permissions/constants.js b/src/permissions/constants.js index ce9aeeee..874ea45a 100644 --- a/src/permissions/constants.js +++ b/src/permissions/constants.js @@ -372,7 +372,7 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export group: 'Project Invite', description: 'Who can invite project members with "customer" role.', }, - topcoderRoles: TOPCODER_ROLES_MANAGERS_AND_ADMINS, + topcoderRoles: TOPCODER_ROLES_ADMINS, projectRoles: ALL, scopes: SCOPES_PROJECT_INVITES_WRITE, }, diff --git a/src/permissions/index.js b/src/permissions/index.js index 3a3f6f1a..a37fdb04 100644 --- a/src/permissions/index.js +++ b/src/permissions/index.js @@ -38,6 +38,7 @@ module.exports = () => { Authorizer.setPolicy('projectMemberInvite.create', generalPermission([ PERMISSION.CREATE_PROJECT_INVITE_CUSTOMER, PERMISSION.CREATE_PROJECT_INVITE_TOPCODER, + PERMISSION.CREATE_PROJECT_INVITE_COPILOT, ])); Authorizer.setPolicy('projectMemberInvite.view', generalPermission([ PERMISSION.READ_PROJECT_INVITE_OWN, diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 40a259eb..66544e8c 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -20,7 +20,7 @@ import { const should = chai.should(); -describe('Project Member Invite create', () => { +describe.only('Project Member Invite create', () => { let project1; let project2; beforeEach((done) => { diff --git a/src/tests/util.js b/src/tests/util.js index 4e50eb95..8e9158ad 100644 --- a/src/tests/util.js +++ b/src/tests/util.js @@ -29,7 +29,7 @@ export default { // userId = 40051334, roles: [ 'Manager', 'Topcoder User' ],handle: 'test1',email: 'test@topcoder.com' manager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzQiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.J5VtOEQVph5jfe2Ji-NH7txEDcx_5gthhFeD-MzX9ck', // userId = 40051337, roles: [ 'Connect Copilot Manager', 'Connect Manager', 'Topcoder User' ], handle: 'connect_copilot_manger', email: 'connect_copilot_manger@topcoder.com' - copilotManager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIiwiQ29ubmVjdCBDb3BpbG90IE1hbmFnZXIiXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXItZGV2LmNvbSIsImhhbmRsZSI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXIiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzM0IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXJAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.jamlfV2gDzPnCOiEIrkt0iWWkKW33KSGvfHoy02Iq_Y', + copilotManager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIiwiQ29ubmVjdCBDb3BpbG90IE1hbmFnZXIiXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXItZGV2LmNvbSIsImhhbmRsZSI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXIiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzM3IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXJAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.3ytaNOJ4w0mmj1v22-6Gjiw292iCvp59S9iq1Vpx6Os', // userId = 40051335, [ 'Topcoder User' ],handle: 'member2',email: 'test@topcoder.com' member2: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJtZW1iZXIyIiwiZXhwIjoyNTYzMDc2Njg5LCJ1c2VySWQiOiI0MDA1MTMzNSIsImlhdCI6MTQ2MzA3NjA4OSwiZW1haWwiOiJ0ZXN0QHRvcGNvZGVyLmNvbSIsImp0aSI6ImIzM2I3N2NkLWI1MmUtNDBmZS04MzdlLWJlYjhlMGFlNmE0YSJ9.Mh4bw3wm-cn5Kcf96gLFVlD0kySOqqk4xN3qnreAKL4', // userId = 40051336, [ 'Connect Admin' ], handle: 'connect_admin1', email: 'connect_admin1@topcoder.com' diff --git a/src/util.js b/src/util.js index 2ad0aa4a..38979868 100644 --- a/src/util.js +++ b/src/util.js @@ -1285,6 +1285,8 @@ const projectServiceUtils = { const allow = util.matchPermissionRule(allowRule, user, projectMembers); const deny = util.matchPermissionRule(denyRule, user, projectMembers); + console.log('hasPermission', JSON.stringify({ permission, user, projectMembers, allow, deny }, null, 2)); + return allow && !deny; }, From 3d56176f4968e1d1147ba2578417359e892001d4 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 15:17:14 +0200 Subject: [PATCH 04/10] fix: debug unit tests --- src/routes/projectMemberInvites/create.spec.js | 4 ++++ src/tests/util.js | 1 + 2 files changed, 5 insertions(+) diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 66544e8c..9b7a890f 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -767,6 +767,10 @@ describe.only('Project Member Invite create', () => { it('should return 201 if try to create copilot invite by "Connect Copilot Manager"', (done) => { util.getUserRoles.restore(); sandbox.stub(util, 'getUserRoles', () => Promise.resolve([USER_ROLE.COPILOT])); + console.log(JSON.stringify({ + userToken: testUtil.jwts.copilotManager, + user: testUtil.getDecodedToken(testUtil.jwts.copilotManager), + }, null, 2)); request(server) .post(`/v5/projects/${project1.id}/invites`) .set({ diff --git a/src/tests/util.js b/src/tests/util.js index 8e9158ad..35082a27 100644 --- a/src/tests/util.js +++ b/src/tests/util.js @@ -56,6 +56,7 @@ export default { manager: 40051334, member2: 40051335, connectAdmin: 40051336, + copilotManager: 40051337, romit: 40158431, }, getDecodedToken: token => jwt.decode(token), From f64e8fb2f88aff80cd965a6463c4d598137aa6cb Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 15:29:54 +0200 Subject: [PATCH 05/10] fix: more debug --- src/routes/projectMemberInvites/create.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 9b7a890f..874d2df5 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -767,7 +767,7 @@ describe.only('Project Member Invite create', () => { it('should return 201 if try to create copilot invite by "Connect Copilot Manager"', (done) => { util.getUserRoles.restore(); sandbox.stub(util, 'getUserRoles', () => Promise.resolve([USER_ROLE.COPILOT])); - console.log(JSON.stringify({ + console.log('AWS', JSON.stringify({ userToken: testUtil.jwts.copilotManager, user: testUtil.getDecodedToken(testUtil.jwts.copilotManager), }, null, 2)); From e8bc70fbc6fcfa79a41ceda868c9801b79a9a5ed Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 15:47:32 +0200 Subject: [PATCH 06/10] fix: more debug --- src/permissions/generalPermission.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/permissions/generalPermission.js b/src/permissions/generalPermission.js index bce44d24..e9dbcdf7 100644 --- a/src/permissions/generalPermission.js +++ b/src/permissions/generalPermission.js @@ -35,6 +35,7 @@ import models from '../models'; * @return {Function} which would be resolved if `req` is allowed and rejected otherwise */ module.exports = permissions => async (req) => { + console.log(JSON.stringify({ path: req.path, body: req.body }, null, 2)); const projectId = _.parseInt(req.params.projectId); // if one of the `permission` requires to know Project Members, but current route doesn't belong to any project From 37dfe47ec78e297130e451a4238bbcc5bf231ce5 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 16:04:15 +0200 Subject: [PATCH 07/10] fix: more debug --- src/permissions/generalPermission.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/permissions/generalPermission.js b/src/permissions/generalPermission.js index e9dbcdf7..cc1a2684 100644 --- a/src/permissions/generalPermission.js +++ b/src/permissions/generalPermission.js @@ -35,7 +35,7 @@ import models from '../models'; * @return {Function} which would be resolved if `req` is allowed and rejected otherwise */ module.exports = permissions => async (req) => { - console.log(JSON.stringify({ path: req.path, body: req.body }, null, 2)); + console.log(JSON.stringify({ path: req.path, body: req.body, permissions }, null, 2)); const projectId = _.parseInt(req.params.projectId); // if one of the `permission` requires to know Project Members, but current route doesn't belong to any project @@ -71,6 +71,8 @@ module.exports = permissions => async (req) => { ? _.some(permissions, permission => util.hasPermissionByReq(permission, req)) : util.hasPermissionByReq(permissions, req); + console.log('hasPermission', hasPermission); + if (!hasPermission) { throw new Error('You do not have permissions to perform this action'); } From c2214d429cd43905655f4b24fe235460b6402be2 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 16:12:24 +0200 Subject: [PATCH 08/10] fix: more debug --- src/routes/projectMemberInvites/create.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 874d2df5..13a35d1c 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -772,7 +772,7 @@ describe.only('Project Member Invite create', () => { user: testUtil.getDecodedToken(testUtil.jwts.copilotManager), }, null, 2)); request(server) - .post(`/v5/projects/${project1.id}/invites`) + .post(`/v5/projects/${project2.id}/invites`) .set({ Authorization: `Bearer ${testUtil.jwts.copilotManager}`, }) @@ -789,7 +789,7 @@ describe.only('Project Member Invite create', () => { const resJson = res.body.success[0]; should.exist(resJson); resJson.role.should.equal('copilot'); - resJson.projectId.should.equal(project1.id); + resJson.projectId.should.equal(project2.id); resJson.userId.should.equal(40051331); done(); } From 7524a0a0e3d8bc89915ca037bfd198749cc4f8f3 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 16:19:43 +0200 Subject: [PATCH 09/10] fix: Copilot Manager token for unit tests --- src/tests/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/util.js b/src/tests/util.js index 35082a27..a98e7b5c 100644 --- a/src/tests/util.js +++ b/src/tests/util.js @@ -29,7 +29,7 @@ export default { // userId = 40051334, roles: [ 'Manager', 'Topcoder User' ],handle: 'test1',email: 'test@topcoder.com' manager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzQiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.J5VtOEQVph5jfe2Ji-NH7txEDcx_5gthhFeD-MzX9ck', // userId = 40051337, roles: [ 'Connect Copilot Manager', 'Connect Manager', 'Topcoder User' ], handle: 'connect_copilot_manger', email: 'connect_copilot_manger@topcoder.com' - copilotManager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIiwiQ29ubmVjdCBDb3BpbG90IE1hbmFnZXIiXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXItZGV2LmNvbSIsImhhbmRsZSI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXIiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzM3IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXJAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.3ytaNOJ4w0mmj1v22-6Gjiw292iCvp59S9iq1Vpx6Os', + copilotManager: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBNYW5hZ2VyIiwiQ29ubmVjdCBDb3BpbG90IE1hbmFnZXIiXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXItZGV2LmNvbSIsImhhbmRsZSI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXIiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzM3IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6ImNvbm5lY3RfY29waWxvdF9tYW5nZXJAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.j9nTufEslU5CLXqkwHixC-nNdysJSCYQC9MhacOca64', // userId = 40051335, [ 'Topcoder User' ],handle: 'member2',email: 'test@topcoder.com' member2: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJtZW1iZXIyIiwiZXhwIjoyNTYzMDc2Njg5LCJ1c2VySWQiOiI0MDA1MTMzNSIsImlhdCI6MTQ2MzA3NjA4OSwiZW1haWwiOiJ0ZXN0QHRvcGNvZGVyLmNvbSIsImp0aSI6ImIzM2I3N2NkLWI1MmUtNDBmZS04MzdlLWJlYjhlMGFlNmE0YSJ9.Mh4bw3wm-cn5Kcf96gLFVlD0kySOqqk4xN3qnreAKL4', // userId = 40051336, [ 'Connect Admin' ], handle: 'connect_admin1', email: 'connect_admin1@topcoder.com' From 266f4ea2d223bd6d9f569c26740037041245b225 Mon Sep 17 00:00:00 2001 From: maxceem Date: Fri, 20 Nov 2020 16:24:24 +0200 Subject: [PATCH 10/10] fix: remove debugging --- src/permissions/generalPermission.js | 3 --- src/routes/projectMemberInvites/create.spec.js | 6 +----- src/util.js | 4 +--- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/permissions/generalPermission.js b/src/permissions/generalPermission.js index cc1a2684..bce44d24 100644 --- a/src/permissions/generalPermission.js +++ b/src/permissions/generalPermission.js @@ -35,7 +35,6 @@ import models from '../models'; * @return {Function} which would be resolved if `req` is allowed and rejected otherwise */ module.exports = permissions => async (req) => { - console.log(JSON.stringify({ path: req.path, body: req.body, permissions }, null, 2)); const projectId = _.parseInt(req.params.projectId); // if one of the `permission` requires to know Project Members, but current route doesn't belong to any project @@ -71,8 +70,6 @@ module.exports = permissions => async (req) => { ? _.some(permissions, permission => util.hasPermissionByReq(permission, req)) : util.hasPermissionByReq(permissions, req); - console.log('hasPermission', hasPermission); - if (!hasPermission) { throw new Error('You do not have permissions to perform this action'); } diff --git a/src/routes/projectMemberInvites/create.spec.js b/src/routes/projectMemberInvites/create.spec.js index 13a35d1c..49376e0c 100644 --- a/src/routes/projectMemberInvites/create.spec.js +++ b/src/routes/projectMemberInvites/create.spec.js @@ -20,7 +20,7 @@ import { const should = chai.should(); -describe.only('Project Member Invite create', () => { +describe('Project Member Invite create', () => { let project1; let project2; beforeEach((done) => { @@ -767,10 +767,6 @@ describe.only('Project Member Invite create', () => { it('should return 201 if try to create copilot invite by "Connect Copilot Manager"', (done) => { util.getUserRoles.restore(); sandbox.stub(util, 'getUserRoles', () => Promise.resolve([USER_ROLE.COPILOT])); - console.log('AWS', JSON.stringify({ - userToken: testUtil.jwts.copilotManager, - user: testUtil.getDecodedToken(testUtil.jwts.copilotManager), - }, null, 2)); request(server) .post(`/v5/projects/${project2.id}/invites`) .set({ diff --git a/src/util.js b/src/util.js index 38979868..1cdd8cfd 100644 --- a/src/util.js +++ b/src/util.js @@ -1277,15 +1277,13 @@ const projectServiceUtils = { return false; } - // console.log('hasPermission', permission, user); - const allowRule = permission.allowRule ? permission.allowRule : permission; const denyRule = permission.denyRule ? permission.denyRule : null; const allow = util.matchPermissionRule(allowRule, user, projectMembers); const deny = util.matchPermissionRule(denyRule, user, projectMembers); - console.log('hasPermission', JSON.stringify({ permission, user, projectMembers, allow, deny }, null, 2)); + // console.log('hasPermission', JSON.stringify({ permission, user, projectMembers, allow, deny }, null, 2)); return allow && !deny; },