[IMP] mail, *: batch channels at init messaging

* = im_livechat, test_discuss_full

Less code, less queries.

Part of task-2622462
This commit is contained in:
Sébastien Theys
2021-08-12 15:22:37 +00:00
parent 7602c168d7
commit 9772512e7a
9 changed files with 39 additions and 82 deletions
+3 -4
View File
@@ -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
@@ -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
*/
@@ -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,
];
},
});
@@ -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")
+13 -22
View File
@@ -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):
+1 -1
View File
@@ -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(),
@@ -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) {
@@ -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),
@@ -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': [
{