From c5eae1618bed54e777bad169361d4c55e73d7b06 Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Thu, 15 Feb 2018 01:46:31 +0300 Subject: [PATCH 1/7] Add channels.setCustomFields and groups.setCustomFields Signed-off-by: Eugene Bolshakov --- packages/rocketchat-api/server/v1/channels.js | 18 ++++++++++++++++++ packages/rocketchat-api/server/v1/groups.js | 18 ++++++++++++++++++ .../rocketchat-channel-settings/package.js | 1 + .../server/functions/saveRoomCustomFields.js | 13 +++++++++++++ .../server/methods/saveRoomSettings.js | 7 ++++++- packages/rocketchat-lib/server/models/Rooms.js | 12 ++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js diff --git a/packages/rocketchat-api/server/v1/channels.js b/packages/rocketchat-api/server/v1/channels.js index 3c150d14ccd4..ce10c80ad4da 100644 --- a/packages/rocketchat-api/server/v1/channels.js +++ b/packages/rocketchat-api/server/v1/channels.js @@ -636,6 +636,24 @@ RocketChat.API.v1.addRoute('channels.rename', { authRequired: true }, { } }); +RocketChat.API.v1.addRoute('channels.setCustomFields', { authRequired: true }, { + post() { + if (!this.bodyParams.customFields || !(typeof this.bodyParams.customFields === 'object')) { + return RocketChat.API.v1.failure('The bodyParam "customFields" is required with a type like object.'); + } + + const findResult = findChannelByIdOrName({ params: this.requestParams() }); + + Meteor.runAsUser(this.userId, () => { + Meteor.call('saveRoomSettings', findResult._id, 'roomCustomFields', this.bodyParams.customFields); + }); + + return RocketChat.API.v1.success({ + channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }) + }); + } +}); + RocketChat.API.v1.addRoute('channels.setDescription', { authRequired: true }, { post() { if (!this.bodyParams.description || !this.bodyParams.description.trim()) { diff --git a/packages/rocketchat-api/server/v1/groups.js b/packages/rocketchat-api/server/v1/groups.js index ccc7790978c5..c8932734e1ba 100644 --- a/packages/rocketchat-api/server/v1/groups.js +++ b/packages/rocketchat-api/server/v1/groups.js @@ -527,6 +527,24 @@ RocketChat.API.v1.addRoute('groups.rename', { authRequired: true }, { } }); +RocketChat.API.v1.addRoute('groups.setCustomFields', { authRequired: true }, { + post() { + if (!this.bodyParams.customFields || !(typeof this.bodyParams.customFields === 'object')) { + return RocketChat.API.v1.failure('The bodyParam "customFields" is required with a type like object.'); + } + + const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId }); + + Meteor.runAsUser(this.userId, () => { + Meteor.call('saveRoomSettings', findResult.rid, 'roomCustomFields', this.bodyParams.customFields); + }); + + return RocketChat.API.v1.success({ + group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }) + }); + } +}); + RocketChat.API.v1.addRoute('groups.setDescription', { authRequired: true }, { post() { if (!this.bodyParams.description || !this.bodyParams.description.trim()) { diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 3f35a159bb40..68a96d705921 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -28,6 +28,7 @@ Package.onUse(function(api) { 'server/functions/saveReactWhenReadOnly.js', 'server/functions/saveRoomType.js', 'server/functions/saveRoomTopic.js', + 'server/functions/saveRoomCustomFields.js', 'server/functions/saveRoomAnnouncement.js', 'server/functions/saveRoomName.js', 'server/functions/saveRoomReadOnly.js', diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js b/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js new file mode 100644 index 000000000000..7bff6b5bc062 --- /dev/null +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js @@ -0,0 +1,13 @@ +RocketChat.saveRoomCustomFields = function(rid, roomCustomFields, user) { + if (!Match.test(rid, String)) { + throw new Meteor.Error('invalid-room', 'Invalid room', { + 'function': 'RocketChat.saveRoomCustomFields' + }); + } + if (!Match.test(roomCustomFields, Object)) { + throw new Meteor.Error('invalid-roomCustomFields-type', 'Invalid roomCustomFields type', { + 'function': 'RocketChat.saveRoomCustomFields' + }); + } + return RocketChat.models.Rooms.setCustomFieldsById(rid, roomCustomFields); +}; diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js index 5ccdced2aaa3..91f460bfc3cb 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js @@ -1,4 +1,4 @@ -const fields = ['roomName', 'roomTopic', 'roomAnnouncement', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode', 'tokenpass', 'streamingOptions']; +const fields = ['roomName', 'roomTopic', 'roomAnnouncement', 'roomCustomFields', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode', 'tokenpass', 'streamingOptions']; Meteor.methods({ saveRoomSettings(rid, settings, value) { if (!Meteor.userId()) { @@ -79,6 +79,11 @@ Meteor.methods({ RocketChat.saveRoomAnnouncement(rid, value, user); } break; + case 'roomCustomFields': + if (value !== room.customFields) { + RocketChat.saveRoomCustomFields(rid, value, user); + } + break; case 'roomDescription': if (value !== room.description) { RocketChat.saveRoomDescription(rid, value, user); diff --git a/packages/rocketchat-lib/server/models/Rooms.js b/packages/rocketchat-lib/server/models/Rooms.js index 1d7273febd1c..fdfa74c261b7 100644 --- a/packages/rocketchat-lib/server/models/Rooms.js +++ b/packages/rocketchat-lib/server/models/Rooms.js @@ -682,6 +682,18 @@ class ModelRooms extends RocketChat.models._Base { return this.update(query, update); } + setCustomFieldsById(_id, customFields) { + const query = {_id}; + + const update = { + $set: { + customFields + } + }; + + return this.update(query, update); + } + muteUsernameByRoomId(_id, username) { const query = {_id}; From 423b75b30c6a0a89294cba1f0e0933c34f88831b Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Thu, 15 Feb 2018 22:48:25 +0300 Subject: [PATCH 2/7] Delete unused `user` parameter Signed-off-by: Eugene Bolshakov --- .../server/functions/saveRoomCustomFields.js | 2 +- .../server/methods/saveRoomSettings.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js b/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js index 7bff6b5bc062..9e8fd6a2a990 100644 --- a/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js @@ -1,4 +1,4 @@ -RocketChat.saveRoomCustomFields = function(rid, roomCustomFields, user) { +RocketChat.saveRoomCustomFields = function(rid, roomCustomFields) { if (!Match.test(rid, String)) { throw new Meteor.Error('invalid-room', 'Invalid room', { 'function': 'RocketChat.saveRoomCustomFields' diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js index 91f460bfc3cb..7ef3a5af6fe0 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.js @@ -81,7 +81,7 @@ Meteor.methods({ break; case 'roomCustomFields': if (value !== room.customFields) { - RocketChat.saveRoomCustomFields(rid, value, user); + RocketChat.saveRoomCustomFields(rid, value); } break; case 'roomDescription': From ad145a7a30163b0fd6389dff4a44eb7141679253 Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Mon, 19 Feb 2018 01:20:54 +0300 Subject: [PATCH 3/7] Add tests for channels.setCustomFields and groups.setCustomFields Signed-off-by: Eugene Bolshakov --- tests/end-to-end/api/02-channels.js | 183 ++++++++++++++++++++++++++++ tests/end-to-end/api/03-groups.js | 182 +++++++++++++++++++++++++++ 2 files changed, 365 insertions(+) diff --git a/tests/end-to-end/api/02-channels.js b/tests/end-to-end/api/02-channels.js index 784263e7b8ce..9891a6a5f04f 100644 --- a/tests/end-to-end/api/02-channels.js +++ b/tests/end-to-end/api/02-channels.js @@ -435,6 +435,189 @@ describe('[Channels]', function() { .end(done); }); + + describe('/channels.setCustomFields:', () => { + let cfchannel; + it('create channel with customFields', (done) => { + const customFields = {'field0':'value0'}; + request.post(api('channels.create')) + .set(credentials) + .send({ + name: `channel.cf.${ Date.now() }`, + customFields + }) + .end((err, res) => { + cfchannel = res.body.channel; + done(); + }); + }); + it('get customFields using channels.info', (done) => { + request.get(api('channels.info')) + .set(credentials) + .query({ + roomId: cfchannel._id + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel.customFields.field0', 'value0'); + }) + .end(done); + }); + it('change customFields', async(done) => { + const customFields = {'field9':'value9'}; + request.post(api('channels.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel._id'); + expect(res.body).to.have.nested.property('channel.name', cfchannel.name); + expect(res.body).to.have.nested.property('channel.t', 'c'); + expect(res.body).to.have.nested.property('channel.customFields.field9', 'value9'); + expect(res.body).to.have.not.nested.property('channel.customFields.field0', 'value0'); + }) + .end(done); + }); + it('get customFields using channels.info', (done) => { + request.get(api('channels.info')) + .set(credentials) + .query({ + roomId: cfchannel._id + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel.customFields.field9', 'value9'); + }) + .end(done); + }); + it('delete channels with customFields', (done) => { + request.post(api('channels.delete')) + .set(credentials) + .send({ + roomName: cfchannel.name + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + it('create channel without customFields', (done) => { + request.post(api('channels.create')) + .set(credentials) + .send({ + name: `channel.cf.${ Date.now() }` + }) + .end((err, res) => { + cfchannel = res.body.channel; + done(); + }); + }); + it('set customFields with one nested field', async(done) => { + const customFields = {'field1':'value1'}; + request.post(api('channels.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel._id'); + expect(res.body).to.have.nested.property('channel.name', cfchannel.name); + expect(res.body).to.have.nested.property('channel.t', 'c'); + expect(res.body).to.have.nested.property('channel.customFields.field1', 'value1'); + }) + .end(done); + }); + it('set customFields with multiple nested fields', async(done) => { + const customFields = {'field2':'value2','field3':'value3','field4':'value4'}; + + request.post(api('channels.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel._id'); + expect(res.body).to.have.nested.property('channel.name', cfchannel.name); + expect(res.body).to.have.nested.property('channel.t', 'c'); + expect(res.body).to.have.nested.property('channel.customFields.field2', 'value2'); + expect(res.body).to.have.nested.property('channel.customFields.field3', 'value3'); + expect(res.body).to.have.nested.property('channel.customFields.field4', 'value4'); + expect(res.body).to.have.not.nested.property('channel.customFields.field1', 'value1'); + }) + .end(done); + }); + it('set customFields to empty object', async(done) => { + const customFields = {}; + + request.post(api('channels.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel._id'); + expect(res.body).to.have.nested.property('channel.name', cfchannel.name); + expect(res.body).to.have.nested.property('channel.t', 'c'); + expect(res.body).to.have.not.nested.property('channel.customFields.field2', 'value2'); + expect(res.body).to.have.not.nested.property('channel.customFields.field3', 'value3'); + expect(res.body).to.have.not.nested.property('channel.customFields.field4', 'value4'); + }) + .end(done); + }); + it('set customFields as a string -> should return 400', async(done) => { + const customFields = ''; + + request.post(api('channels.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + it('delete channel with empty customFields', (done) => { + request.post(api('channels.delete')) + .set(credentials) + .send({ + roomName: cfchannel.name + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); + it('/channels.setJoinCode', async(done) => { const roomInfo = await getRoomInfo(channel._id); diff --git a/tests/end-to-end/api/03-groups.js b/tests/end-to-end/api/03-groups.js index 8ce141a0ac32..7e0d240fcbd0 100644 --- a/tests/end-to-end/api/03-groups.js +++ b/tests/end-to-end/api/03-groups.js @@ -424,6 +424,188 @@ describe('groups', function() { .end(done); }); + describe('/groups.setCustomFields:', () => { + let cfchannel; + it('create group with customFields', (done) => { + const customFields = {'field0':'value0'}; + request.post(api('groups.create')) + .set(credentials) + .send({ + name: `channel.cf.${ Date.now() }`, + customFields + }) + .end((err, res) => { + cfchannel = res.body.group; + done(); + }); + }); + it('get customFields using groups.info', (done) => { + request.get(api('groups.info')) + .set(credentials) + .query({ + roomId: cfchannel._id + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group.customFields.field0', 'value0'); + }) + .end(done); + }); + it('change customFields', async(done) => { + const customFields = {'field9':'value9'}; + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); + expect(res.body).to.have.not.nested.property('group.customFields.field0', 'value0'); + }) + .end(done); + }); + it('get customFields using groups.info', (done) => { + request.get(api('groups.info')) + .set(credentials) + .query({ + roomId: cfchannel._id + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); + }) + .end(done); + }); + it('delete group with customFields', (done) => { + request.post(api('groups.delete')) + .set(credentials) + .send({ + roomName: cfchannel.name + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + it('create group without customFields', (done) => { + request.post(api('groups.create')) + .set(credentials) + .send({ + name: `channel.cf.${ Date.now() }` + }) + .end((err, res) => { + cfchannel = res.body.group; + done(); + }); + }); + it('set customFields with one nested field', async(done) => { + const customFields = {'field1':'value1'}; + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field1', 'value1'); + }) + .end(done); + }); + it('set customFields with multiple nested fields', async(done) => { + const customFields = {'field2':'value2','field3':'value3','field4':'value4'}; + + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field2', 'value2'); + expect(res.body).to.have.nested.property('group.customFields.field3', 'value3'); + expect(res.body).to.have.nested.property('group.customFields.field4', 'value4'); + expect(res.body).to.have.not.nested.property('group.customFields.field1', 'value1'); + }) + .end(done); + }); + it('set customFields to empty object', async(done) => { + const customFields = {}; + + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.not.nested.property('group.customFields.field2', 'value2'); + expect(res.body).to.have.not.nested.property('group.customFields.field3', 'value3'); + expect(res.body).to.have.not.nested.property('group.customFields.field4', 'value4'); + }) + .end(done); + }); + it('set customFields as a string -> should return 400', async(done) => { + const customFields = ''; + + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + it('delete group with empty customFields', (done) => { + request.post(api('groups.delete')) + .set(credentials) + .send({ + roomName: cfchannel.name + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); + describe('/groups.delete', () => { let testGroup; it('/groups.create', (done) => { From 4bd15364ba1d8602fafd419d2e3ea34206f696af Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Mon, 19 Feb 2018 01:30:03 +0300 Subject: [PATCH 4/7] Fix lint Signed-off-by: Eugene Bolshakov --- tests/end-to-end/api/02-channels.js | 2 +- tests/end-to-end/api/03-groups.js | 200 ++++++++++++++-------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/tests/end-to-end/api/02-channels.js b/tests/end-to-end/api/02-channels.js index 9891a6a5f04f..0300f31b3fda 100644 --- a/tests/end-to-end/api/02-channels.js +++ b/tests/end-to-end/api/02-channels.js @@ -543,7 +543,7 @@ describe('[Channels]', function() { .end(done); }); it('set customFields with multiple nested fields', async(done) => { - const customFields = {'field2':'value2','field3':'value3','field4':'value4'}; + const customFields = {'field2':'value2', 'field3':'value3', 'field4':'value4'}; request.post(api('channels.setCustomFields')) .set(credentials) diff --git a/tests/end-to-end/api/03-groups.js b/tests/end-to-end/api/03-groups.js index 7e0d240fcbd0..250fb7726f74 100644 --- a/tests/end-to-end/api/03-groups.js +++ b/tests/end-to-end/api/03-groups.js @@ -453,106 +453,106 @@ describe('groups', function() { }) .end(done); }); - it('change customFields', async(done) => { - const customFields = {'field9':'value9'}; - request.post(api('groups.setCustomFields')) - .set(credentials) - .send({ - roomId: cfchannel._id, - customFields - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group._id'); - expect(res.body).to.have.nested.property('group.name', cfchannel.name); - expect(res.body).to.have.nested.property('group.t', 'p'); - expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); - expect(res.body).to.have.not.nested.property('group.customFields.field0', 'value0'); - }) - .end(done); - }); - it('get customFields using groups.info', (done) => { - request.get(api('groups.info')) - .set(credentials) - .query({ - roomId: cfchannel._id - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); - }) - .end(done); - }); - it('delete group with customFields', (done) => { - request.post(api('groups.delete')) - .set(credentials) - .send({ - roomName: cfchannel.name - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - }) - .end(done); - }); - it('create group without customFields', (done) => { - request.post(api('groups.create')) - .set(credentials) - .send({ - name: `channel.cf.${ Date.now() }` - }) - .end((err, res) => { - cfchannel = res.body.group; - done(); - }); - }); - it('set customFields with one nested field', async(done) => { - const customFields = {'field1':'value1'}; - request.post(api('groups.setCustomFields')) - .set(credentials) - .send({ - roomId: cfchannel._id, - customFields - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group._id'); - expect(res.body).to.have.nested.property('group.name', cfchannel.name); - expect(res.body).to.have.nested.property('group.t', 'p'); - expect(res.body).to.have.nested.property('group.customFields.field1', 'value1'); - }) - .end(done); - }); - it('set customFields with multiple nested fields', async(done) => { - const customFields = {'field2':'value2','field3':'value3','field4':'value4'}; - - request.post(api('groups.setCustomFields')) - .set(credentials) - .send({ - roomName: cfchannel.name, - customFields - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group._id'); - expect(res.body).to.have.nested.property('group.name', cfchannel.name); - expect(res.body).to.have.nested.property('group.t', 'p'); - expect(res.body).to.have.nested.property('group.customFields.field2', 'value2'); - expect(res.body).to.have.nested.property('group.customFields.field3', 'value3'); - expect(res.body).to.have.nested.property('group.customFields.field4', 'value4'); - expect(res.body).to.have.not.nested.property('group.customFields.field1', 'value1'); - }) - .end(done); - }); + it('change customFields', async(done) => { + const customFields = {'field9':'value9'}; + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); + expect(res.body).to.have.not.nested.property('group.customFields.field0', 'value0'); + }) + .end(done); + }); + it('get customFields using groups.info', (done) => { + request.get(api('groups.info')) + .set(credentials) + .query({ + roomId: cfchannel._id + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); + }) + .end(done); + }); + it('delete group with customFields', (done) => { + request.post(api('groups.delete')) + .set(credentials) + .send({ + roomName: cfchannel.name + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + it('create group without customFields', (done) => { + request.post(api('groups.create')) + .set(credentials) + .send({ + name: `channel.cf.${ Date.now() }` + }) + .end((err, res) => { + cfchannel = res.body.group; + done(); + }); + }); + it('set customFields with one nested field', async(done) => { + const customFields = {'field1':'value1'}; + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field1', 'value1'); + }) + .end(done); + }); + it('set customFields with multiple nested fields', async(done) => { + const customFields = {'field2':'value2', 'field3':'value3', 'field4':'value4'}; + + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field2', 'value2'); + expect(res.body).to.have.nested.property('group.customFields.field3', 'value3'); + expect(res.body).to.have.nested.property('group.customFields.field4', 'value4'); + expect(res.body).to.have.not.nested.property('group.customFields.field1', 'value1'); + }) + .end(done); + }); it('set customFields to empty object', async(done) => { const customFields = {}; From f83c84dfafb3509ba4fe4d000df5ba2307b66641 Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Mon, 19 Feb 2018 01:34:55 +0300 Subject: [PATCH 5/7] Fix lint Signed-off-by: Eugene Bolshakov --- tests/end-to-end/api/03-groups.js | 198 +++++++++++++++--------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/tests/end-to-end/api/03-groups.js b/tests/end-to-end/api/03-groups.js index 250fb7726f74..534689471738 100644 --- a/tests/end-to-end/api/03-groups.js +++ b/tests/end-to-end/api/03-groups.js @@ -453,106 +453,106 @@ describe('groups', function() { }) .end(done); }); - it('change customFields', async(done) => { - const customFields = {'field9':'value9'}; - request.post(api('groups.setCustomFields')) - .set(credentials) - .send({ - roomId: cfchannel._id, - customFields - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group._id'); - expect(res.body).to.have.nested.property('group.name', cfchannel.name); - expect(res.body).to.have.nested.property('group.t', 'p'); - expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); - expect(res.body).to.have.not.nested.property('group.customFields.field0', 'value0'); - }) - .end(done); - }); - it('get customFields using groups.info', (done) => { - request.get(api('groups.info')) - .set(credentials) - .query({ - roomId: cfchannel._id - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); - }) - .end(done); - }); - it('delete group with customFields', (done) => { - request.post(api('groups.delete')) - .set(credentials) - .send({ - roomName: cfchannel.name - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - }) - .end(done); - }); - it('create group without customFields', (done) => { - request.post(api('groups.create')) - .set(credentials) - .send({ - name: `channel.cf.${ Date.now() }` - }) - .end((err, res) => { - cfchannel = res.body.group; - done(); - }); - }); - it('set customFields with one nested field', async(done) => { - const customFields = {'field1':'value1'}; - request.post(api('groups.setCustomFields')) - .set(credentials) - .send({ - roomId: cfchannel._id, - customFields - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group._id'); - expect(res.body).to.have.nested.property('group.name', cfchannel.name); - expect(res.body).to.have.nested.property('group.t', 'p'); - expect(res.body).to.have.nested.property('group.customFields.field1', 'value1'); - }) - .end(done); - }); - it('set customFields with multiple nested fields', async(done) => { - const customFields = {'field2':'value2', 'field3':'value3', 'field4':'value4'}; - - request.post(api('groups.setCustomFields')) - .set(credentials) - .send({ - roomName: cfchannel.name, - customFields - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('group._id'); - expect(res.body).to.have.nested.property('group.name', cfchannel.name); - expect(res.body).to.have.nested.property('group.t', 'p'); - expect(res.body).to.have.nested.property('group.customFields.field2', 'value2'); - expect(res.body).to.have.nested.property('group.customFields.field3', 'value3'); - expect(res.body).to.have.nested.property('group.customFields.field4', 'value4'); - expect(res.body).to.have.not.nested.property('group.customFields.field1', 'value1'); - }) - .end(done); + it('change customFields', async(done) => { + const customFields = {'field9':'value9'}; + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); + expect(res.body).to.have.not.nested.property('group.customFields.field0', 'value0'); + }) + .end(done); + }); + it('get customFields using groups.info', (done) => { + request.get(api('groups.info')) + .set(credentials) + .query({ + roomId: cfchannel._id + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group.customFields.field9', 'value9'); + }) + .end(done); + }); + it('delete group with customFields', (done) => { + request.post(api('groups.delete')) + .set(credentials) + .send({ + roomName: cfchannel.name + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + it('create group without customFields', (done) => { + request.post(api('groups.create')) + .set(credentials) + .send({ + name: `channel.cf.${ Date.now() }` + }) + .end((err, res) => { + cfchannel = res.body.group; + done(); }); + }); + it('set customFields with one nested field', async(done) => { + const customFields = {'field1':'value1'}; + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomId: cfchannel._id, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field1', 'value1'); + }) + .end(done); + }); + it('set customFields with multiple nested fields', async(done) => { + const customFields = {'field2':'value2', 'field3':'value3', 'field4':'value4'}; + + request.post(api('groups.setCustomFields')) + .set(credentials) + .send({ + roomName: cfchannel.name, + customFields + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', cfchannel.name); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.customFields.field2', 'value2'); + expect(res.body).to.have.nested.property('group.customFields.field3', 'value3'); + expect(res.body).to.have.nested.property('group.customFields.field4', 'value4'); + expect(res.body).to.have.not.nested.property('group.customFields.field1', 'value1'); + }) + .end(done); + }); it('set customFields to empty object', async(done) => { const customFields = {}; From bb3f07f2b87beb263d63bf02cc30353b430a360c Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Sun, 25 Feb 2018 02:16:47 +0300 Subject: [PATCH 6/7] Propogate setCustomFields to Subscriptions Signed-off-by: Eugene Bolshakov --- .../server/functions/saveRoomCustomFields.js | 7 ++++++- .../rocketchat-lib/server/models/Subscriptions.js | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js b/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js index 9e8fd6a2a990..8f7a8f61024d 100644 --- a/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomCustomFields.js @@ -9,5 +9,10 @@ RocketChat.saveRoomCustomFields = function(rid, roomCustomFields) { 'function': 'RocketChat.saveRoomCustomFields' }); } - return RocketChat.models.Rooms.setCustomFieldsById(rid, roomCustomFields); + const ret = RocketChat.models.Rooms.setCustomFieldsById(rid, roomCustomFields); + + // Update customFields of any user's Subscription related with this rid + RocketChat.models.Subscriptions.updateCustomFieldsByRoomId(rid, roomCustomFields); + + return ret; }; diff --git a/packages/rocketchat-lib/server/models/Subscriptions.js b/packages/rocketchat-lib/server/models/Subscriptions.js index 4c59e26add7f..2858b058cd16 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.js +++ b/packages/rocketchat-lib/server/models/Subscriptions.js @@ -491,6 +491,18 @@ class ModelSubscriptions extends RocketChat.models._Base { return this.update(query, update) && this.update(query2, update2); } + updateCustomFieldsByRoomId(rid, cfields) { + const query = {rid}; + const customFields = cfields || {} + const update = { + $set: { + customFields + } + }; + + return this.update(query, update, { multi: true }); + } + updateTypeByRoomId(roomId, type) { const query = {rid: roomId}; From 6a924c3b4171f3afa806e33c7702b39eb0848385 Mon Sep 17 00:00:00 2001 From: Eugene Bolshakov Date: Sun, 25 Feb 2018 02:22:10 +0300 Subject: [PATCH 7/7] Fix semicolon Signed-off-by: Eugene Bolshakov --- packages/rocketchat-lib/server/models/Subscriptions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/models/Subscriptions.js b/packages/rocketchat-lib/server/models/Subscriptions.js index 2858b058cd16..adb621492ba5 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.js +++ b/packages/rocketchat-lib/server/models/Subscriptions.js @@ -493,7 +493,7 @@ class ModelSubscriptions extends RocketChat.models._Base { updateCustomFieldsByRoomId(rid, cfields) { const query = {rid}; - const customFields = cfields || {} + const customFields = cfields || {}; const update = { $set: { customFields