Skip to content
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ export const USER_ROLE = {
TOPCODER_ADMIN: 'administrator',
MANAGER: 'Connect Manager',
COPILOT: 'Connect Copilot',
CONNECT_ADMIN: 'Connect Admin',
};

export const ADMIN_ROLES = [USER_ROLE.CONNECT_ADMIN, USER_ROLE.TOPCODER_ADMIN];


export const EVENT = {
ROUTING_KEY: {
Expand Down
4 changes: 2 additions & 2 deletions src/permissions/project.delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import _ from 'lodash';
import util from '../util';
import models from '../models';
import { USER_ROLE, PROJECT_MEMBER_ROLE } from '../constants';
import { PROJECT_MEMBER_ROLE } from '../constants';

/**
* Super admin, Topcoder Managers are allowed to edit any project
Expand All @@ -20,7 +20,7 @@ module.exports = freq => new Promise((resolve, reject) => {
req.context = req.context || {};
req.context.currentProjectMembers = members;
// check if auth user has acecss to this project
const hasAccess = util.hasRole(req, USER_ROLE.TOPCODER_ADMIN) ||
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)));
Expand Down
2 changes: 1 addition & 1 deletion src/permissions/project.edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = freq => new Promise((resolve, reject) => {
req.context = req.context || {};
req.context.currentProjectMembers = members;
// check if auth user has acecss to this project
const hasAccess = util.hasRole(req, USER_ROLE.TOPCODER_ADMIN)
const hasAccess = util.hasAdminRole(req)
|| util.hasRole(req, USER_ROLE.MANAGER)
|| !_.isUndefined(_.find(members, m => m.userId === req.authUser.userId));

Expand Down
2 changes: 1 addition & 1 deletion src/permissions/project.view.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = freq => new Promise((resolve, reject) => {
req.context = req.context || {};
req.context.currentProjectMembers = members;
// check if auth user has acecss to this project
const hasAccess = util.hasRole(req, USER_ROLE.TOPCODER_ADMIN)
const hasAccess = util.hasAdminRole(req)
|| util.hasRole(req, USER_ROLE.MANAGER)
|| !_.isUndefined(_.find(members, m => m.userId === currentUserId));

Expand Down
3 changes: 1 addition & 2 deletions src/permissions/projectMember.delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import _ from 'lodash';
import util from '../util';
import models from '../models';
import {
USER_ROLE,
PROJECT_MEMBER_ROLE,
} from '../constants';

Expand All @@ -25,7 +24,7 @@ module.exports = freq => new Promise((resolve, reject) => {
const prjMemberId = _.parseInt(req.params.id);
const memberToBeRemoved = _.find(members, m => m.id === prjMemberId);
// check if auth user has acecss to this project
const hasAccess = util.hasRole(req, USER_ROLE.TOPCODER_ADMIN)
const hasAccess = util.hasAdminRole(req)
|| (authMember && memberToBeRemoved && (authMember.role === PROJECT_MEMBER_ROLE.MANAGER ||
(authMember.role === PROJECT_MEMBER_ROLE.CUSTOMER && authMember.isPrimary &&
memberToBeRemoved.role === PROJECT_MEMBER_ROLE.CUSTOMER) ||
Expand Down
2 changes: 1 addition & 1 deletion src/routes/projectMembers/update.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ describe('Project members update', () => {
resJson.isPrimary.should.be.false;
resJson.updatedBy.should.equal(40051332);
deleteSpy.should.have.been.calledOnce;
server.services.pubsub.publish.calledWith('project.member.removed').should.be.true;
server.services.pubsub.publish.calledWith('project.member.updated').should.be.true;
done();
}
});
Expand Down
4 changes: 3 additions & 1 deletion src/routes/projects/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ module.exports = [
*/
(req, res, next) => {
const project = req.body.param;
const userRole = util.hasRole(req, USER_ROLE.MANAGER)
// by default connect admin and managers joins projects as manager
const userRole = util.hasRoles(req, [USER_ROLE.CONNECT_ADMIN, USER_ROLE.MANAGER])
? PROJECT_MEMBER_ROLE.MANAGER
: PROJECT_MEMBER_ROLE.CUSTOMER;
// set defaults
Expand Down Expand Up @@ -136,6 +137,7 @@ module.exports = [
req.log.error(err);
return Promise.resolve();
});
// return Promise.resolve();
})

.then(() => {
Expand Down
34 changes: 34 additions & 0 deletions src/routes/projects/delete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,39 @@ describe('Project delete test', () => {
}
});
});

it('should return 204, for connect admin, if project was successfully removed', (done) => {
request(server)
.delete(`/v4/projects/${project1.id}`)
.set({
Authorization: `Bearer ${testUtil.jwts.admin}`,
})
.expect(204)
.end((err) => {
if (err) {
done(err);
} else {
server.services.pubsub.publish.calledWith('project.deleted').should.be.true;
done();
}
});
});

it('should return 204, for connect admin, if project was successfully removed', (done) => {
request(server)
.delete(`/v4/projects/${project1.id}`)
.set({
Authorization: `Bearer ${testUtil.jwts.admin}`,
})
.expect(204)
.end((err) => {
if (err) {
done(err);
} else {
server.services.pubsub.publish.calledWith('project.deleted').should.be.true;
done();
}
});
});
});
});
21 changes: 20 additions & 1 deletion src/routes/projects/get.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,25 @@ describe('GET Project', () => {
});
});

it('should return the project for connect admin ', (done) => {
request(server)
.get(`/v4/projects/${project1.id}`)
.set({
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
})
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
} else {
const resJson = res.body.result.content;
should.exist(resJson);
done();
}
});
});

it('should return attachment with downloadUrl', (done) => {
models.ProjectAttachment.create({
projectId: project1.id,
Expand Down Expand Up @@ -172,6 +191,7 @@ describe('GET Project', () => {
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
stub.restore();
if (err) {
done(err);
} else {
Expand All @@ -181,7 +201,6 @@ describe('GET Project', () => {
resJson.attachments.should.have.lengthOf(1);
resJson.attachments[0].filePath.should.equal(attachment.filePath);
resJson.attachments[0].downloadUrl.should.exist;
stub.restore();
done();
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/routes/projects/list-db.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ module.exports = [
req.log.debug(criteria);

if (!memberOnly
&& (util.hasRole(req, USER_ROLE.TOPCODER_ADMIN)
&& (util.hasAdminRole(req)
|| util.hasRole(req, USER_ROLE.MANAGER))) {
// admins & topcoder managers can see all projects
return retrieveProjects(req, criteria, sort, req.query.fields)
Expand Down
104 changes: 104 additions & 0 deletions src/routes/projects/list-db.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,109 @@ describe('LIST Project db', () => {
}
});
});

describe('for connect admin ', () => {
it('should return the project ', (done) => {
request(server)
.get('/v4/projects/db/?fields=id%2Cmembers.id')
.set({
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
})
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
} else {
const resJson = res.body.result.content;
should.exist(resJson);
resJson.should.have.lengthOf(3);
done();
}
});
});

it('should return all projects that match when filtering by name', (done) => {
request(server)
.get('/v4/projects/db/?filter=keyword%3Dtest')
.set({
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
})
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
} else {
const resJson = res.body.result.content;
should.exist(resJson);
resJson.should.have.lengthOf(3);
done();
}
});
});

it('should return the project when filtering by keyword, which matches the name', (done) => {
request(server)
.get('/v4/projects/db/?filter=keyword%3D1')
.set({
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
})
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
} else {
const resJson = res.body.result.content;
should.exist(resJson);
resJson.should.have.lengthOf(1);
resJson[0].name.should.equal('test1');
done();
}
});
});

it('should return the project when filtering by keyword, which matches the description', (done) => {
request(server)
.get('/v4/projects/db/?filter=keyword%3Dproject')
.set({
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
})
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
} else {
const resJson = res.body.result.content;
should.exist(resJson);
resJson.should.have.lengthOf(3);
done();
}
});
});

it('should return the project when filtering by keyword, which matches the details', (done) => {
request(server)
.get('/v4/projects/db/?filter=keyword%3Dcode')
.set({
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
})
.expect('Content-Type', /json/)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
} else {
const resJson = res.body.result.content;
should.exist(resJson);
resJson.should.have.lengthOf(1);
resJson[0].name.should.equal('test1');
done();
}
});
});
});
});
});
4 changes: 2 additions & 2 deletions src/routes/projects/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ module.exports = [
limit: Math.min(req.query.limit || 20, 20),
offset: req.query.offset || 0,
};
req.log.debug(criteria);
req.log.info(criteria);

if (!memberOnly
&& (util.hasRole(req, USER_ROLE.TOPCODER_ADMIN)
&& (util.hasAdminRole(req)
|| util.hasRole(req, USER_ROLE.MANAGER))) {
// admins & topcoder managers can see all projects
return retrieveProjects(req, criteria, sort, req.query.fields)
Expand Down
Loading