From 050c2dd7a3716487a8837f7fd0c7d60816b53eec Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Tue, 5 Nov 2019 19:42:26 +0800 Subject: [PATCH 1/3] Merge pull request #382 from r0hit-gupta/issue-381-fix Fix for issue-381 --- src/routes/milestones/update.js | 10 ++++- src/routes/milestones/update.spec.js | 55 ++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/routes/milestones/update.js b/src/routes/milestones/update.js index 4b68e72d..fd72c263 100644 --- a/src/routes/milestones/update.js +++ b/src/routes/milestones/update.js @@ -10,7 +10,7 @@ import Sequelize from 'sequelize'; import { middleware as tcMiddleware } from 'tc-core-library-js'; import util from '../../util'; import validateTimeline from '../../middlewares/validateTimeline'; -import { EVENT, MILESTONE_STATUS } from '../../constants'; +import { EVENT, MILESTONE_STATUS, ADMIN_ROLES } from '../../constants'; import models from '../../models'; const permissions = tcMiddleware.permissions; @@ -185,6 +185,14 @@ module.exports = [ } } + if (entityToUpdate.completionDate || entityToUpdate.actualStartDate) { + if (!util.hasPermission({ topcoderRoles: ADMIN_ROLES }, req.authUser)) { + const apiErr = new Error('You are not authorised to perform this action'); + apiErr.status = 403; + return Promise.reject(apiErr); + } + } + if (entityToUpdate.completionDate && entityToUpdate.completionDate < milestone.startDate) { const apiErr = new Error('The milestone completionDate should be greater or equal than the startDate.'); apiErr.status = 422; diff --git a/src/routes/milestones/update.spec.js b/src/routes/milestones/update.spec.js index 382d2eab..253107a7 100644 --- a/src/routes/milestones/update.spec.js +++ b/src/routes/milestones/update.spec.js @@ -264,7 +264,6 @@ describe('UPDATE Milestone', () => { param: { name: 'Milestone 1-updated', duration: 3, - completionDate: '2018-05-16T00:00:00.000Z', description: 'description-updated', status: 'draft', type: 'type1-updated', @@ -302,6 +301,30 @@ describe('UPDATE Milestone', () => { .expect(403, done); }); + it('should return 403 for non-admin member updating the completionDate', (done) => { + const newBody = _.cloneDeep(body); + newBody.param.completionDate = '2019-01-16T00:00:00.000Z'; + request(server) + .patch('/v4/timelines/1/milestones/1') + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .send(newBody) + .expect(403, done); + }); + + it('should return 403 for non-admin member updating the actualStartDate', (done) => { + const newBody = _.cloneDeep(body); + newBody.param.actualStartDate = '2018-05-15T00:00:00.000Z'; + request(server) + .patch('/v4/timelines/1/milestones/1') + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .send(newBody) + .expect(403, done); + }); + it('should return 404 for non-existed timeline', (done) => { request(server) .patch('/v4/timelines/1234/milestones/1') @@ -490,12 +513,14 @@ describe('UPDATE Milestone', () => { }); it('should return 200 for admin', (done) => { + const newBody = _.cloneDeep(body); + newBody.param.completionDate = '2018-05-15T00:00:00.000Z'; request(server) .patch('/v4/timelines/1/milestones/1') .set({ Authorization: `Bearer ${testUtil.jwts.admin}`, }) - .send(body) + .send(newBody) .expect(200) .end((err, res) => { const resJson = res.body.result.content; @@ -503,7 +528,7 @@ describe('UPDATE Milestone', () => { resJson.name.should.be.eql(body.param.name); resJson.description.should.be.eql(body.param.description); resJson.duration.should.be.eql(body.param.duration); - resJson.completionDate.should.be.eql(body.param.completionDate); + resJson.completionDate.should.be.eql(newBody.param.completionDate); resJson.status.should.be.eql(body.param.status); resJson.type.should.be.eql(body.param.type); resJson.details.should.be.eql({ @@ -1061,6 +1086,30 @@ describe('UPDATE Milestone', () => { .end(done); }); + it('should return 200 for admin updating the completionDate', (done) => { + const newBody = _.cloneDeep(body); + newBody.param.completionDate = '2018-05-16T00:00:00.000Z'; + request(server) + .patch('/v4/timelines/1/milestones/1') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(newBody) + .expect(200, done); + }); + + it('should return 200 for admin updating the actualStartDate', (done) => { + const newBody = _.cloneDeep(body); + newBody.param.actualStartDate = '2018-05-15T00:00:00.000Z'; + request(server) + .patch('/v4/timelines/1/milestones/1') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(newBody) + .expect(200, done); + }); + it('should return 200 for connect manager', (done) => { request(server) .patch('/v4/timelines/1/milestones/1') From 6f0fa6898693e898b1cfbe802612799b6f13b89b Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Tue, 5 Nov 2019 19:42:53 +0800 Subject: [PATCH 2/3] fix: issues during updating milestone completionDate --- src/routes/milestones/update.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/routes/milestones/update.js b/src/routes/milestones/update.js index fd72c263..90e5b29a 100644 --- a/src/routes/milestones/update.js +++ b/src/routes/milestones/update.js @@ -193,8 +193,15 @@ module.exports = [ } } - if (entityToUpdate.completionDate && entityToUpdate.completionDate < milestone.startDate) { - const apiErr = new Error('The milestone completionDate should be greater or equal than the startDate.'); + if ( + entityToUpdate.completionDate && + (entityToUpdate.actualStartDate || milestone.actualStartDate) && + moment.utc(entityToUpdate.completionDate).isBefore( + moment.utc(entityToUpdate.actualStartDate || milestone.actualStartDate), + 'day', + ) + ) { + const apiErr = new Error('The milestone completionDate should be greater or equal to actualStartDate.'); apiErr.status = 422; return Promise.reject(apiErr); } @@ -216,7 +223,8 @@ module.exports = [ // if status has changed to be completed, set the compeltionDate if not provided if (entityToUpdate.status === MILESTONE_STATUS.COMPLETED) { entityToUpdate.completionDate = entityToUpdate.completionDate ? entityToUpdate.completionDate : today; - entityToUpdate.duration = entityToUpdate.completionDate.diff(entityToUpdate.actualStartDate, 'days') + 1; + entityToUpdate.duration = moment.utc(entityToUpdate.completionDate) + .diff(entityToUpdate.actualStartDate, 'days') + 1; } // if status has changed to be active, set the startDate to today if (entityToUpdate.status === MILESTONE_STATUS.ACTIVE) { @@ -241,7 +249,8 @@ module.exports = [ // if completionDate has changed if (!statusChanged && completionDateChanged) { - entityToUpdate.duration = entityToUpdate.completionDate.diff(entityToUpdate.actualStartDate, 'days') + 1; + entityToUpdate.duration = moment.utc(entityToUpdate.completionDate) + .diff(entityToUpdate.actualStartDate, 'days') + 1; entityToUpdate.status = MILESTONE_STATUS.COMPLETED; } From f585f9a338aec2f0331be221202b78317cb30434 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Thu, 7 Nov 2019 11:48:29 +0800 Subject: [PATCH 3/3] fix: "projectUpdatedKafkaHandler" unit test Project has been indexed in a wrong way for unit test. Also, we have to wait until the index is refreshed to make tests consistent. --- src/events/projects/index.spec.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/events/projects/index.spec.js b/src/events/projects/index.spec.js index 9067166e..0f524c17 100644 --- a/src/events/projects/index.spec.js +++ b/src/events/projects/index.spec.js @@ -111,9 +111,8 @@ describe('projectUpdatedKafkaHandler', () => { index: ES_PROJECT_INDEX, type: ES_PROJECT_TYPE, id: project.id, - body: { - doc: project.get({ plain: true }), - }, + body: project.get({ plain: true }), + refresh: 'wait_for', }); });