[FIX] mail, test_mail: fix channel_get result

- flush must be done before executing queries
- when the current partner is given, it shouldn't be checked twice
- when a channel includes the given partners but also has more partners, it
  shouldn't be returned
- query can be limited to 1 result, minor performance gain in the rare case
  where more than one canonical channel exists

task-2324119

closes odoo/odoo#56680

X-original-commit: b716dd9e62991997e03556f2d3e2483921fedef9
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Sébastien Theys
2020-08-27 15:12:50 +00:00
parent 30f589f748
commit 2a0bcd103a
2 changed files with 72 additions and 34 deletions
+41 -34
View File
@@ -625,42 +625,49 @@ class Channel(models.Model):
only the given partners.
:param partners_to : list of res.partner ids to add to the conversation
:param pin : True if getting the channel should pin it for the current user
:returns a channel header, or False if the users_to was False
:rtype : dict
:returns: channel_info of the created or existing channel
:rtype: dict
"""
if partners_to:
if self.env.user.partner_id.id not in partners_to:
partners_to.append(self.env.user.partner_id.id)
# determine type according to the number of partner in the channel
self.env.cr.execute("""
SELECT P.channel_id
FROM mail_channel C, mail_channel_partner P
WHERE P.channel_id = C.id
AND C.public LIKE 'private'
AND P.partner_id IN %s
AND C.channel_type LIKE 'chat'
GROUP BY P.channel_id
HAVING ARRAY_AGG(DISTINCT P.partner_id ORDER BY P.partner_id) = %s
""", (tuple(partners_to), sorted(list(partners_to)),))
result = self.env.cr.dictfetchall()
if result:
# get the existing channel between the given partners
channel = self.browse(result[0].get('channel_id'))
# pin up the channel for the current partner
if pin:
self.env['mail.channel.partner'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', channel.id)]).write({'is_pinned': True})
else:
# create a new one
channel = self.create({
'channel_partner_ids': [(4, partner_id) for partner_id in partners_to],
'public': 'private',
'channel_type': 'chat',
'email_send': False,
'name': ', '.join(self.env['res.partner'].sudo().browse(partners_to).mapped('name')),
})
# broadcast the channel header to the other partner (not me)
channel._broadcast(partners_to)
return channel.channel_info()[0]
return False
# determine type according to the number of partner in the channel
self.flush()
self.env.cr.execute("""
SELECT P.channel_id
FROM mail_channel C, mail_channel_partner P
WHERE P.channel_id = C.id
AND C.public LIKE 'private'
AND P.partner_id IN %s
AND C.channel_type LIKE 'chat'
AND NOT EXISTS (
SELECT *
FROM mail_channel_partner P2
WHERE P2.channel_id = C.id
AND P2.partner_id NOT IN %s
)
GROUP BY P.channel_id
HAVING ARRAY_AGG(DISTINCT P.partner_id ORDER BY P.partner_id) = %s
LIMIT 1
""", (tuple(partners_to), tuple(partners_to), sorted(list(partners_to)),))
result = self.env.cr.dictfetchall()
if result:
# get the existing channel between the given partners
channel = self.browse(result[0].get('channel_id'))
# pin up the channel for the current partner
if pin:
self.env['mail.channel.partner'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', channel.id)]).write({'is_pinned': True})
else:
# create a new one
channel = self.create({
'channel_partner_ids': [(4, partner_id) for partner_id in partners_to],
'public': 'private',
'channel_type': 'chat',
'email_send': False,
'name': ', '.join(self.env['res.partner'].sudo().browse(partners_to).mapped('name')),
})
# broadcast the channel header to the other partner (not me)
channel._broadcast(partners_to)
return channel.channel_info()[0]
@api.model
def channel_get_and_minimize(self, partners_to):
@@ -226,6 +226,37 @@ class TestChannelFeatures(TestMailCommon):
self.assertEqual(test_channel_group.channel_partner_ids, self.env['res.partner'])
self.assertEqual(self.test_channel.channel_partner_ids, self.user_employee.partner_id | test_partner)
def test_channel_get(self):
current_user = self.env['res.users'].create({
"login": "adam",
"name": "Jonas",
})
current_user = current_user.with_user(current_user)
current_partner = current_user.partner_id
other_partner = self.test_partner
# `channel_get` should return a new channel the first time a partner is given
initial_channel_info = current_user.env['mail.channel'].channel_get(partners_to=other_partner.ids)
self.assertEqual(set(p['id'] for p in initial_channel_info['members']), {current_partner.id, other_partner.id})
# `channel_get` should return the existing channel every time the same partner is given
same_channel_info = current_user.env['mail.channel'].channel_get(partners_to=other_partner.ids)
self.assertEqual(same_channel_info['id'], initial_channel_info['id'])
# `channel_get` should return the existing channel when the current partner is given together with the other partner
together_channel_info = current_user.env['mail.channel'].channel_get(partners_to=(current_partner + other_partner).ids)
self.assertEqual(together_channel_info['id'], initial_channel_info['id'])
# `channel_get` should return a new channel the first time just the current partner is given,
# even if a channel containing the current partner together with other partners already exists
solo_channel_info = current_user.env['mail.channel'].channel_get(partners_to=current_partner.ids)
self.assertNotEqual(solo_channel_info['id'], initial_channel_info['id'])
self.assertEqual(set(p['id'] for p in solo_channel_info['members']), {current_partner.id})
# `channel_get` should return the existing channel every time the current partner is given
same_solo_channel_info = current_user.env['mail.channel'].channel_get(partners_to=current_partner.ids)
self.assertEqual(same_solo_channel_info['id'], solo_channel_info['id'])
@tagged('moderation')
class TestChannelModeration(TestMailCommon):