Skip to content

Commit a8567db

Browse files
committed
Merge branch 'develop' into connect-performance-testing
2 parents 7d71274 + ca831c0 commit a8567db

File tree

7 files changed

+54
-99
lines changed

7 files changed

+54
-99
lines changed

docs/permissions.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,37 @@ <h2 class="anchor-container">
259259
</div>
260260
</div>
261261
</div>
262+
<div class="row border-top">
263+
<div class="col py-2">
264+
<div class="permission-title anchor-container">
265+
<a href="#UPDATE_PROJECT_STATUS" name="UPDATE_PROJECT_STATUS" class="anchor"></a>Update Project Status
266+
</div>
267+
<div class="permission-variable"><small><code>UPDATE_PROJECT_STATUS</code></small></div>
268+
<div class="text-black-50 small-text"></div>
269+
</div>
270+
<div class="col-9 py-2">
271+
<div>
272+
<span class="badge badge-primary" title="Allowed Project Role">manager</span>
273+
<span class="badge badge-primary" title="Allowed Project Role">account_manager</span>
274+
<span class="badge badge-primary" title="Allowed Project Role">program_manager</span>
275+
<span class="badge badge-primary" title="Allowed Project Role">account_executive</span>
276+
<span class="badge badge-primary" title="Allowed Project Role">solution_architect</span>
277+
<span class="badge badge-primary" title="Allowed Project Role">project_manager</span>
278+
<span class="badge badge-primary" title="Allowed Project Role">copilot</span>
279+
</div>
280+
281+
<div>
282+
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
283+
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
284+
</div>
285+
286+
<div>
287+
<span class="badge badge-dark" title="Allowed Topcoder Role">all:connect_project</span>
288+
<span class="badge badge-dark" title="Allowed Topcoder Role">all:projects</span>
289+
<span class="badge badge-dark" title="Allowed Topcoder Role">write:projects</span>
290+
</div>
291+
</div>
292+
</div>
262293
<div class="row border-top">
263294
<div class="col py-2">
264295
<div class="permission-title anchor-container">

src/events/projects/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ async function projectCreatedKafkaHandler(app, topic, payload) {
187187
await Promise.all(topicPromises);
188188
app.logger.debug('Topics for phases are successfully created.');
189189
}
190-
if (project.type === 'talent-as-a-service') {
190+
// TODO: temporary disable this feature, until we release TaaS APP
191+
if (false === true && project.type === 'talent-as-a-service') {
191192
const specialists = _.get(project, 'details.taasDefinition.specialists');
192193
if (!specialists || !specialists.length) {
193194
app.logger.debug(`no specialists found in the project ${project.id}`);

src/permissions/constants.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,19 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export
195195
scopes: SCOPES_PROJECTS_WRITE,
196196
},
197197

198+
UPDATE_PROJECT_STATUS: {
199+
meta: {
200+
title: 'Update Project Status',
201+
group: 'Project',
202+
},
203+
topcoderRoles: TOPCODER_ROLES_ADMINS,
204+
projectRoles: [
205+
...PROJECT_ROLES_MANAGEMENT,
206+
PROJECT_MEMBER_ROLE.COPILOT,
207+
],
208+
scopes: SCOPES_PROJECTS_WRITE,
209+
},
210+
198211
MANAGE_PROJECT_DIRECT_PROJECT_ID: {
199212
meta: {
200213
title: 'Manage Project property "directProjectId"',

src/routes/milestones/commonHelper.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ async function createMilestone(authUser, timeline, data, transaction) {
2323
// eslint-disable-next-line
2424
const userId = authUser.userId;
2525
const entity = Object.assign({}, data, { createdBy: userId, updatedBy: userId, timelineId: timeline.id });
26-
if (entity.startDate < timeline.startDate) {
27-
const apiErr = new Error('Milestone startDate must not be before the timeline startDate');
28-
apiErr.status = 400;
29-
throw apiErr;
30-
}
3126
// Circumvent postgresql duplicate key error, see https://stackoverflow.com/questions/50834623/sequelizejs-error-duplicate-key-value-violates-unique-constraint-message-pkey
3227
await models.sequelize.query('SELECT setval(\'milestones_id_seq\', (SELECT MAX(id) FROM "milestones"))',
3328
{ raw: true, transaction });
@@ -55,7 +50,7 @@ async function deleteMilestone(authUser, timelineId, id, transaction, item) {
5550
}
5651
await milestone.update({ deletedBy: authUser.userId }, { transaction });
5752
await milestone.destroy({ transaction });
58-
return { id };
53+
return { id, timelineId };
5954
}
6055

6156
/**
@@ -123,7 +118,6 @@ async function updateMilestone(authUser, timelineId, data, transaction, item) {
123118
const isUpdatedActualStartDate = milestone.actualStartDate && entityToUpdate.actualStartDate
124119
&& !moment(milestone.actualStartDate).isSame(entityToUpdate.actualStartDate);
125120

126-
127121
if (
128122
(isUpdatedCompletionDate || isUpdatedActualStartDate)
129123
&& !util.hasPermission({ topcoderRoles: ADMIN_ROLES }, authUser)

src/routes/milestones/create.spec.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -344,21 +344,6 @@ describe('CREATE milestone', () => {
344344
.expect(400, done);
345345
});
346346

347-
it('should return 400 if startDate is before the timeline startDate', (done) => {
348-
const invalidBody = _.assign({}, body, {
349-
startDate: '2018-05-01T00:00:00.000Z',
350-
});
351-
352-
request(server)
353-
.post('/v5/timelines/1/milestones')
354-
.set({
355-
Authorization: `Bearer ${testUtil.jwts.admin}`,
356-
})
357-
.send(invalidBody)
358-
.expect('Content-Type', /json/)
359-
.expect(400, done);
360-
});
361-
362347
it('should return 400 if invalid timelineId param', (done) => {
363348
request(server)
364349
.post('/v5/timelines/0/milestones')

src/routes/projects/update.js

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
import models from '../../models';
88
import {
99
PROJECT_STATUS,
10-
PROJECT_MEMBER_ROLE,
1110
EVENT,
1211
RESOURCES,
1312
REGEX,
@@ -224,23 +223,14 @@ module.exports = [
224223
});
225224
return Promise.reject(err);
226225
}
227-
// Only project manager (user with manager role assigned) or topcoder
228-
// admin should be allowed to transition project status to 'active'.
229-
const members = req.context.currentProjectMembers;
230-
const validRoles = [
231-
PROJECT_MEMBER_ROLE.MANAGER,
232-
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
233-
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,
234-
PROJECT_MEMBER_ROLE.SOLUTION_ARCHITECT,
235-
].map(x => x.toLowerCase());
236-
const matchRole = role => _.indexOf(validRoles, role.toLowerCase()) >= 0;
237-
if (updatedProps.status === PROJECT_STATUS.ACTIVE &&
238-
!util.hasAdminRole(req) &&
239-
_.isUndefined(_.find(members,
240-
m => m.userId === req.authUser.userId && matchRole(m.role)))
226+
227+
// check if user has permissions to update project status
228+
if (
229+
updatedProps.status &&
230+
updatedProps.status !== project.status &&
231+
!util.hasPermissionByReq(PERMISSION.UPDATE_PROJECT_STATUS, req)
241232
) {
242-
const err = new Error('Only assigned topcoder-managers or topcoder admins should be allowed ' +
243-
'to launch a project');
233+
const err = new Error('You are not allowed to update project status.');
244234
err.status = 403;
245235
return Promise.reject(err);
246236
}

src/routes/projects/update.spec.js

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -148,28 +148,6 @@ describe('Project', () => {
148148
});
149149
});
150150

151-
it('should return 403 if invalid user will update a project', (done) => {
152-
request(server)
153-
.patch(`/v5/projects/${project1.id}`)
154-
.set({
155-
Authorization: `Bearer ${testUtil.jwts.copilot}`,
156-
})
157-
.send({
158-
status: 'active',
159-
})
160-
.expect('Content-Type', /json/)
161-
.expect(403)
162-
.end((err, res) => {
163-
if (err) {
164-
done(err);
165-
} else {
166-
res.body.message.should.equal('Only assigned topcoder-managers or topcoder admins' +
167-
' should be allowed to launch a project');
168-
done();
169-
}
170-
});
171-
});
172-
173151
it('should return 200 if topcoder manager user will update a project', (done) => {
174152
request(server)
175153
.patch(`/v5/projects/${project1.id}`)
@@ -495,43 +473,6 @@ describe('Project', () => {
495473
});
496474
});
497475

498-
it('should return 403, copilot is not allowed to transition project out of cancel status', (done) => {
499-
models.Project.update({
500-
status: PROJECT_STATUS.CANCELLED,
501-
}, {
502-
where: {
503-
id: project1.id,
504-
},
505-
})
506-
.then(() => {
507-
const mbody = {
508-
name: 'updatedProject name',
509-
status: PROJECT_STATUS.ACTIVE,
510-
511-
};
512-
request(server)
513-
.patch(`/v5/projects/${project1.id}`)
514-
.set({
515-
Authorization: `Bearer ${testUtil.jwts.copilot}`,
516-
})
517-
.send(mbody)
518-
.expect('Content-Type', /json/)
519-
.expect(403)
520-
.end((err, res) => {
521-
if (err) {
522-
done(err);
523-
} else {
524-
res
525-
.body
526-
.message
527-
.should
528-
.equal('Only assigned topcoder-managers or topcoder admins should be allowed to launch a project');
529-
done();
530-
}
531-
});
532-
});
533-
});
534-
535476
it('should return 200 and project history should not be updated', (done) => {
536477
request(server)
537478
.patch(`/v5/projects/${project1.id}`)

0 commit comments

Comments
 (0)