From f29a09d7d35b0326cd4a960e0aa08685f6cdf3b4 Mon Sep 17 00:00:00 2001 From: "Didier (did)" Date: Tue, 26 Sep 2023 10:59:15 +0200 Subject: [PATCH] [IMP] mail: send channel update to the client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this PR, channel update were not sent via bus notifications. Part of task-2821415 closes odoo/odoo#136623 Signed-off-by: Alexandre Kühn (aku) --- addons/mail/models/discuss/discuss_channel.py | 34 ++++++------- .../core/web/discuss_core_web_service.js | 6 +-- .../static/tests/discuss_app/sidebar_tests.js | 19 +++++++ .../mock_server/models/discuss_channel.js | 50 +++++++++++++------ .../tests/discuss/test_discuss_channel.py | 19 +++++++ 5 files changed, 93 insertions(+), 35 deletions(-) diff --git a/addons/mail/models/discuss/discuss_channel.py b/addons/mail/models/discuss/discuss_channel.py index 6c0ee29a2fa..56d3a25fa43 100644 --- a/addons/mail/models/discuss/discuss_channel.py +++ b/addons/mail/models/discuss/discuss_channel.py @@ -273,11 +273,25 @@ class Channel(models.Model): failing_channels = self.sudo().filtered(lambda channel: channel.channel_type != vals.get('channel_type')) if failing_channels: raise UserError(_('Cannot change the channel type of: %(channel_names)s', channel_names=', '.join(failing_channels.mapped('name')))) + notifications = [] + for channel in self: + current_val = channel.read(vals.keys())[0] + diff = {} + for key in vals.keys(): + if current_val.get(key) != vals.get(key) and key != "image_128": + diff[key] = vals[key] + if diff: + notifications.append([channel, "mail.record/insert", { + "Thread": { + "id": current_val["id"], + "model": "discuss.channel", + **diff + } + }]) result = super().write(vals) if vals.get('group_ids'): self._subscribe_users_automatically() if 'image_128' in vals: - notifications = [] for channel in self: notifications.append([channel, 'mail.record/insert', { 'Channel': { @@ -285,7 +299,7 @@ class Channel(models.Model): 'id': channel.id, } }]) - self.env['bus.bus']._sendmany(notifications) + self.env['bus.bus']._sendmany(notifications) return result def init(self): @@ -1001,7 +1015,7 @@ class Channel(models.Model): 'foldStateCount': state_count, 'id': session_state.channel_id.id, 'model': 'discuss.channel', - 'serverFoldState': state, + 'fold_state': state, } }) @@ -1112,24 +1126,10 @@ class Channel(models.Model): def channel_rename(self, name): self.ensure_one() self.write({'name': name}) - self.env['bus.bus']._sendone(self, 'mail.record/insert', { - 'Thread': { - 'id': self.id, - 'model': 'discuss.channel', - 'name': name, - } - }) def channel_change_description(self, description): self.ensure_one() self.write({'description': description}) - self.env['bus.bus']._sendone(self, 'mail.record/insert', { - 'Thread': { - 'id': self.id, - 'description': description, - 'model': 'discuss.channel', - } - }) def channel_join(self): """ Shortcut to add the current user as member of self channels. diff --git a/addons/mail/static/src/discuss/core/web/discuss_core_web_service.js b/addons/mail/static/src/discuss/core/web/discuss_core_web_service.js index 8c695765f61..b9c11365c86 100644 --- a/addons/mail/static/src/discuss/core/web/discuss_core_web_service.js +++ b/addons/mail/static/src/discuss/core/web/discuss_core_web_service.js @@ -87,10 +87,10 @@ export class DiscussCoreWeb { if (payload.Thread) { const data = payload.Thread; const thread = this.store.Thread.get(data); - if (data.serverFoldState && thread && data.foldStateCount > thread.foldStateCount) { + if (data.fold_state && thread && data.foldStateCount > thread.foldStateCount) { thread.foldStateCount = data.foldStateCount; - if (data.serverFoldState !== thread.state) { - thread.state = data.serverFoldState; + if (data.fold_state !== thread.state) { + thread.state = data.fold_state; if (thread.state === "closed") { const chatWindow = this.store.discuss.chatWindows.find((chatWindow) => chatWindow.thread?.eq(thread) diff --git a/addons/mail/static/tests/discuss_app/sidebar_tests.js b/addons/mail/static/tests/discuss_app/sidebar_tests.js index 9ebb3071616..40749a6b9eb 100644 --- a/addons/mail/static/tests/discuss_app/sidebar_tests.js +++ b/addons/mail/static/tests/discuss_app/sidebar_tests.js @@ -7,6 +7,7 @@ import { start } from "@mail/../tests/helpers/test_utils"; import { getOrigin } from "@web/core/utils/urls"; import { click, contains, insertText } from "@web/../tests/utils"; +import { triggerHotkey } from "@web/../tests/helpers/utils"; QUnit.module("discuss sidebar"); @@ -1158,3 +1159,21 @@ QUnit.test("Unpinning channel closes its chat window", async () => { await openFormView("discuss.channel"); await contains(".o-mail-ChatWindow", { count: 0, text: "Sales" }); }); + +QUnit.test("Update channel data via bus notification", async () => { + const pyEnv = await startServer(); + const channelId = pyEnv["discuss.channel"].create({ + name: "Sales", + channel_member_ids: [Command.create({ partner_id: pyEnv.currentPartnerId })], + channel_type: "channel", + create_uid: pyEnv.currentUserId, + }); + const tab1 = await start({ asTab: true }); + const tab2 = await start({ asTab: true }); + tab1.openDiscuss(channelId); + tab2.openDiscuss(channelId); + await contains(".o-mail-DiscussSidebarChannel", { text: "Sales", target: tab1.target }); + await insertText(".o-mail-Discuss-threadName", "test", { target: tab1.target }); + await triggerHotkey("Enter"); + await contains(".o-mail-DiscussSidebarChannel", { text: "Salestest", target: tab2.target }); +}); diff --git a/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js b/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js index 1bcbbb14af0..ddefc7712bf 100644 --- a/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js +++ b/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js @@ -10,6 +10,40 @@ import { Command } from "@mail/../tests/helpers/command"; const { DateTime } = luxon; patch(MockServer.prototype, { + /** + * @override + */ + mockWrite(model, args) { + const notifications = []; + if (model == "discuss.channel") { + const vals = args[1]; + const [channel] = this.getRecords(model, [["id", "=", args[0][0]]]); + if (channel) { + const diff = {}; + for (const key in vals) { + if (channel[key] != vals[key] && key !== "image_128") { + diff[key] = vals[key]; + } + } + notifications.push([ + channel, + "mail.record/insert", + { + Thread: { + id: channel.id, + model: "discuss.channel", + ...diff, + }, + }, + ]); + } + } + const mockWriteResult = super.mockWrite(...arguments); + if (notifications.length) { + this.pyEnv["bus.bus"]._sendmany(notifications); + } + return mockWriteResult; + }, async _performRPC(route, args) { if (args.model === "discuss.channel" && args.method === "execute_command_help") { return this._mockDiscussChannelExecuteCommandHelp(args.args[0], args.model); @@ -488,7 +522,7 @@ patch(MockServer.prototype, { foldStateCount: state_count, id: channel.id, model: "discuss.channel", - serverFoldState: foldState, + fold_state: foldState, }, }); } @@ -777,24 +811,10 @@ patch(MockServer.prototype, { _mockDiscussChannelChannelRename(ids, name) { const channel = this.getRecords("discuss.channel", [["id", "in", ids]])[0]; this.pyEnv["discuss.channel"].write([channel.id], { name }); - this.pyEnv["bus.bus"]._sendone(channel, "mail.record/insert", { - Thread: { - id: channel.id, - model: "discuss.channel", - name: name, - }, - }); }, _mockDiscussChannelChannelChangeDescription(ids, description) { const channel = this.getRecords("discuss.channel", [["id", "in", ids]])[0]; this.pyEnv["discuss.channel"].write([channel.id], { description }); - this.pyEnv["bus.bus"]._sendone(channel, "mail.record/insert", { - Thread: { - id: channel.id, - model: "discuss.channel", - description: description, - }, - }); }, /** * Simulates `channel_set_custom_name` on `discuss.channel`. diff --git a/addons/mail/tests/discuss/test_discuss_channel.py b/addons/mail/tests/discuss/test_discuss_channel.py index 6e875fa437e..13be66a8dd7 100644 --- a/addons/mail/tests/discuss/test_discuss_channel.py +++ b/addons/mail/tests/discuss/test_discuss_channel.py @@ -504,6 +504,25 @@ class TestChannelInternals(MailCommon): test_channel.image_128 = base64.b64encode(("").encode()) self.assertEqual(test_channel.avatar_128, test_channel.image_128) + def test_channel_write_should_send_notification(self): + channel = self.env['discuss.channel'].create({"name": "test", "description": "test"}) + # do the operation once before the assert to grab the value to expect + with self.assertBus( + [(self.cr.dbname, 'discuss.channel', channel.id)], + [{ + "type": "mail.record/insert", + "payload": { + 'Thread': { + "id": channel.id, + "model": "discuss.channel", + "name": "test test", + } + }, + }] + ): + channel.name = "test test" + channel.description = "test" + def test_channel_write_should_send_notification_if_image_128_changed(self): channel = self.env['discuss.channel'].create({'name': '', 'uuid': 'test-uuid'}) # do the operation once before the assert to grab the value to expect