Skip to content

Commit c5c36a5

Browse files
committed
More fixes based on feedback.
1 parent c6abfb2 commit c5c36a5

File tree

22 files changed

+1023
-129
lines changed

22 files changed

+1023
-129
lines changed

config/custom-environment-variables.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,16 @@
5353
"inviteEmailSubject": "INVITE_EMAIL_SUBJECT",
5454
"inviteEmailSectionTitle": "INVITE_EMAIL_SECTION_TITLE",
5555
"pageSize": "PAGE_SIZE",
56-
"SSO_REFCODES": "SSO_REFCODES"
56+
"SSO_REFCODES": "SSO_REFCODES",
57+
"lookerConfig": {
58+
"BASE_URL": "LOOKER_API_BASE_URL",
59+
"CLIENT_ID": "LOOKER_API_CLIENT_ID",
60+
"CLIENT_SECRET": "LOOKER_API_CLIENT_SECRET",
61+
"TOKEN": "TOKEN",
62+
"USE_MOCK": "LOOKER_API_ENABLE_MOCK",
63+
"QUERIES": {
64+
"REG_STATS": "LOOKER_API_REG_STATS_QUERY_ID",
65+
"BUDGET": "LOOKER_API_BUDGET_QUERY_ID"
66+
}
67+
}
5768
}

config/default.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,16 @@
5858
"UNIQUE_GMAIL_VALIDATION": false,
5959
"pageSize": 20,
6060
"VALID_STATUSES_BEFORE_PAUSED": "[\"active\"]",
61-
"SSO_REFCODES": "[]"
61+
"SSO_REFCODES": "[]",
62+
"lookerConfig": {
63+
"BASE_URL": "",
64+
"CLIENT_ID": "",
65+
"CLIENT_SECRET": "",
66+
"TOKEN": "TOKEN",
67+
"USE_MOCK": "true",
68+
"QUERIES": {
69+
"REG_STATS": 1234,
70+
"BUDGET": 123
71+
}
72+
}
6273
}

local/seed/seedProjects.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import util from '../../src/tests/util';
2+
import models from '../../src/models';
23

34
const axios = require('axios');
45
const Promise = require('bluebird');

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"scripts": {
1010
"lint": "./node_modules/.bin/eslint .",
1111
"lint:fix": "./node_modules/.bin/eslint . --fix || true",
12-
"build": "babel src -d dist --presets es2015",
12+
"build": "babel src -d dist --presets es2015 --copy-files",
1313
"sync:db": "./node_modules/.bin/babel-node migrations/sync.js",
1414
"sync:es": "./node_modules/.bin/babel-node migrations/elasticsearch_sync.js",
1515
"migrate:es": "./node_modules/.bin/babel-node migrations/seedElasticsearchIndex.js",
@@ -75,7 +75,7 @@
7575
"babel-plugin-add-module-exports": "^0.2.1",
7676
"babel-plugin-transform-runtime": "^6.23.0",
7777
"babel-preset-es2015": "^6.9.0",
78-
"bunyan": "^1.8.1",
78+
"bunyan": "^1.8.12",
7979
"chai": "^3.5.0",
8080
"chai-as-promised": "^7.1.1",
8181
"eslint": "^3.16.1",

src/models/projectPhase.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ module.exports = function defineProjectPhase(sequelize, DataTypes) {
44
const ProjectPhase = sequelize.define('ProjectPhase', {
55
id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true },
66
name: { type: DataTypes.STRING, allowNull: true },
7+
description: { type: DataTypes.STRING, allowNull: true },
8+
requirements: { type: DataTypes.STRING, allowNull: true },
79
status: { type: DataTypes.STRING, allowNull: true },
810
startDate: { type: DataTypes.DATE, allowNull: true },
911
endDate: { type: DataTypes.DATE, allowNull: true },

src/routes/form/version/getVersion.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ module.exports = [
4646
.then((data) => {
4747
if (data.length === 0) {
4848
req.log.debug('No form found in ES');
49-
models.Form.findOneWithLatestRevision(req.params)
49+
return models.Form.findOneWithLatestRevision(req.params)
5050
.then((form) => {
5151
// Not found
5252
if (!form) {
@@ -58,10 +58,10 @@ module.exports = [
5858
return Promise.resolve();
5959
})
6060
.catch(next);
61-
} else {
62-
req.log.debug('forms found in ES');
63-
res.json(data[0].inner_hits.forms.hits.hits[0]._source); // eslint-disable-line no-underscore-dangle
6461
}
62+
req.log.debug('forms found in ES');
63+
res.json(data[0].inner_hits.forms.hits.hits[0]._source); // eslint-disable-line no-underscore-dangle
64+
return Promise.resolve();
6565
})
6666
.catch(next);
6767
},

src/routes/metadata/list.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const forms = [
112112
{
113113
key: 'productKey 1',
114114
config: {
115-
questions: [{
115+
sections: [{
116116
id: 'appDefinition',
117117
title: 'Sample Project',
118118
required: true,

src/routes/milestones/create.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ module.exports = [
5858
});
5959
let result;
6060

61-
// Validate startDate and endDate to be within the timeline startDate and endDate
61+
// Validate startDate is not earlier than timeline startDate
6262
let error;
6363
if (req.body.startDate < req.timeline.startDate) {
6464
error = 'Milestone startDate must not be before the timeline startDate';

src/routes/milestones/create.spec.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ describe('CREATE milestone', () => {
142142
// Create milestones
143143
models.Milestone.bulkCreate([
144144
{
145+
id: 11,
145146
timelineId: 1,
146147
name: 'milestone 1',
147148
duration: 2,
@@ -164,6 +165,7 @@ describe('CREATE milestone', () => {
164165
updatedBy: 2,
165166
},
166167
{
168+
id: 12,
167169
timelineId: 1,
168170
name: 'milestone 2',
169171
duration: 3,
@@ -179,6 +181,7 @@ describe('CREATE milestone', () => {
179181
updatedBy: 3,
180182
},
181183
{
184+
id: 13,
182185
timelineId: 1,
183186
name: 'milestone 3',
184187
duration: 4,
@@ -424,18 +427,27 @@ describe('CREATE milestone', () => {
424427
should.not.exist(resJson.deletedBy);
425428
should.not.exist(resJson.deletedAt);
426429

430+
// validate statusHistory
431+
should.exist(resJson.statusHistory);
432+
resJson.statusHistory.should.be.an('array');
433+
resJson.statusHistory.length.should.be.eql(1);
434+
resJson.statusHistory.forEach((statusHistory) => {
435+
statusHistory.reference.should.be.eql('milestone');
436+
statusHistory.referenceId.should.be.eql(resJson.id);
437+
});
438+
427439
// eslint-disable-next-line no-unused-expressions
428440
server.services.pubsub.publish.calledWith(EVENT.ROUTING_KEY.MILESTONE_ADDED).should.be.true;
429441

430442
// Verify 'order' of the other milestones
431443
models.Milestone.findAll({ where: { timelineId: 1 } })
432444
.then((milestones) => {
433445
_.each(milestones, (milestone) => {
434-
if (milestone.id === 1) {
446+
if (milestone.id === 11) {
435447
milestone.order.should.be.eql(1);
436-
} else if (milestone.id === 2) {
448+
} else if (milestone.id === 12) {
437449
milestone.order.should.be.eql(2 + 1);
438-
} else if (milestone.id === 3) {
450+
} else if (milestone.id === 13) {
439451
milestone.order.should.be.eql(3 + 1);
440452
}
441453
});

src/routes/milestones/delete.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ describe('DELETE milestone', () => {
162162
// Create milestones
163163
models.Milestone.bulkCreate([
164164
{
165+
id: 1,
165166
timelineId: 1,
166167
name: 'milestone 1',
167168
duration: 2,
@@ -184,6 +185,7 @@ describe('DELETE milestone', () => {
184185
updatedBy: 2,
185186
},
186187
{
188+
id: 2,
187189
timelineId: 1,
188190
name: 'milestone 2',
189191
duration: 3,
@@ -199,6 +201,7 @@ describe('DELETE milestone', () => {
199201
updatedBy: 3,
200202
},
201203
{
204+
id: 3,
202205
timelineId: 1,
203206
name: 'milestone 3',
204207
duration: 4,

src/routes/milestones/get.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ describe('GET milestone', () => {
133133
// Create milestones
134134
models.Milestone.bulkCreate([
135135
{
136+
id: 1,
136137
timelineId: 1,
137138
name: 'milestone 1',
138139
duration: 2,
@@ -155,6 +156,7 @@ describe('GET milestone', () => {
155156
updatedBy: 2,
156157
},
157158
{
159+
id: 2,
158160
timelineId: 1,
159161
name: 'milestone 2',
160162
duration: 3,
@@ -170,6 +172,7 @@ describe('GET milestone', () => {
170172
updatedBy: 3,
171173
},
172174
{
175+
id: 3,
173176
timelineId: 1,
174177
name: 'milestone 3',
175178
duration: 4,

src/routes/milestones/update.spec.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ describe('UPDATE Milestone', () => {
265265
const body = {
266266
name: 'Milestone 1-updated',
267267
duration: 3,
268-
completionDate: '2018-05-16T00:00:00.000Z',
269268
description: 'description-updated',
270269
status: 'draft',
271270
type: 'type1-updated',
@@ -512,20 +511,22 @@ describe('UPDATE Milestone', () => {
512511
});
513512

514513
it('should return 200 for admin', (done) => {
514+
const newBody = _.cloneDeep(body);
515+
newBody.completionDate = '2018-05-15T00:00:00.000Z';
515516
request(server)
516517
.patch('/v5/timelines/1/milestones/1')
517518
.set({
518519
Authorization: `Bearer ${testUtil.jwts.admin}`,
519520
})
520-
.send(body)
521+
.send(newBody)
521522
.expect(200)
522523
.end((err, res) => {
523524
const resJson = res.body;
524525
should.exist(resJson.id);
525526
resJson.name.should.be.eql(body.name);
526527
resJson.description.should.be.eql(body.description);
527528
resJson.duration.should.be.eql(body.duration);
528-
resJson.completionDate.should.be.eql(body.completionDate);
529+
resJson.completionDate.should.be.eql(newBody.completionDate);
529530
resJson.status.should.be.eql(body.status);
530531
resJson.type.should.be.eql(body.type);
531532
resJson.details.should.be.eql({
@@ -546,6 +547,15 @@ describe('UPDATE Milestone', () => {
546547
should.not.exist(resJson.deletedBy);
547548
should.not.exist(resJson.deletedAt);
548549

550+
// validate statusHistory
551+
should.exist(resJson.statusHistory);
552+
resJson.statusHistory.should.be.an('array');
553+
resJson.statusHistory.length.should.be.eql(2);
554+
resJson.statusHistory.forEach((statusHistory) => {
555+
statusHistory.reference.should.be.eql('milestone');
556+
statusHistory.referenceId.should.be.eql(resJson.id);
557+
});
558+
549559
// eslint-disable-next-line no-unused-expressions
550560
server.services.pubsub.publish.calledWith(EVENT.ROUTING_KEY.MILESTONE_UPDATED).should.be.true;
551561

@@ -1098,36 +1108,36 @@ describe('UPDATE Milestone', () => {
10981108
.expect(200, done);
10991109
});
11001110

1101-
it('should return 403 for connect manager when entity to update has completionDate', (done) => {
1111+
it('should return 200 for connect manager', (done) => {
11021112
request(server)
11031113
.patch('/v5/timelines/1/milestones/1')
11041114
.set({
11051115
Authorization: `Bearer ${testUtil.jwts.manager}`,
11061116
})
11071117
.send(body)
1108-
.expect(403)
1118+
.expect(200)
11091119
.end(done);
11101120
});
11111121

1112-
it('should return 403 for copilot when entity to update has completionDate', (done) => {
1122+
it('should return 200 for copilot', (done) => {
11131123
request(server)
11141124
.patch('/v5/timelines/1/milestones/1')
11151125
.set({
11161126
Authorization: `Bearer ${testUtil.jwts.copilot}`,
11171127
})
11181128
.send(body)
1119-
.expect(403)
1129+
.expect(200)
11201130
.end(done);
11211131
});
11221132

1123-
it('should return 403 for member when entity to update has completionDate', (done) => {
1133+
it('should return 200 for member', (done) => {
11241134
request(server)
11251135
.patch('/v5/timelines/1/milestones/1')
11261136
.set({
11271137
Authorization: `Bearer ${testUtil.jwts.member}`,
11281138
})
11291139
.send(body)
1130-
.expect(403)
1140+
.expect(200)
11311141
.end(done);
11321142
});
11331143

src/routes/phaseProducts/create.spec.js

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ describe('Phase Products', () => {
177177
request(server)
178178
.post(`/v5/projects/99999/phases/${phaseId}/products`)
179179
.set({
180-
Authorization: `Bearer ${testUtil.jwts.admin}`,
180+
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
181181
})
182182
.send(body)
183183
.expect('Content-Type', /json/)
@@ -199,7 +199,7 @@ describe('Phase Products', () => {
199199
request(server)
200200
.post(`/v5/projects/${projectId}/phases/${phaseId}/products`)
201201
.set({
202-
Authorization: `Bearer ${testUtil.jwts.copilot}`,
202+
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
203203
})
204204
.send(body)
205205
.expect('Content-Type', /json/)
@@ -220,6 +220,68 @@ describe('Phase Products', () => {
220220
});
221221
});
222222

223+
it('should return 201 if requested by admin', (done) => {
224+
request(server)
225+
.post(`/v5/projects/${projectId}/phases/${phaseId}/products`)
226+
.set({
227+
Authorization: `Bearer ${testUtil.jwts.connectAdmin}`,
228+
})
229+
.send(body)
230+
.expect('Content-Type', /json/)
231+
.expect(201)
232+
.end(done);
233+
});
234+
235+
it('should return 201 if requested by manager which is a member', (done) => {
236+
models.ProjectMember.create({
237+
id: 3,
238+
userId: testUtil.userIds.manager,
239+
projectId,
240+
role: 'manager',
241+
isPrimary: false,
242+
createdBy: 1,
243+
updatedBy: 1,
244+
}).then(() => {
245+
request(server)
246+
.post(`/v5/projects/${projectId}/phases/${phaseId}/products`)
247+
.set({
248+
Authorization: `Bearer ${testUtil.jwts.manager}`,
249+
})
250+
.send(body)
251+
.expect('Content-Type', /json/)
252+
.expect(201)
253+
.end(done);
254+
});
255+
});
256+
257+
it('should return 403 if requested by manager which is not a member', (done) => {
258+
request(server)
259+
.post(`/v5/projects/${projectId}/phases/${phaseId}/products`)
260+
.set({
261+
Authorization: `Bearer ${testUtil.jwts.manager}`,
262+
})
263+
.send(body)
264+
.expect('Content-Type', /json/)
265+
.expect(403)
266+
.end(done);
267+
});
268+
269+
it('should return 403 if requested by non-member copilot', (done) => {
270+
models.ProjectMember.destroy({
271+
where: { userId: testUtil.userIds.copilot, projectId },
272+
}).then(() => {
273+
request(server)
274+
.post(`/v5/projects/${projectId}/phases/${phaseId}/products`)
275+
.set({
276+
Authorization: `Bearer ${testUtil.jwts.copilot}`,
277+
})
278+
.send(body)
279+
.expect('Content-Type', /json/)
280+
.expect(403)
281+
.end(done);
282+
});
283+
});
284+
223285
describe('Bus api', () => {
224286
let createEventSpy;
225287
const sandbox = sinon.sandbox.create();

0 commit comments

Comments
 (0)