[IMP] mail, hr_holidays: improve channel_info
`channel_info` can be called on multiple channels especially during
the init_messaging. The current implementation will perform read and
other queries in the loop. This commits aims to refactor `channel_info`
in order to read all informations in database out of the loop.
Computation of members informations is now the same as for `direct_partner`
As a side effect direct partner will have an email adress and members will have
im_status and out_of_office message if the partner is in a
channel of type chat. It would be easier to compute im_status in all case but
this could create performances issues when calling channel info on channel with
hundreds of users.
channel_fetch_preview will make a query in database in any case but seems to work ok
in api multi. We can put it out of the loop.
44ac7903cc fix shouldn't be broken by this refactoring since we are no longer using the many2many to find direct_partners.
This commit is contained in:
@@ -8,14 +8,10 @@ class Channel(models.Model):
|
||||
_inherit = 'mail.channel'
|
||||
|
||||
@api.multi
|
||||
def channel_info(self, extra_info=False):
|
||||
channel_infos = super(Channel, self).channel_info(extra_info)
|
||||
partners_on_leave = []
|
||||
for channel_info in channel_infos:
|
||||
if 'direct_partner' in channel_info:
|
||||
for direct_partner in channel_info['direct_partner']:
|
||||
if 'leave' in direct_partner['im_status']:
|
||||
partners_on_leave.append(direct_partner['id'])
|
||||
def partner_info(self, all_partners, direct_partners):
|
||||
partner_infos = super(Channel, self).partner_info(all_partners, direct_partners)
|
||||
# only search for leave out_of_office_message if im_status is on leave
|
||||
partners_on_leave = [partner_id for partner_id in direct_partners.ids if 'leave' in partner_infos[partner_id]['im_status']]
|
||||
if partners_on_leave:
|
||||
now = fields.Datetime.now()
|
||||
self.env.cr.execute('''SELECT res_users.partner_id as partner_id, hr_leave.out_of_office_message as out_of_office_message, hr_leave.date_to as date_to
|
||||
@@ -26,11 +22,8 @@ class Channel(models.Model):
|
||||
AND hr_leave.date_from <= %s
|
||||
AND hr_leave.date_to >= %s
|
||||
AND res_users.partner_id in %s''', (now, now, tuple(partners_on_leave)))
|
||||
out_of_office_info = dict(((res['partner_id'], res) for res in self.env.cr.dictfetchall()))
|
||||
for channel_info in channel_infos:
|
||||
if 'direct_partner' in channel_info:
|
||||
for direct_partner in channel_info['direct_partner']:
|
||||
if 'leave' in direct_partner['im_status']:
|
||||
direct_partner['out_of_office_date_end'] = out_of_office_info.get(direct_partner['id'], {}).get('date_to')
|
||||
direct_partner['out_of_office_message'] = out_of_office_info.get(direct_partner['id'], {}).get('out_of_office_message')
|
||||
return channel_infos
|
||||
out_of_office_infos = dict(((res['partner_id'], res) for res in self.env.cr.dictfetchall()))
|
||||
for partner_id, out_of_office_info in out_of_office_infos.items():
|
||||
partner_infos[partner_id]['out_of_office_date_end'] = out_of_office_info['date_to']
|
||||
partner_infos[partner_id]['out_of_office_message'] = out_of_office_info['out_of_office_message']
|
||||
return partner_infos
|
||||
|
||||
@@ -540,21 +540,47 @@ class Channel(models.Model):
|
||||
notifications.append([channel.uuid, dict(message_values)])
|
||||
return notifications
|
||||
|
||||
@api.model
|
||||
def partner_info(self, all_partners, direct_partners):
|
||||
"""
|
||||
Return the information needed by channel to display channel members
|
||||
:param all_partners: list of res.parner():
|
||||
:param direct_partners: list of res.parner():
|
||||
:returns: a list of {'id', 'name', 'email'} for each partner and adds {im_status, out_of_office_message} for direct_partners.
|
||||
:rtype : list(dict)
|
||||
"""
|
||||
partner_infos = {partner['id']: partner for partner in all_partners.sudo().read(['id', 'name', 'email'])}
|
||||
# add im _status and out_of_office_message for direct_partners
|
||||
direct_partners_im_status = {partner['id']: partner for partner in direct_partners.sudo().read(['im_status'])}
|
||||
partner_infos.update(direct_partners_im_status)
|
||||
for user in self.env['res.users'].search([('partner_id', 'in', direct_partners.ids), ('out_of_office_message', '!=', False)]):
|
||||
partner_infos[user.partner_id.id]['out_of_office_message'] = user.out_of_office_message
|
||||
return partner_infos
|
||||
|
||||
@api.multi
|
||||
def channel_info(self, extra_info = False):
|
||||
def channel_info(self, extra_info=False):
|
||||
""" Get the informations header for the current channels
|
||||
:returns a list of channels values
|
||||
:rtype : list(dict)
|
||||
"""
|
||||
if not self:
|
||||
return []
|
||||
channel_infos = []
|
||||
|
||||
# all relations partner_channel on those channels
|
||||
all_partner_channel = self.env['mail.channel.partner'].search([('channel_id', 'in', self.ids)])
|
||||
|
||||
# all partner infos on those channels
|
||||
partner_infos = all_partner_channel.mapped('partner_id').read(['id', 'name', 'email'])
|
||||
channel_dict = {channel.id: channel for channel in self}
|
||||
all_partners = all_partner_channel.mapped('partner_id')
|
||||
direct_channel_partners = all_partner_channel.filtered(lambda pc: channel_dict[pc.channel_id.id].channel_type == 'chat')
|
||||
direct_partners = direct_channel_partners.mapped('partner_id')
|
||||
partner_infos = self.partner_info(all_partners, direct_partners)
|
||||
|
||||
# add last message preview (only used in mobile)
|
||||
addPreview = self._context.get('isMobile', False)
|
||||
if addPreview:
|
||||
channel_previews = {channel_preview['id']: channel_preview for channel_preview in self.channel_fetch_preview()}
|
||||
|
||||
# for each channel, build the information header and include the logged partner information
|
||||
for channel in self:
|
||||
info = {
|
||||
'id': channel.id,
|
||||
@@ -572,46 +598,39 @@ class Channel(models.Model):
|
||||
}
|
||||
if extra_info:
|
||||
info['info'] = extra_info
|
||||
# add the partner for 'direct mesage' channel
|
||||
if channel.channel_type == 'chat':
|
||||
info['direct_partner'] = (channel.sudo()
|
||||
.with_context(active_test=False)
|
||||
.channel_partner_ids
|
||||
.filtered(lambda p: p.id != self.env.user.partner_id.id)
|
||||
.read(['id', 'name', 'im_status']))
|
||||
for direct_partner in info['direct_partner']:
|
||||
users = self.env['res.partner'].browse(direct_partner['id']).user_ids
|
||||
if users:
|
||||
direct_partner['out_of_office_message'] = users[0].out_of_office_message
|
||||
|
||||
# add last message preview (only used in mobile)
|
||||
if self._context.get('isMobile', False):
|
||||
last_message = channel.channel_fetch_preview()
|
||||
if last_message:
|
||||
info['last_message'] = last_message[0].get('last_message')
|
||||
if addPreview:
|
||||
if channel in channel_previews:
|
||||
info['last_message'] = channel_previews[channel]
|
||||
|
||||
# listeners of the channel
|
||||
channel_partners = all_partner_channel.filtered(lambda pc: channel.id == pc.channel_id.id)
|
||||
|
||||
# find the channel partner state, if logged user
|
||||
partner_channel = self.env['mail.channel.partner']
|
||||
if self.env.user and self.env.user.partner_id:
|
||||
partner_channel = channel_partners.filtered(lambda pc: pc.partner_id.id == self.env.user.partner_id.id)
|
||||
# add the partner for 'direct mesage' channel
|
||||
if channel.channel_type == 'chat':
|
||||
# direct_partner should be removed from channel info since we can find it from members and channel_type
|
||||
# we keep it know to avoid change tests and javascript
|
||||
direct_partner = direct_channel_partners.filtered(lambda pc: pc.partner_id.id != self.env.user.partner_id.id)
|
||||
info['direct_partner'] = [partner_infos[direct_partner[0].partner_id.id]]
|
||||
# add needaction and unread counter, since the user is logged
|
||||
info['message_needaction_counter'] = channel.message_needaction_counter
|
||||
info['message_unread_counter'] = channel.message_unread_counter
|
||||
|
||||
# add user session state, if available and if user is logged
|
||||
if len(partner_channel.ids):
|
||||
partner_channel = partner_channel[0]
|
||||
info['state'] = partner_channel.fold_state or 'open'
|
||||
info['is_minimized'] = partner_channel.is_minimized
|
||||
info['seen_message_id'] = partner_channel.seen_message_id.id
|
||||
info['custom_channel_name'] = partner_channel.custom_channel_name
|
||||
# add user session state, if available and if user is logged
|
||||
partner_channel = channel_partners.filtered(lambda pc: pc.partner_id.id == self.env.user.partner_id.id)
|
||||
if partner_channel:
|
||||
partner_channel = partner_channel[0]
|
||||
info['state'] = partner_channel.fold_state or 'open'
|
||||
info['is_minimized'] = partner_channel.is_minimized
|
||||
info['seen_message_id'] = partner_channel.seen_message_id.id
|
||||
info['custom_channel_name'] = partner_channel.custom_channel_name
|
||||
|
||||
# add members infos
|
||||
partner_ids = channel_partners.mapped('partner_id').ids
|
||||
info['members'] = [partner_info for partner_info in partner_infos if partner_info['id'] in partner_ids]
|
||||
info['members'] = [partner_infos[partner] for partner in partner_ids]
|
||||
info['seen_partners_info'] = [{
|
||||
'partner_id': cp.partner_id.id,
|
||||
'fetched_message_id': cp.fetched_message_id.id,
|
||||
@@ -929,6 +948,8 @@ class Channel(models.Model):
|
||||
@api.multi
|
||||
def channel_fetch_preview(self):
|
||||
""" Return the last message of the given channels """
|
||||
if not self:
|
||||
return []
|
||||
self._cr.execute("""
|
||||
SELECT mail_channel_id AS id, MAX(mail_message_id) AS message_id
|
||||
FROM mail_message_mail_channel_rel
|
||||
|
||||
Reference in New Issue
Block a user