Skip to content

Commit d70a183

Browse files
author
vikasrohit
authored
Merge pull request #407 from topcoder-platform/hotfix/milestone-completion-date
[PROD] Hotfix /milestone completion date
2 parents eecab0d + f585f9a commit d70a183

File tree

3 files changed

+76
-11
lines changed

3 files changed

+76
-11
lines changed

src/events/projects/index.spec.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,8 @@ describe('projectUpdatedKafkaHandler', () => {
111111
index: ES_PROJECT_INDEX,
112112
type: ES_PROJECT_TYPE,
113113
id: project.id,
114-
body: {
115-
doc: project.get({ plain: true }),
116-
},
114+
body: project.get({ plain: true }),
115+
refresh: 'wait_for',
117116
});
118117
});
119118

src/routes/milestones/update.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Sequelize from 'sequelize';
1010
import { middleware as tcMiddleware } from 'tc-core-library-js';
1111
import util from '../../util';
1212
import validateTimeline from '../../middlewares/validateTimeline';
13-
import { EVENT, MILESTONE_STATUS } from '../../constants';
13+
import { EVENT, MILESTONE_STATUS, ADMIN_ROLES } from '../../constants';
1414
import models from '../../models';
1515

1616
const permissions = tcMiddleware.permissions;
@@ -185,8 +185,23 @@ module.exports = [
185185
}
186186
}
187187

188-
if (entityToUpdate.completionDate && entityToUpdate.completionDate < milestone.startDate) {
189-
const apiErr = new Error('The milestone completionDate should be greater or equal than the startDate.');
188+
if (entityToUpdate.completionDate || entityToUpdate.actualStartDate) {
189+
if (!util.hasPermission({ topcoderRoles: ADMIN_ROLES }, req.authUser)) {
190+
const apiErr = new Error('You are not authorised to perform this action');
191+
apiErr.status = 403;
192+
return Promise.reject(apiErr);
193+
}
194+
}
195+
196+
if (
197+
entityToUpdate.completionDate &&
198+
(entityToUpdate.actualStartDate || milestone.actualStartDate) &&
199+
moment.utc(entityToUpdate.completionDate).isBefore(
200+
moment.utc(entityToUpdate.actualStartDate || milestone.actualStartDate),
201+
'day',
202+
)
203+
) {
204+
const apiErr = new Error('The milestone completionDate should be greater or equal to actualStartDate.');
190205
apiErr.status = 422;
191206
return Promise.reject(apiErr);
192207
}
@@ -208,7 +223,8 @@ module.exports = [
208223
// if status has changed to be completed, set the compeltionDate if not provided
209224
if (entityToUpdate.status === MILESTONE_STATUS.COMPLETED) {
210225
entityToUpdate.completionDate = entityToUpdate.completionDate ? entityToUpdate.completionDate : today;
211-
entityToUpdate.duration = entityToUpdate.completionDate.diff(entityToUpdate.actualStartDate, 'days') + 1;
226+
entityToUpdate.duration = moment.utc(entityToUpdate.completionDate)
227+
.diff(entityToUpdate.actualStartDate, 'days') + 1;
212228
}
213229
// if status has changed to be active, set the startDate to today
214230
if (entityToUpdate.status === MILESTONE_STATUS.ACTIVE) {
@@ -233,7 +249,8 @@ module.exports = [
233249

234250
// if completionDate has changed
235251
if (!statusChanged && completionDateChanged) {
236-
entityToUpdate.duration = entityToUpdate.completionDate.diff(entityToUpdate.actualStartDate, 'days') + 1;
252+
entityToUpdate.duration = moment.utc(entityToUpdate.completionDate)
253+
.diff(entityToUpdate.actualStartDate, 'days') + 1;
237254
entityToUpdate.status = MILESTONE_STATUS.COMPLETED;
238255
}
239256

src/routes/milestones/update.spec.js

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ describe('UPDATE Milestone', () => {
264264
param: {
265265
name: 'Milestone 1-updated',
266266
duration: 3,
267-
completionDate: '2018-05-16T00:00:00.000Z',
268267
description: 'description-updated',
269268
status: 'draft',
270269
type: 'type1-updated',
@@ -302,6 +301,30 @@ describe('UPDATE Milestone', () => {
302301
.expect(403, done);
303302
});
304303

304+
it('should return 403 for non-admin member updating the completionDate', (done) => {
305+
const newBody = _.cloneDeep(body);
306+
newBody.param.completionDate = '2019-01-16T00:00:00.000Z';
307+
request(server)
308+
.patch('/v4/timelines/1/milestones/1')
309+
.set({
310+
Authorization: `Bearer ${testUtil.jwts.manager}`,
311+
})
312+
.send(newBody)
313+
.expect(403, done);
314+
});
315+
316+
it('should return 403 for non-admin member updating the actualStartDate', (done) => {
317+
const newBody = _.cloneDeep(body);
318+
newBody.param.actualStartDate = '2018-05-15T00:00:00.000Z';
319+
request(server)
320+
.patch('/v4/timelines/1/milestones/1')
321+
.set({
322+
Authorization: `Bearer ${testUtil.jwts.manager}`,
323+
})
324+
.send(newBody)
325+
.expect(403, done);
326+
});
327+
305328
it('should return 404 for non-existed timeline', (done) => {
306329
request(server)
307330
.patch('/v4/timelines/1234/milestones/1')
@@ -490,20 +513,22 @@ describe('UPDATE Milestone', () => {
490513
});
491514

492515
it('should return 200 for admin', (done) => {
516+
const newBody = _.cloneDeep(body);
517+
newBody.param.completionDate = '2018-05-15T00:00:00.000Z';
493518
request(server)
494519
.patch('/v4/timelines/1/milestones/1')
495520
.set({
496521
Authorization: `Bearer ${testUtil.jwts.admin}`,
497522
})
498-
.send(body)
523+
.send(newBody)
499524
.expect(200)
500525
.end((err, res) => {
501526
const resJson = res.body.result.content;
502527
should.exist(resJson.id);
503528
resJson.name.should.be.eql(body.param.name);
504529
resJson.description.should.be.eql(body.param.description);
505530
resJson.duration.should.be.eql(body.param.duration);
506-
resJson.completionDate.should.be.eql(body.param.completionDate);
531+
resJson.completionDate.should.be.eql(newBody.param.completionDate);
507532
resJson.status.should.be.eql(body.param.status);
508533
resJson.type.should.be.eql(body.param.type);
509534
resJson.details.should.be.eql({
@@ -1061,6 +1086,30 @@ describe('UPDATE Milestone', () => {
10611086
.end(done);
10621087
});
10631088

1089+
it('should return 200 for admin updating the completionDate', (done) => {
1090+
const newBody = _.cloneDeep(body);
1091+
newBody.param.completionDate = '2018-05-16T00:00:00.000Z';
1092+
request(server)
1093+
.patch('/v4/timelines/1/milestones/1')
1094+
.set({
1095+
Authorization: `Bearer ${testUtil.jwts.admin}`,
1096+
})
1097+
.send(newBody)
1098+
.expect(200, done);
1099+
});
1100+
1101+
it('should return 200 for admin updating the actualStartDate', (done) => {
1102+
const newBody = _.cloneDeep(body);
1103+
newBody.param.actualStartDate = '2018-05-15T00:00:00.000Z';
1104+
request(server)
1105+
.patch('/v4/timelines/1/milestones/1')
1106+
.set({
1107+
Authorization: `Bearer ${testUtil.jwts.admin}`,
1108+
})
1109+
.send(newBody)
1110+
.expect(200, done);
1111+
});
1112+
10641113
it('should return 200 for connect manager', (done) => {
10651114
request(server)
10661115
.patch('/v4/timelines/1/milestones/1')

0 commit comments

Comments
 (0)