diff --git a/migrations/20180717_project_types_metadata.sql b/migrations/20180717_project_types_metadata.sql new file mode 100644 index 00000000..f856796f --- /dev/null +++ b/migrations/20180717_project_types_metadata.sql @@ -0,0 +1,13 @@ +-- +-- UPDATE EXISTING TABLES: +-- project_types +-- metadata column: added +-- + +-- +-- project_types +-- + +ALTER TABLE project_types ADD COLUMN "metadata" json; +UPDATE project_types set metadata='{}' where metadata is null; +ALTER TABLE project_types ALTER COLUMN "metadata" SET NOT NULL; diff --git a/src/models/projectType.js b/src/models/projectType.js index acd7b44b..19618698 100644 --- a/src/models/projectType.js +++ b/src/models/projectType.js @@ -10,6 +10,7 @@ module.exports = function definePhaseProduct(sequelize, DataTypes) { aliases: { type: DataTypes.JSON, allowNull: false }, disabled: { type: DataTypes.BOOLEAN, defaultValue: false }, hidden: { type: DataTypes.BOOLEAN, defaultValue: false }, + metadata: { type: DataTypes.JSON, allowNull: false }, deletedAt: { type: DataTypes.DATE, allowNull: true }, createdAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, diff --git a/src/routes/projectTypes/create.js b/src/routes/projectTypes/create.js index 6a4ea058..8e73e1ec 100644 --- a/src/routes/projectTypes/create.js +++ b/src/routes/projectTypes/create.js @@ -21,6 +21,7 @@ const schema = { aliases: Joi.array().required(), disabled: Joi.boolean().optional(), hidden: Joi.boolean().optional(), + metadata: Joi.object().required(), createdAt: Joi.any().strip(), updatedAt: Joi.any().strip(), deletedAt: Joi.any().strip(), diff --git a/src/routes/projectTypes/create.spec.js b/src/routes/projectTypes/create.spec.js index f690bd4d..d2e339bc 100644 --- a/src/routes/projectTypes/create.spec.js +++ b/src/routes/projectTypes/create.spec.js @@ -22,6 +22,7 @@ describe('CREATE project type', () => { aliases: ['key-1', 'key_1'], disabled: false, hidden: false, + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, createdBy: 1, updatedBy: 1, })).then(() => Promise.resolve()), @@ -39,6 +40,7 @@ describe('CREATE project type', () => { aliases: ['key-1', 'key_1'], disabled: true, hidden: true, + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, }, }; @@ -149,6 +151,20 @@ describe('CREATE project type', () => { .expect(422, done); }); + it('should return 422 for missing metadata', (done) => { + const invalidBody = _.cloneDeep(body); + delete invalidBody.param.metadata; + + request(server) + .post('/v4/projectTypes') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(invalidBody) + .expect('Content-Type', /json/) + .expect(422, done); + }); + it('should return 422 for duplicated key', (done) => { const invalidBody = _.cloneDeep(body); invalidBody.param.key = 'key1'; @@ -182,6 +198,7 @@ describe('CREATE project type', () => { resJson.aliases.should.be.eql(body.param.aliases); resJson.disabled.should.be.eql(body.param.disabled); resJson.hidden.should.be.eql(body.param.hidden); + resJson.metadata.should.be.eql(body.param.metadata); resJson.createdBy.should.be.eql(40051333); // admin should.exist(resJson.createdAt); @@ -213,6 +230,7 @@ describe('CREATE project type', () => { resJson.aliases.should.be.eql(body.param.aliases); resJson.disabled.should.be.eql(body.param.disabled); resJson.hidden.should.be.eql(body.param.hidden); + resJson.metadata.should.be.eql(body.param.metadata); resJson.createdBy.should.be.eql(40051336); // connect admin resJson.updatedBy.should.be.eql(40051336); // connect admin done(); diff --git a/src/routes/projectTypes/delete.spec.js b/src/routes/projectTypes/delete.spec.js index 053bfb1c..496a47a5 100644 --- a/src/routes/projectTypes/delete.spec.js +++ b/src/routes/projectTypes/delete.spec.js @@ -19,6 +19,7 @@ describe('DELETE project type', () => { question: 'question 1', info: 'info 1', aliases: ['key-1', 'key_1'], + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, createdBy: 1, updatedBy: 1, })).then(() => Promise.resolve()), diff --git a/src/routes/projectTypes/get.spec.js b/src/routes/projectTypes/get.spec.js index cf12bb88..eb72604f 100644 --- a/src/routes/projectTypes/get.spec.js +++ b/src/routes/projectTypes/get.spec.js @@ -20,6 +20,7 @@ describe('GET project type', () => { aliases: ['key-1', 'key_1'], disabled: true, hidden: true, + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, createdBy: 1, updatedBy: 1, }; @@ -71,6 +72,7 @@ describe('GET project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); should.exist(resJson.createdAt); resJson.updatedBy.should.be.eql(type.updatedBy); diff --git a/src/routes/projectTypes/list.spec.js b/src/routes/projectTypes/list.spec.js index 5128a760..991667b5 100644 --- a/src/routes/projectTypes/list.spec.js +++ b/src/routes/projectTypes/list.spec.js @@ -21,6 +21,7 @@ describe('LIST project types', () => { aliases: ['key-1', 'key_1'], disabled: true, hidden: true, + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, createdBy: 1, updatedBy: 1, }, @@ -33,6 +34,7 @@ describe('LIST project types', () => { aliases: ['key-2', 'key_2'], disabled: true, hidden: true, + metadata: { 'slack-notification-mappings': { color: '#b47dd6', label: 'Full App 2' } }, createdBy: 1, updatedBy: 1, }, @@ -67,6 +69,7 @@ describe('LIST project types', () => { resJson[0].createdBy.should.be.eql(type.createdBy); resJson[0].disabled.should.be.eql(type.disabled); resJson[0].hidden.should.be.eql(type.hidden); + resJson[0].metadata.should.be.eql(type.metadata); should.exist(resJson[0].createdAt); resJson[0].updatedBy.should.be.eql(type.updatedBy); should.exist(resJson[0].updatedAt); diff --git a/src/routes/projectTypes/update.js b/src/routes/projectTypes/update.js index 3946715e..9975f478 100644 --- a/src/routes/projectTypes/update.js +++ b/src/routes/projectTypes/update.js @@ -24,6 +24,7 @@ const schema = { aliases: Joi.array().optional(), disabled: Joi.boolean().optional(), hidden: Joi.boolean().optional(), + metadata: Joi.object().optional(), createdAt: Joi.any().strip(), updatedAt: Joi.any().strip(), deletedAt: Joi.any().strip(), diff --git a/src/routes/projectTypes/update.spec.js b/src/routes/projectTypes/update.spec.js index 5e809720..0402020c 100644 --- a/src/routes/projectTypes/update.spec.js +++ b/src/routes/projectTypes/update.spec.js @@ -21,6 +21,7 @@ describe('UPDATE project type', () => { aliases: ['key-1', 'key_1'], disabled: false, hidden: false, + metadata: { 'slack-notification-mappings': { color: '#96d957', label: 'Full App' } }, createdBy: 1, updatedBy: 1, }; @@ -42,6 +43,7 @@ describe('UPDATE project type', () => { aliases: ['key-1-updated', 'key_1_updated'], disabled: true, hidden: true, + metadata: { 'slack-notification-mappings': { color: '#b47dd6', label: 'Full App 2' } }, }, }; @@ -113,6 +115,7 @@ describe('UPDATE project type', () => { delete partialBody.param.aliases; delete partialBody.param.disabled; delete partialBody.param.hidden; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -130,6 +133,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin @@ -149,6 +153,7 @@ describe('UPDATE project type', () => { delete partialBody.param.aliases; delete partialBody.param.disabled; delete partialBody.param.hidden; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -166,6 +171,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin @@ -185,6 +191,7 @@ describe('UPDATE project type', () => { delete partialBody.param.aliases; delete partialBody.param.disabled; delete partialBody.param.hidden; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -202,6 +209,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin @@ -221,6 +229,7 @@ describe('UPDATE project type', () => { delete partialBody.param.aliases; delete partialBody.param.disabled; delete partialBody.param.hidden; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -238,6 +247,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin @@ -257,6 +267,7 @@ describe('UPDATE project type', () => { delete partialBody.param.displayName; delete partialBody.param.disabled; delete partialBody.param.hidden; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -274,6 +285,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(partialBody.param.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin @@ -293,6 +305,7 @@ describe('UPDATE project type', () => { delete partialBody.param.displayName; delete partialBody.param.aliases; delete partialBody.param.hidden; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -310,6 +323,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(partialBody.param.disabled); resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(type.metadata); resJson.createdBy.should.be.eql(type.createdBy); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin @@ -329,6 +343,7 @@ describe('UPDATE project type', () => { delete partialBody.param.displayName; delete partialBody.param.disabled; delete partialBody.param.aliases; + delete partialBody.param.metadata; request(server) .patch(`/v4/projectTypes/${key}`) .set({ @@ -346,6 +361,44 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(type.aliases); resJson.disabled.should.be.eql(type.disabled); resJson.hidden.should.be.eql(partialBody.param.hidden); + resJson.metadata.should.be.eql(type.metadata); + resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt + resJson.updatedBy.should.be.eql(40051333); // admin + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + + it('should return 200 for admin metadata updated', (done) => { + const partialBody = _.cloneDeep(body); + delete partialBody.param.icon; + delete partialBody.param.info; + delete partialBody.param.question; + delete partialBody.param.displayName; + delete partialBody.param.disabled; + delete partialBody.param.aliases; + delete partialBody.param.hidden; + request(server) + .patch(`/v4/projectTypes/${key}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(partialBody) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.key.should.be.eql(key); + resJson.displayName.should.be.eql(type.displayName); + resJson.icon.should.be.eql(type.icon); + resJson.info.should.be.eql(type.info); + resJson.question.should.be.eql(type.question); + resJson.aliases.should.be.eql(type.aliases); + resJson.disabled.should.be.eql(type.disabled); + resJson.hidden.should.be.eql(type.hidden); + resJson.metadata.should.be.eql(partialBody.param.metadata); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin should.exist(resJson.updatedAt); @@ -374,6 +427,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(body.param.aliases); resJson.disabled.should.be.eql(body.param.disabled); resJson.hidden.should.be.eql(body.param.hidden); + resJson.metadata.should.be.eql(body.param.metadata); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051333); // admin should.exist(resJson.updatedAt); @@ -402,6 +456,7 @@ describe('UPDATE project type', () => { resJson.aliases.should.be.eql(body.param.aliases); resJson.disabled.should.be.eql(body.param.disabled); resJson.hidden.should.be.eql(body.param.hidden); + resJson.metadata.should.be.eql(body.param.metadata); resJson.createdBy.should.be.eql(type.createdBy); // should not update createdAt resJson.updatedBy.should.be.eql(40051336); // connect admin done(); diff --git a/src/routes/projects/create.spec.js b/src/routes/projects/create.spec.js index 9de4e1df..5f12ab42 100644 --- a/src/routes/projects/create.spec.js +++ b/src/routes/projects/create.spec.js @@ -26,6 +26,7 @@ describe('Project create', () => { question: 'question 1', info: 'info 1', aliases: ['key-1', 'key_1'], + metadata: {}, createdBy: 1, updatedBy: 1, }, diff --git a/src/routes/projects/update.spec.js b/src/routes/projects/update.spec.js index 8492d883..42abf4f0 100644 --- a/src/routes/projects/update.spec.js +++ b/src/routes/projects/update.spec.js @@ -30,6 +30,7 @@ describe('Project', () => { aliases: ['key-1', 'key_1'], createdBy: 1, updatedBy: 1, + metadata: {}, }, ])) .then(() => done());