From 9772512e7a8fbec5b90417256b5462b8f13067fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Wed, 11 Aug 2021 16:21:20 +0000 Subject: [PATCH] [IMP] mail, *: batch channels at init messaging * = im_livechat, test_discuss_full Less code, less queries. Part of task-2622462 --- addons/im_livechat/models/res_partner.py | 7 ++-- .../messaging_initializer.js | 24 ------------- .../static/tests/helpers/mock_server.js | 6 ++-- .../tests/test_get_mail_channel.py | 2 +- addons/mail/models/res_partner.py | 35 +++++++------------ addons/mail/models/res_users.py | 2 +- .../messaging_initializer.js | 18 +++------- .../mail/static/tests/helpers/mock_server.js | 12 +++---- .../tests/test_performance.py | 15 ++++---- 9 files changed, 39 insertions(+), 82 deletions(-) diff --git a/addons/im_livechat/models/res_partner.py b/addons/im_livechat/models/res_partner.py index ffc86a5b89d..df2e7a0a493 100644 --- a/addons/im_livechat/models/res_partner.py +++ b/addons/im_livechat/models/res_partner.py @@ -35,13 +35,12 @@ class Partners(models.Model): return result def _get_channels_as_member(self): - values = super()._get_channels_as_member() - livechat_channels = self.env['mail.channel'].search([ + channels = super()._get_channels_as_member() + channels |= self.env['mail.channel'].search([ ('channel_type', '=', 'livechat'), ('channel_last_seen_partner_ids', 'in', self.env['mail.channel.partner'].sudo()._search([ ('partner_id', '=', self.id), ('is_pinned', '=', True), ])), ]) - values['channel_livechat'] = livechat_channels.channel_info() - return values + return channels diff --git a/addons/im_livechat/static/src/models/messaging_initializer/messaging_initializer.js b/addons/im_livechat/static/src/models/messaging_initializer/messaging_initializer.js index 66c881d7ca6..27ef526720f 100644 --- a/addons/im_livechat/static/src/models/messaging_initializer/messaging_initializer.js +++ b/addons/im_livechat/static/src/models/messaging_initializer/messaging_initializer.js @@ -1,33 +1,9 @@ /** @odoo-module **/ import { registerInstancePatchModel } from '@mail/model/model_core'; -import { executeGracefully } from '@mail/utils/utils'; import { insert } from '@mail/model/model_field_command'; registerInstancePatchModel('mail.messaging_initializer', 'im_livechat/static/src/models/messaging_initializer/messaging_initializer.js', { - - //---------------------------------------------------------------------- - // Private - //---------------------------------------------------------------------- - - /** - * @override - * @param {Object[]} [param0.channel_livechat=[]] - */ - async _initChannels(initMessagingData) { - await this.async(() => this._super(initMessagingData)); - const { channel_livechat = [] } = initMessagingData; - return executeGracefully(channel_livechat.map(data => () => { - const channel = this.env.models['mail.thread'].insert( - this.env.models['mail.thread'].convertData(data), - ); - // flux specific: channels received at init have to be - // considered pinned. task-2284357 - if (!channel.isPinned) { - channel.pin(); - } - })); - }, /** * @override */ diff --git a/addons/im_livechat/static/tests/helpers/mock_server.js b/addons/im_livechat/static/tests/helpers/mock_server.js index c67bff03f17..7059c274825 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server.js +++ b/addons/im_livechat/static/tests/helpers/mock_server.js @@ -249,9 +249,9 @@ MockServer.include({ ['is_pinned', '=', true], ['members', 'in', partner.id], ]); - return { - channel_livechat: this._mockMailChannelChannelInfo(livechats.map(channel => channel.id)), + return [ ...this._super(ids), - }; + ...livechats, + ]; }, }); diff --git a/addons/im_livechat/tests/test_get_mail_channel.py b/addons/im_livechat/tests/test_get_mail_channel.py index e7bed715a15..aa48d8dabbc 100644 --- a/addons/im_livechat/tests/test_get_mail_channel.py +++ b/addons/im_livechat/tests/test_get_mail_channel.py @@ -99,4 +99,4 @@ class TestGetMailChannel(TransactionCase): self.assertFalse(operator_channel_partner.is_pinned, "channel should not be pinned for operator initially") self.env['mail.channel'].browse(channel_info['id']).message_post(body='cc') self.assertTrue(operator_channel_partner.is_pinned, "channel should be pinned for operator after visitor sent a message") - self.assertIn(channel_info['id'], [init_channel_info['id'] for init_channel_info in operator_channel_partner.partner_id._get_channels_as_member()['channel_livechat']], "channel should be fetched by operator on new page") + self.assertIn(channel_info['id'], operator_channel_partner.partner_id._get_channels_as_member().ids, "channel should be fetched by operator on new page") diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index 86cdf50011d..c6f69f6590a 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -119,32 +119,23 @@ class Partner(models.Model): return messages._message_notification_format() def _get_channels_as_member(self): - """ Return the channels of the partner grouped by 'slot' (channel, direct_message or private_group), and - the mapping between partner_id/channel_id for direct_message channels. - :returns dict : the grouped channels and the mapping - """ + """Returns the channels of the partner.""" self.ensure_one() - values = {} - pinned_channels = self.env['mail.channel.partner'].search([('partner_id', '=', self.id), ('is_pinned', '=', True)]).mapped('channel_id') - # get the group/public channels - values['channel_channel'] = self.env['mail.channel'].search([ + channels = self.env['mail.channel'] + # get the channels + channels |= self.env['mail.channel'].search([ ('channel_type', '=', 'channel'), - ('public', 'in', ['public', 'groups']), ('channel_partner_ids', 'in', [self.id]), - ]).channel_info() - # get the pinned 'direct message' channel - direct_message_channels = self.env['mail.channel'].search([ - ('channel_type', '=', 'chat'), - ('id', 'in', pinned_channels.ids), ]) - values['channel_direct_message'] = direct_message_channels.channel_info() - # get the private group - values['channel_private_group'] = self.env['mail.channel'].search([ - ('channel_type', '=', 'channel'), - ('public', '=', 'private'), - ('channel_partner_ids', 'in', [self.id]), - ]).channel_info() - return values + # get the pinned direct messages + channels |= self.env['mail.channel'].search([ + ('channel_type', '=', 'chat'), + ('channel_last_seen_partner_ids', 'in', self.env['mail.channel.partner'].sudo()._search([ + ('partner_id', '=', self.id), + ('is_pinned', '=', True), + ])), + ]) + return channels @api.model def search_for_channel_invite(self, search_term, channel_id=None, limit=30): diff --git a/addons/mail/models/res_users.py b/addons/mail/models/res_users.py index b1a0350fc3b..498bbeaebec 100644 --- a/addons/mail/models/res_users.py +++ b/addons/mail/models/res_users.py @@ -83,7 +83,7 @@ class Users(models.Model): def _init_messaging(self): self.ensure_one() values = { - 'channel_slots': self.partner_id._get_channels_as_member(), + 'channels': self.partner_id._get_channels_as_member().channel_info(), 'current_partner': self.partner_id.mail_partner_format(), 'current_user_id': self.id, 'mail_failures': self.partner_id._message_fetch_failed(), diff --git a/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js b/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js index f0b1a83e725..d217b36a505 100644 --- a/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js +++ b/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js @@ -65,7 +65,7 @@ function factory(dependencies) { /** * @private * @param {Object} param0 - * @param {Object} param0.channel_slots + * @param {Object[]} param0.channels * @param {Object} param0.current_partner * @param {integer} param0.current_user_id * @param {Object} [param0.mail_failures={}] @@ -76,7 +76,7 @@ function factory(dependencies) { * @param {integer} [param0.starred_counter=0] */ async _init({ - channel_slots, + channels, commands = [], current_partner, current_user_id, @@ -106,7 +106,7 @@ function factory(dependencies) { this._initCannedResponses(shortcodes); this._initCommands(); // channels when the rest of messaging is ready - await this.async(() => this._initChannels(channel_slots)); + await this.async(() => this._initChannels(channels)); // failures after channels this._initMailFailures(mail_failures); discuss.update({ menu_id }); @@ -124,17 +124,9 @@ function factory(dependencies) { /** * @private - * @param {Object} [param0={}] - * @param {Object[]} [param0.channel_channel=[]] - * @param {Object[]} [param0.channel_direct_message=[]] - * @param {Object[]} [param0.channel_private_group=[]] + * @param {Object[]} channelsData */ - async _initChannels({ - channel_channel = [], - channel_direct_message = [], - channel_private_group = [], - } = {}) { - const channelsData = channel_channel.concat(channel_direct_message, channel_private_group); + async _initChannels(channelsData) { return executeGracefully(channelsData.map(channelData => () => { const convertedData = this.env.models['mail.thread'].convertData(channelData); if (!convertedData.members) { diff --git a/addons/mail/static/tests/helpers/mock_server.js b/addons/mail/static/tests/helpers/mock_server.js index 09e774260d3..3aaab02fd33 100644 --- a/addons/mail/static/tests/helpers/mock_server.js +++ b/addons/mail/static/tests/helpers/mock_server.js @@ -1617,11 +1617,11 @@ MockServer.include({ ['members', 'in', partner.id], ['public', '=', 'private'], ]); - return { - channel_channel: this._mockMailChannelChannelInfo(channels.map(channel => channel.id)), - channel_direct_message: this._mockMailChannelChannelInfo(directMessages.map(channel => channel.id)), - channel_private_group: this._mockMailChannelChannelInfo(privateGroups.map(channel => channel.id)), - }; + return [ + ...channels, + ...privateGroups, + ...directMessages, + ]; }, /** * Simulates `get_mention_suggestions` on `res.partner`. @@ -1797,7 +1797,7 @@ MockServer.include({ _mockResUsers_InitMessaging(ids) { const user = this._getRecords('res.users', [['id', 'in', ids]])[0]; return { - channel_slots: this._mockResPartner_GetChannelsAsMember(user.partner_id), + channels: this._mockMailChannelChannelInfo(this._mockResPartner_GetChannelsAsMember(user.partner_id).map(channel => channel.id)), current_partner: this._mockResPartnerMailPartnerFormat(user.partner_id), current_user_id: this.currentUserId, mail_failures: this._mockResPartner_MessageFetchFailed(user.partner_id), diff --git a/addons/test_discuss_full/tests/test_performance.py b/addons/test_discuss_full/tests/test_performance.py index f7034faac81..e65b5f3707d 100644 --- a/addons/test_discuss_full/tests/test_performance.py +++ b/addons/test_discuss_full/tests/test_performance.py @@ -94,13 +94,13 @@ class TestDiscussFullPerformance(TransactionCase): self.users[0].flush() self.users[0].invalidate_cache() - with self.assertQueryCount(emp=69): + with self.assertQueryCount(emp=42): init_messaging = self.users[0]._init_messaging() self.assertEqual(init_messaging, { 'needaction_inbox_counter': 1, 'starred_counter': 1, - 'channel_slots': {'channel_channel': [ + 'channels': [ { 'channel_type': 'channel', 'create_uid': user_root.id, @@ -179,7 +179,6 @@ class TestDiscussFullPerformance(TransactionCase): 'state': 'open', 'uuid': channel_group_2.uuid, }, - ], 'channel_private_group': [ { 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -210,7 +209,6 @@ class TestDiscussFullPerformance(TransactionCase): 'state': 'open', 'uuid': channel_private_2.uuid, }, - ], 'channel_direct_message': [ { 'channel_type': 'chat', 'create_uid': self.env.user.id, @@ -391,7 +389,6 @@ class TestDiscussFullPerformance(TransactionCase): 'state': 'open', 'uuid': channel_dm_4.uuid, }, - ], 'channel_livechat': [ { 'channel_type': 'livechat', 'create_uid': self.env.user.id, @@ -410,7 +407,8 @@ class TestDiscussFullPerformance(TransactionCase): 'email': 'e.e@example.com', 'id': self.users[0].partner_id.id, 'name': 'Ernest Employee', - 'out_of_office_date_end': False, + 'im_status': 'leave_offline', + 'out_of_office_date_end': self.leaves.filtered(lambda l: l.employee_id.user_id == self.users[0]).date_to, }, { 'email': 'test1@example.com', @@ -464,8 +462,9 @@ class TestDiscussFullPerformance(TransactionCase): { 'email': 'e.e@example.com', 'id': self.users[0].partner_id.id, + 'im_status': 'leave_offline', 'name': 'Ernest Employee', - 'out_of_office_date_end': False, + 'out_of_office_date_end': self.leaves.filtered(lambda l: l.employee_id.user_id == self.users[0]).date_to, }, ], 'message_needaction_counter': 0, @@ -490,7 +489,7 @@ class TestDiscussFullPerformance(TransactionCase): 'state': 'open', 'uuid': channel_livechat_2.uuid, }, - ]}, + ], 'mail_failures': [], 'shortcodes': [ {