From e5338146e764c9abfb50a33bbd1180d1372f978c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?=
Date: Wed, 17 Feb 2021 08:29:43 +0000
Subject: [PATCH] [REF] mail: make message belongs to a single thread without
listener channels
RATIONALE
Channel model is a mail.thread enabled model behaving strangely with followers,
notifications and discuss. Its code should however be simplified to be more
self contained and avoid unwanted side effects on other models.
PURPOSE
Remove channel ability to follow records as it mainly adds noise without a lot
of added value. Simplify channel notification flow by using directly members
and not a delegation through a channel self-following trick. Remove followers
being channels and posting with added listeners being channels.
SPECIFICATIONS
In this commit we force messages to belong to a single document using
``model`` / ``res_id`` pair. It is not possible anymore to link a message
to channels using ``channel_ids``. A message belongs to a document and
is displayed in that document's chatter.
This change implies modifying a lot of domains, notably in chatter. Indeed
discuss for channels does not use ``('channel_ids', 'in', [3])`` domains.
They now use ``('model', '=', 'mail.channel'), ('res_id', 'in', [3])`` like
other documents fetching their messages.
This commit also removes ``channel_message_ids`` field on ``mail.channel``
model. As channels are now considered as standard documents they will use
``message_ids`` field like all other documents. Linking a channel on a message
is possible only as a link in message from now on. It is not possible to push
it into a channel anymore (no more listener channels, no more channel link).
Finally a global cleaning also linked to all previous commits is done.
LINKS
Task ID-2070632 (main task)
Task ID-2419762 (followup task)
COM PR odoo/odoo#62859
ENT PR odoo/enterprise#15172
UPG PR odoo/upgrade#2005
---
addons/crm_livechat/models/mail_channel.py | 2 +-
.../data/im_livechat_channel_demo.xml | 39 ---
.../im_livechat/models/im_livechat_channel.py | 5 +-
addons/im_livechat/models/mail_channel.py | 6 +-
.../report/im_livechat_report_channel.py | 13 +-
.../report/im_livechat_report_operator.py | 5 +-
.../src/components/discuss/discuss_tests.js | 6 +-
.../static/src/legacy/public_livechat.js | 3 +-
.../tests/test_get_mail_channel.py | 4 +-
.../im_livechat/views/mail_channel_views.xml | 4 +-
addons/mail/data/mail_channel_data.xml | 1 -
addons/mail/data/mail_channel_demo.xml | 8 -
addons/mail/models/mail_channel.py | 34 ++-
addons/mail/models/mail_message.py | 105 +++-----
addons/mail/models/mail_thread.py | 4 +-
.../chat_window_manager_tests.js | 27 +-
.../discuss/tests/discuss_domain_tests.js | 6 +-
.../discuss/tests/discuss_inbox_tests.js | 7 -
.../discuss/tests/discuss_moderation_tests.js | 1 -
.../components/discuss/tests/discuss_tests.js | 233 +-----------------
.../messaging_menu/messaging_menu_tests.js | 12 +-
.../notification_list_tests.js | 5 -
.../thread_needaction_preview_tests.js | 43 ----
.../thread_preview/thread_preview_tests.js | 1 -
.../thread_view/thread_view_tests.js | 46 ++--
.../static/src/models/composer/composer.js | 1 -
.../mail/static/src/models/message/message.js | 20 +-
.../messaging_notification_handler.js | 3 +-
.../mail/static/src/models/thread/thread.js | 37 ++-
.../src/models/thread_cache/thread_cache.js | 4 +-
.../mail/static/tests/helpers/mock_models.js | 1 -
.../mail/static/tests/helpers/mock_server.js | 27 +-
addons/mail/tests/test_mail_channel.py | 23 +-
addons/mail/views/mail_message_views.xml | 1 -
addons/test_mail/tests/test_message_post.py | 1 -
.../website_crm_livechat/models/crm_lead.py | 2 +-
.../website_livechat/models/mail_channel.py | 2 +-
addons/website_livechat/models/website.py | 2 +-
.../models/website_visitor.py | 2 +-
.../views/website_visitor_views.xml | 2 +-
40 files changed, 181 insertions(+), 567 deletions(-)
diff --git a/addons/crm_livechat/models/mail_channel.py b/addons/crm_livechat/models/mail_channel.py
index 7747d6926f8..c051309c813 100644
--- a/addons/crm_livechat/models/mail_channel.py
+++ b/addons/crm_livechat/models/mail_channel.py
@@ -29,7 +29,7 @@ class MailChannel(models.Model):
"""
description = ''.join(
'%s: %s\n' % (message.author_id.name or self.anonymous_name, message.body)
- for message in self.channel_message_ids.sorted('id')
+ for message in self.message_ids.sorted('id')
)
# if public user is part of the chat: consider lead to be linked to an
# anonymous user whatever the participants. Otherwise keep only share
diff --git a/addons/im_livechat/data/im_livechat_channel_demo.xml b/addons/im_livechat/data/im_livechat_channel_demo.xml
index 59d2b3b1072..2e9bffd27f4 100644
--- a/addons/im_livechat/data/im_livechat_channel_demo.xml
+++ b/addons/im_livechat/data/im_livechat_channel_demo.xml
@@ -38,7 +38,6 @@
email
You're welcome, have a nice day!
-
@@ -47,7 +46,6 @@
email
Great! Thanks for the info
-
@@ -56,7 +54,6 @@
email
Yes, you can use our Timesheets application and Awesome Timesheets to record your time efficiently!
-
@@ -65,7 +62,6 @@
email
I'm looking for an application to record my timesheet, any tips?
-
@@ -74,7 +70,6 @@
email
Hello, how may I help you?
-
@@ -99,7 +94,6 @@
email
You're welcome, enjoy Odoo!
-
@@ -108,7 +102,6 @@
email
Awesome, thanks!
-
@@ -117,7 +110,6 @@
email
Yes, we just released a new application called Social Marketing that should fit your needs! Check it out :)
-
@@ -126,7 +118,6 @@
email
I was wondering if Odoo has an application to easily manage social media for my business..
-
@@ -135,7 +126,6 @@
email
Hello, how may I help you?
-
@@ -160,7 +150,6 @@
email
Oh :(
-
@@ -169,7 +158,6 @@
email
Nope, sorry to disappoint :(
-
@@ -178,7 +166,6 @@
email
Hello, are you single?
-
@@ -187,7 +174,6 @@
email
Hello, how may I help you?
-
@@ -212,7 +198,6 @@
email
Thanks for the info, I'll look into it!
-
@@ -221,7 +206,6 @@
email
Hello Joel Willis, you're at the right place! You can customize Odoo using our Studio application in just a few clicks.
-
@@ -230,7 +214,6 @@
email
Hello, I'm looking for a software that can be easily updated with my needs.
-
@@ -255,7 +238,6 @@
email
Ok.. Will do, thanks
-
@@ -264,7 +246,6 @@
email
Hi, if you need help with your database, feel free to contact our support via http://www.odoo.com/help
-
@@ -273,7 +254,6 @@
email
Hello, it seems that I can't log in to my database. Can you help?
-
@@ -282,7 +262,6 @@
email
Hello, how may I help you?
-
@@ -307,7 +286,6 @@
email
Thanks!
-
@@ -316,7 +294,6 @@
email
Yes, of course, you can find it here: https://www.odoo.com/documentation/user/14.0/
-
@@ -325,7 +302,6 @@
email
Hello, I'm a bit lost in the Invetory module, is there some documentation I could find?
-
@@ -334,7 +310,6 @@
email
Hello, how may I help you?
-
@@ -359,7 +334,6 @@
email
Good to hear, thanks!
-
@@ -368,7 +342,6 @@
email
Joel Willis, you'll need our Inventory and Sales application to do so. You can try them for 15 days, FOR FREE :)
-
@@ -377,7 +350,6 @@
email
Hi, I need a software to easily manage my stock, and generate sales orders.
-
@@ -386,7 +358,6 @@
email
Hello, how may I help you?
-
@@ -411,7 +382,6 @@
email
I'm great, thanks for asking!
-
@@ -420,7 +390,6 @@
email
I'm fine, and you?
-
@@ -429,7 +398,6 @@
email
Heeeey Marc, how are you?
-
@@ -438,7 +406,6 @@
email
Hello, how may I help you?
-
@@ -458,7 +425,6 @@
Hi
mail.channel
-
@@ -467,7 +433,6 @@
Hello, how may I help you?
mail.channel
-
@@ -477,7 +442,6 @@
I would like to know more about the CRM application
mail.channel
-
@@ -486,7 +450,6 @@
The CRM application helps you to track leads, close opportunities and get accurate forecasts. You can test it for free on our website.
mail.channel
-
@@ -496,7 +459,6 @@
Great, thanks!
mail.channel
-
@@ -506,7 +468,6 @@
Rating: :-)
mail.channel
-
diff --git a/addons/im_livechat/models/im_livechat_channel.py b/addons/im_livechat/models/im_livechat_channel.py
index a79734a92ef..8a8ac0fcdd8 100644
--- a/addons/im_livechat/models/im_livechat_channel.py
+++ b/addons/im_livechat/models/im_livechat_channel.py
@@ -76,7 +76,7 @@ class ImLivechatChannel(models.Model):
def _compute_nbr_channel(self):
data = self.env['mail.channel'].read_group([
('livechat_channel_id', 'in', self._ids),
- ('channel_message_ids', '!=', False)], ['__count'], ['livechat_channel_id'], lazy=False)
+ ('message_ids', '!=', False)], ['__count'], ['livechat_channel_id'], lazy=False)
channel_count = {x['livechat_channel_id'][0]: x['__count'] for x in data}
for record in self:
record.nbr_channel = channel_count.get(record.id, 0)
@@ -182,8 +182,7 @@ class ImLivechatChannel(models.Model):
self.env.cr.execute("""SELECT COUNT(DISTINCT c.id), c.livechat_operator_id
FROM mail_channel c
- LEFT OUTER JOIN mail_message_mail_channel_rel r ON c.id = r.mail_channel_id
- LEFT OUTER JOIN mail_message m ON r.mail_message_id = m.id
+ LEFT OUTER JOIN mail_message m ON c.id = m.res_id AND m.model = 'mail.channel'
WHERE c.channel_type = 'livechat'
AND c.livechat_operator_id in %s
AND m.create_date > ((now() at time zone 'UTC') - interval '30 minutes')
diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py
index 8b9f4e102cd..c77e0082702 100644
--- a/addons/im_livechat/models/mail_channel.py
+++ b/addons/im_livechat/models/mail_channel.py
@@ -131,8 +131,8 @@ class MailChannel(models.Model):
FROM mail_channel C
WHERE NOT EXISTS (
SELECT *
- FROM mail_message_mail_channel_rel R
- WHERE R.mail_channel_id = C.id
+ FROM mail_message M
+ WHERE M.res_id = C.id AND m.model = 'mail.channel'
) AND C.channel_type = 'livechat' AND livechat_channel_id IS NOT NULL AND
COALESCE(write_date, create_date, (now() at time zone 'UTC'))::timestamp
< ((now() at time zone 'UTC') - interval %s)""", ("%s hours" % hours,))
@@ -177,7 +177,7 @@ class MailChannel(models.Model):
if self.livechat_active:
self.livechat_active = False
# avoid useless notification if the channel is empty
- if not self.channel_message_ids:
+ if not self.message_ids:
return
# Notify that the visitor has left the conversation
self.message_post(author_id=self.env.ref('base.partner_root').id,
diff --git a/addons/im_livechat/report/im_livechat_report_channel.py b/addons/im_livechat/report/im_livechat_report_channel.py
index 07c01110b8e..9e3d2c79cbb 100644
--- a/addons/im_livechat/report/im_livechat_report_channel.py
+++ b/addons/im_livechat/report/im_livechat_report_channel.py
@@ -59,9 +59,11 @@ class ImLivechatReportChannel(models.Model):
count(distinct C.livechat_operator_id) as nbr_speaker,
count(distinct M.id) as nbr_message,
CASE
- WHEN EXISTS (select distinct M.author_id FROM mail_message M, mail_message_mail_channel_rel R
- WHERE M.author_id=C.livechat_operator_id AND R.mail_channel_id = C.id
- AND R.mail_message_id = M.id and C.livechat_operator_id = M.author_id)
+ WHEN EXISTS (select distinct M.author_id FROM mail_message M
+ WHERE M.author_id=C.livechat_operator_id
+ AND M.res_id = C.id
+ AND M.model = 'mail.channel'
+ AND C.livechat_operator_id = M.author_id)
THEN 0
ELSE 1
END as is_without_answer,
@@ -88,10 +90,9 @@ class ImLivechatReportChannel(models.Model):
END as is_unrated,
C.livechat_operator_id as partner_id
FROM mail_channel C
- JOIN mail_message_mail_channel_rel R ON (C.id = R.mail_channel_id)
- JOIN mail_message M ON (M.id = R.mail_message_id)
+ JOIN mail_message M ON (M.res_id = C.id AND m.model = 'mail.channel')
JOIN im_livechat_channel L ON (L.id = C.livechat_channel_id)
- LEFT JOIN mail_message MO ON (R.mail_message_id = MO.id AND MO.author_id = C.livechat_operator_id)
+ LEFT JOIN mail_message MO ON (M.res_id = C.id AND m.model = 'mail.channel' AND MO.author_id = C.livechat_operator_id)
LEFT JOIN rating_rating Rate ON (Rate.res_id = C.id and Rate.res_model = 'mail.channel' and Rate.parent_res_model = 'im_livechat.channel')
WHERE C.livechat_operator_id is not null
GROUP BY C.livechat_operator_id, C.id, C.name, C.livechat_channel_id, L.name, C.create_date, C.uuid, Rate.rating
diff --git a/addons/im_livechat/report/im_livechat_report_operator.py b/addons/im_livechat/report/im_livechat_report_operator.py
index cafaf898da2..8dec7061b16 100644
--- a/addons/im_livechat/report/im_livechat_report_operator.py
+++ b/addons/im_livechat/report/im_livechat_report_operator.py
@@ -35,9 +35,8 @@ class ImLivechatReportOperator(models.Model):
EXTRACT('epoch' FROM MAX(M.create_date) - MIN(M.create_date)) AS duration,
EXTRACT('epoch' FROM MIN(MO.create_date) - MIN(M.create_date)) AS time_to_answer
FROM mail_channel C
- JOIN mail_message_mail_channel_rel R ON R.mail_channel_id = C.id
- JOIN mail_message M ON R.mail_message_id = M.id
- LEFT JOIN mail_message MO ON (R.mail_message_id = MO.id AND MO.author_id = C.livechat_operator_id)
+ JOIN mail_message M ON M.res_id = C.id AND M.model = 'mail.channel'
+ LEFT JOIN mail_message MO ON (MO.res_id = C.id AND M.model = 'mail.channel' AND MO.author_id = C.livechat_operator_id)
WHERE C.livechat_channel_id IS NOT NULL
GROUP BY C.id, C.livechat_operator_id
)
diff --git a/addons/im_livechat/static/src/components/discuss/discuss_tests.js b/addons/im_livechat/static/src/components/discuss/discuss_tests.js
index 4cfd207ff1c..36c38f6180a 100644
--- a/addons/im_livechat/static/src/components/discuss/discuss_tests.js
+++ b/addons/im_livechat/static/src/components/discuss/discuss_tests.js
@@ -264,8 +264,8 @@ QUnit.test('livechats are sorted by last message date in the sidebar: most recen
assert.expect(7);
this.data['mail.message'].records.push(
- { id: 11, channel_ids: [11] }, // least recent message due to smaller id
- { id: 12, channel_ids: [12] }, // most recent message due to higher id
+ { id: 11, model: "mail.channel", res_id: 11 }, // least recent message due to smaller id
+ { id: 12, model: "mail.channel", res_id: 12 }, // most recent message due to higher id
);
this.data['mail.channel'].records.push(
{
@@ -345,7 +345,7 @@ QUnit.test('livechats with no messages are sorted by creation date in the sideba
assert.expect(5);
this.data['mail.message'].records.push(
- { id: 13, channel_ids: [13] },
+ { id: 13, model: "mail.channel", res_id: 13 },
);
this.data['mail.channel'].records.push(
{
diff --git a/addons/im_livechat/static/src/legacy/public_livechat.js b/addons/im_livechat/static/src/legacy/public_livechat.js
index 951ebb9ca45..0d3fc1eac08 100644
--- a/addons/im_livechat/static/src/legacy/public_livechat.js
+++ b/addons/im_livechat/static/src/legacy/public_livechat.js
@@ -383,8 +383,9 @@ var LivechatButton = Widget.extend({
attachment_ids: [],
author_id: this._livechat.getOperatorPID(),
body: this.options.default_message,
- channel_ids: [this._livechat.getID()],
date: time.datetime_to_str(new Date()),
+ model: "mail.channel",
+ res_id: this._livechat.getID(),
}, { prepend: true });
}
},
diff --git a/addons/im_livechat/tests/test_get_mail_channel.py b/addons/im_livechat/tests/test_get_mail_channel.py
index 30deee55d4a..fb31ab31121 100644
--- a/addons/im_livechat/tests/test_get_mail_channel.py
+++ b/addons/im_livechat/tests/test_get_mail_channel.py
@@ -87,8 +87,6 @@ class TestGetMailChannel(TransactionCase):
mail_channel = self.livechat_channel._open_livechat_mail_channel('Anonymous')
mail_channels.append(mail_channel)
# send a message to mark this channel as 'active'
- self.env['mail.channel'].browse(mail_channel['id']).write({
- 'channel_message_ids': [(0, 0, {'body': 'cc'})]
- })
+ self.env['mail.channel'].browse(mail_channel['id']).message_post(body='cc')
return mail_channels
diff --git a/addons/im_livechat/views/mail_channel_views.xml b/addons/im_livechat/views/mail_channel_views.xml
index a9e03b819b3..b3245a8e270 100644
--- a/addons/im_livechat/views/mail_channel_views.xml
+++ b/addons/im_livechat/views/mail_channel_views.xml
@@ -24,7 +24,7 @@
-
+
@@ -129,7 +129,7 @@
Sessions
mail.channel
tree,form
- [('livechat_channel_id', 'in', [active_id]), ('channel_message_ids', '!=', False)]
+ [('livechat_channel_id', 'in', [active_id]), ('message_ids', '!=', False)]
{
'search_default_livechat_channel_id': [active_id],
'default_livechat_channel_id': active_id,
diff --git a/addons/mail/data/mail_channel_data.xml b/addons/mail/data/mail_channel_data.xml
index e99f9761f4e..7a8e4b0b628 100644
--- a/addons/mail/data/mail_channel_data.xml
+++ b/addons/mail/data/mail_channel_data.xml
@@ -11,7 +11,6 @@
mail.channel
-
email
Welcome to Odoo!
diff --git a/addons/mail/data/mail_channel_demo.xml b/addons/mail/data/mail_channel_demo.xml
index a38123f80c7..5b1137089c6 100644
--- a/addons/mail/data/mail_channel_demo.xml
+++ b/addons/mail/data/mail_channel_demo.xml
@@ -23,7 +23,6 @@
Selling a training session and selling the products after the training session is more efficient than directly selling a pack with the training session and the products.
]]>
comment
-
@@ -33,7 +32,6 @@
I noted I can not manage efficiently my pipeline when I have more than 50 opportunities in the qualification stage.Any advice on this? How do you organize your activities with more than 50 opportunities?
]]>
comment
-
@@ -44,7 +42,6 @@
comment
-
@@ -53,7 +50,6 @@
mail.channel
-
Great news!
@@ -70,7 +66,6 @@
mail.channel
-
Your monthly meal vouchers arrived. You can get them at the HR's office.
This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.
]]>
comment
@@ -81,7 +76,6 @@
mail.channel
-
Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!]]>
comment
@@ -92,7 +86,6 @@
mail.channel
-
Building B3, second floor on the right :-).]]>
comment
@@ -158,7 +151,6 @@
]]>
comment
-
diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py
index 521661a48c0..00f7b5de214 100644
--- a/addons/mail/models/mail_channel.py
+++ b/addons/mail/models/mail_channel.py
@@ -57,9 +57,6 @@ class Channel(models.Model):
channel_last_seen_partner_ids = fields.One2many(
'mail.channel.partner', 'channel_id', string='Last Seen',
groups='base.group_user')
- channel_message_ids = fields.Many2many(
- 'mail.message', 'mail_message_mail_channel_rel',
- string='Channel Messages')
is_member = fields.Boolean('Is Member', compute='_compute_is_member', compute_sudo=True)
group_ids = fields.Many2many(
'res.groups', string='Auto Subscription',
@@ -571,7 +568,6 @@ class Channel(models.Model):
# When posting a message on a mail channel, manage moderation and postpone notify users
if not msg_vals or msg_vals.get('moderation_status') != 'pending_moderation':
# link message to channel
- message.write({'channel_ids': [(4, cid) for cid in self.ids]})
rdata = super(Channel, self)._notify_thread(message, msg_vals=msg_vals, **kwargs)
message_format_values = message.message_format()[0]
@@ -871,7 +867,7 @@ class Channel(models.Model):
:rtype : list(dict)
"""
self.ensure_one()
- domain = [("channel_ids", "in", self.ids)]
+ domain = ["&", ("model", "=", "mail.channel"), ("res_id", "in", self.ids)]
if last_id:
domain.append(("id", "<", last_id))
return self.env['mail.message'].message_fetch(domain=domain, limit=limit)
@@ -990,7 +986,7 @@ class Channel(models.Model):
kept only for compatibility reasons.
"""
self.ensure_one()
- domain = [('channel_ids', 'in', self.ids)]
+ domain = ["&", ("model", "=", "mail.channel"), ("res_id", "in", self.ids)]
if last_message_id:
domain = expression.AND([domain, [('id', '<=', last_message_id)]])
last_message = self.env['mail.message'].search(domain, order="id DESC", limit=1)
@@ -1032,14 +1028,13 @@ class Channel(models.Model):
def channel_fetched(self):
""" Broadcast the channel_fetched notification to channel members
- :param channel_ids : list of channel id that has been fetched by current user
"""
for channel in self:
- if not channel.channel_message_ids.ids:
+ if not channel.message_ids.ids:
return
if channel.channel_type != 'chat':
return
- last_message_id = channel.channel_message_ids.ids[0] # zero is the index of the last message
+ last_message_id = channel.message_ids.ids[0] # zero is the index of the last message
channel_partner = self.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', self.env.user.partner_id.id)], limit=1)
if channel_partner.fetched_message_id.id == last_message_id:
# last message fetched by user is already up-to-date
@@ -1202,10 +1197,10 @@ class Channel(models.Model):
return []
self.flush()
self.env.cr.execute("""
- SELECT mail_channel_id AS id, MAX(mail_message_id) AS message_id
- FROM mail_message_mail_channel_rel
- WHERE mail_channel_id IN %s
- GROUP BY mail_channel_id
+ SELECT res_id AS id, MAX(id) AS message_id
+ FROM mail_message
+ WHERE model = 'mail.channel' AND res_id IN %s
+ GROUP BY res_id
""", (tuple(self.ids),))
return self.env.cr.dictfetchall()
@@ -1236,11 +1231,14 @@ class Channel(models.Model):
def _send_transient_message(self, partner_to, content):
""" Notifies partner_to that a message (not stored in DB) has been
written in this channel """
- self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', partner_to.id), {
- 'body': "" + content + "",
- 'channel_ids': [self.id],
- 'info': 'transient_message',
- })
+ self.env['bus.bus'].sendone(
+ (self._cr.dbname, 'res.partner', partner_to.id),
+ {'body': "" + content + "",
+ 'info': 'transient_message',
+ 'model': self._name,
+ 'res_id': self.id,
+ }
+ )
def _define_command_help(self):
return {'help': _("Show a helper message")}
diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index b9dd993437a..a586fd2bc3b 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -138,8 +138,6 @@ class Message(models.Model):
has_error = fields.Boolean(
'Has error', compute='_compute_has_error', search='_search_has_error',
help='Has error')
- channel_ids = fields.Many2many(
- 'mail.channel', 'mail_message_mail_channel_rel', string='Channels')
# notifications
notification_ids = fields.One2many(
'mail.notification', 'mail_message_id', 'Notifications',
@@ -292,47 +290,35 @@ class Message(models.Model):
return ids
pid = self.env.user.partner_id.id
- author_ids, partner_ids, channel_ids, allowed_ids = set([]), set([]), set([]), set([])
+ author_ids, partner_ids, allowed_ids = set([]), set([]), set([])
model_ids = {}
# check read access rights before checking the actual rules on the given ids
super(Message, self.with_user(access_rights_uid or self._uid)).check_access_rights('read')
- self.flush(['model', 'res_id', 'author_id', 'message_type', 'partner_ids', 'channel_ids'])
+ self.flush(['model', 'res_id', 'author_id', 'message_type', 'partner_ids'])
self.env['mail.notification'].flush(['mail_message_id', 'res_partner_id'])
- self.env['mail.channel'].flush(['channel_message_ids'])
- self.env['mail.channel.partner'].flush(['channel_id', 'partner_id'])
for sub_ids in self._cr.split_for_in_conditions(ids):
self._cr.execute("""
SELECT DISTINCT m.id, m.model, m.res_id, m.author_id, m.message_type,
- COALESCE(partner_rel.res_partner_id, needaction_rel.res_partner_id),
- channel_partner.channel_id as channel_id
+ COALESCE(partner_rel.res_partner_id, needaction_rel.res_partner_id)
FROM "%s" m
LEFT JOIN "mail_message_res_partner_rel" partner_rel
ON partner_rel.mail_message_id = m.id AND partner_rel.res_partner_id = %%(pid)s
LEFT JOIN "mail_notification" needaction_rel
ON needaction_rel.mail_message_id = m.id AND needaction_rel.res_partner_id = %%(pid)s
- LEFT JOIN "mail_message_mail_channel_rel" channel_rel
- ON channel_rel.mail_message_id = m.id
- LEFT JOIN "mail_channel" channel
- ON channel.id = channel_rel.mail_channel_id
- LEFT JOIN "mail_channel_partner" channel_partner
- ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = %%(pid)s
-
WHERE m.id = ANY (%%(ids)s)""" % self._table, dict(pid=pid, ids=list(sub_ids)))
- for id, rmod, rid, author_id, message_type, partner_id, channel_id in self._cr.fetchall():
+ for msg_id, rmod, rid, author_id, message_type, partner_id in self._cr.fetchall():
if author_id == pid:
- author_ids.add(id)
+ author_ids.add(msg_id)
elif partner_id == pid:
- partner_ids.add(id)
- elif channel_id:
- channel_ids.add(id)
+ partner_ids.add(msg_id)
elif rmod and rid and message_type != 'user_notification':
- model_ids.setdefault(rmod, {}).setdefault(rid, set()).add(id)
+ model_ids.setdefault(rmod, {}).setdefault(rid, set()).add(msg_id)
allowed_ids = self._find_allowed_doc_ids(model_ids)
- final_ids = author_ids | partner_ids | channel_ids | allowed_ids
+ final_ids = author_ids | partner_ids | allowed_ids
if count:
return len(final_ids)
@@ -363,7 +349,6 @@ class Message(models.Model):
- author_id == pid, uid is the author OR
- uid is in the recipients (partner_ids) OR
- uid has been notified (needaction) OR
- - uid is member of a listern channel (channel_ids.partner_ids) OR
- uid have read access to the related document if model, res_id
- otherwise: raise
- create: if
@@ -417,31 +402,24 @@ class Message(models.Model):
# Read mail_message.ids to have their values
message_values = dict((message_id, {}) for message_id in self.ids)
- self.flush(['model', 'res_id', 'author_id', 'parent_id', 'moderation_status', 'message_type', 'partner_ids', 'channel_ids'])
+ self.flush(['model', 'res_id', 'author_id', 'parent_id', 'moderation_status', 'message_type', 'partner_ids'])
self.env['mail.notification'].flush(['mail_message_id', 'res_partner_id'])
- self.env['mail.channel'].flush(['channel_message_ids', 'moderator_ids'])
- self.env['mail.channel.partner'].flush(['channel_id', 'partner_id'])
+ self.env['mail.channel'].flush(['moderator_ids'])
self.env['res.users'].flush(['moderation_channel_ids'])
if operation == 'read':
self._cr.execute("""
SELECT DISTINCT m.id, m.model, m.res_id, m.author_id, m.parent_id,
COALESCE(partner_rel.res_partner_id, needaction_rel.res_partner_id),
- channel_partner.channel_id as channel_id, m.moderation_status,
+ m.moderation_status,
m.message_type as message_type
FROM "%s" m
LEFT JOIN "mail_message_res_partner_rel" partner_rel
ON partner_rel.mail_message_id = m.id AND partner_rel.res_partner_id = %%(pid)s
LEFT JOIN "mail_notification" needaction_rel
ON needaction_rel.mail_message_id = m.id AND needaction_rel.res_partner_id = %%(pid)s
- LEFT JOIN "mail_message_mail_channel_rel" channel_rel
- ON channel_rel.mail_message_id = m.id
- LEFT JOIN "mail_channel" channel
- ON channel.id = channel_rel.mail_channel_id
- LEFT JOIN "mail_channel_partner" channel_partner
- ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = %%(pid)s
WHERE m.id = ANY (%%(ids)s)""" % self._table, dict(pid=self.env.user.partner_id.id, ids=self.ids))
- for mid, rmod, rid, author_id, parent_id, partner_id, channel_id, moderation_status, message_type in self._cr.fetchall():
+ for mid, rmod, rid, author_id, parent_id, partner_id, moderation_status, message_type in self._cr.fetchall():
message_values[mid] = {
'model': rmod,
'res_id': rid,
@@ -449,32 +427,26 @@ class Message(models.Model):
'parent_id': parent_id,
'moderation_status': moderation_status,
'moderator_id': False,
- 'notified': any((message_values[mid].get('notified'), partner_id, channel_id)),
+ 'notified': any((message_values[mid].get('notified'), partner_id)),
'message_type': message_type,
}
elif operation == 'write':
self._cr.execute("""
SELECT DISTINCT m.id, m.model, m.res_id, m.author_id, m.parent_id, m.moderation_status,
COALESCE(partner_rel.res_partner_id, needaction_rel.res_partner_id),
- channel_partner.channel_id as channel_id, channel_moderator_rel.res_users_id as moderator_id,
+ channel_moderator_rel.res_users_id as moderator_id,
m.message_type as message_type
FROM "%s" m
LEFT JOIN "mail_message_res_partner_rel" partner_rel
ON partner_rel.mail_message_id = m.id AND partner_rel.res_partner_id = %%(pid)s
LEFT JOIN "mail_notification" needaction_rel
ON needaction_rel.mail_message_id = m.id AND needaction_rel.res_partner_id = %%(pid)s
- LEFT JOIN "mail_message_mail_channel_rel" channel_rel
- ON channel_rel.mail_message_id = m.id
- LEFT JOIN "mail_channel" channel
- ON channel.id = channel_rel.mail_channel_id
- LEFT JOIN "mail_channel_partner" channel_partner
- ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = %%(pid)s
LEFT JOIN "mail_channel" moderated_channel
ON m.moderation_status = 'pending_moderation' AND m.res_id = moderated_channel.id
LEFT JOIN "mail_channel_moderator_rel" channel_moderator_rel
ON channel_moderator_rel.mail_channel_id = moderated_channel.id AND channel_moderator_rel.res_users_id = %%(uid)s
WHERE m.id = ANY (%%(ids)s)""" % self._table, dict(pid=self.env.user.partner_id.id, uid=self.env.user.id, ids=self.ids))
- for mid, rmod, rid, author_id, parent_id, moderation_status, partner_id, channel_id, moderator_id, message_type in self._cr.fetchall():
+ for mid, rmod, rid, author_id, parent_id, moderation_status, partner_id, moderator_id, message_type in self._cr.fetchall():
message_values[mid] = {
'model': rmod,
'res_id': rid,
@@ -482,7 +454,7 @@ class Message(models.Model):
'parent_id': parent_id,
'moderation_status': moderation_status,
'moderator_id': moderator_id,
- 'notified': any((message_values[mid].get('notified'), partner_id, channel_id)),
+ 'notified': any((message_values[mid].get('notified'), partner_id)),
'message_type': message_type,
}
elif operation == 'create':
@@ -583,17 +555,11 @@ class Message(models.Model):
# TDE: probably clean me
parent_ids = [message.get('parent_id') for message in message_values.values()
if message.get('parent_id')]
- self._cr.execute("""SELECT DISTINCT m.id, partner_rel.res_partner_id, channel_partner.partner_id FROM "%s" m
+ self._cr.execute("""SELECT DISTINCT m.id, partner_rel.res_partner_id FROM "%s" m
LEFT JOIN "mail_message_res_partner_rel" partner_rel
ON partner_rel.mail_message_id = m.id AND partner_rel.res_partner_id = (%%s)
- LEFT JOIN "mail_message_mail_channel_rel" channel_rel
- ON channel_rel.mail_message_id = m.id
- LEFT JOIN "mail_channel" channel
- ON channel.id = channel_rel.mail_channel_id
- LEFT JOIN "mail_channel_partner" channel_partner
- ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = (%%s)
- WHERE m.id = ANY (%%s)""" % self._table, (self.env.user.partner_id.id, self.env.user.partner_id.id, parent_ids,))
- not_parent_ids = [mid[0] for mid in self._cr.fetchall() if any([mid[1], mid[2]])]
+ WHERE m.id = ANY (%%s)""" % self._table, (self.env.user.partner_id.id, parent_ids,))
+ not_parent_ids = [mid[0] for mid in self._cr.fetchall() if mid[1]]
notified_ids += [mid for mid, message in message_values.items()
if message.get('parent_id') in not_parent_ids]
@@ -774,30 +740,16 @@ class Message(models.Model):
if not notifications:
return
- # notifies changes in messages through the bus. To minimize the number of
- # notifications, we need to group the messages depending on their channel_ids
- groups = []
- messages = notifications.mapped('mail_message_id')
- current_channel_ids = messages[0].channel_ids
- current_group = []
- for record in messages:
- if record.channel_ids == current_channel_ids:
- current_group.append(record.id)
- else:
- groups.append((current_group, current_channel_ids))
- current_group = [record.id]
- current_channel_ids = record.channel_ids
-
- groups.append((current_group, current_channel_ids))
- current_group = [record.id]
- current_channel_ids = record.channel_ids
-
notifications.write({'is_read': True})
- for (msg_ids, channel_ids) in groups:
- # channel_ids in result is deprecated and will be removed in a future version
- notification = {'type': 'mark_as_read', 'message_ids': msg_ids, 'channel_ids': [c.id for c in channel_ids], 'needaction_inbox_counter': self.env.user.partner_id.get_needaction_count()}
- self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', partner_id.id), notification)
+ # notifies changes in messages through the bus.
+ self.env['bus.bus'].sendone(
+ (self._cr.dbname, 'res.partner', partner_id.id),
+ {'type': 'mark_as_read',
+ 'message_ids': notifications.mapped('mail_message_id').ids,
+ 'needaction_inbox_counter': self.env.user.partner_id.get_needaction_count()
+ }
+ )
@api.model
def unstar_all(self):
@@ -1127,7 +1079,6 @@ class Message(models.Model):
'author_id': (3, u'Administrator'),
'email_from': 'sacha@pokemon.com' # email address or False
'subtype_id': (1, u'Discussions'),
- 'channel_ids': [], # list of channel ids
'date': '2015-06-30 08:22:33',
'partner_ids': [[7, "Sacha Du Bourg-Palette"]], # list of partner name_get
'message_type': u'comment',
@@ -1164,7 +1115,7 @@ class Message(models.Model):
'id', 'body', 'date', 'author_id', 'email_from', # base message fields
'message_type', 'subtype_id', 'subject', # message specific
'model', 'res_id', 'record_name', # document related
- 'channel_ids', 'partner_ids', # recipients
+ 'partner_ids', # recipients
'starred_partner_ids', # list of partner ids for whom the message is starred
'moderation_status',
]
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 35afe3d737e..43447fa1902 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -160,10 +160,8 @@ class MailThread(models.AbstractModel):
if self.ids:
# search for unread messages, directly in SQL to improve performances
self._cr.execute(""" SELECT msg.res_id FROM mail_message msg
- RIGHT JOIN mail_message_mail_channel_rel rel
- ON rel.mail_message_id = msg.id
RIGHT JOIN mail_channel_partner cp
- ON (cp.channel_id = rel.mail_channel_id AND cp.partner_id = %s AND
+ ON (cp.channel_id = msg.res_id AND cp.partner_id = %s AND
(cp.seen_message_id IS NULL OR cp.seen_message_id < msg.id))
WHERE msg.model = %s AND msg.res_id = ANY(%s) AND
msg.message_type != 'user_notification' AND
diff --git a/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js b/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js
index 0ca449a2828..d336f17235d 100644
--- a/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js
+++ b/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js
@@ -1013,7 +1013,8 @@ QUnit.test('[technical] chat window: scroll conservation on toggle home menu', a
for (let i = 0; i < 10; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
}
await this.start();
@@ -1784,7 +1785,8 @@ QUnit.test('chat window with a thread: keep scroll position in message list on f
for (let i = 0; i < 10; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
}
await this.start();
@@ -1866,7 +1868,8 @@ QUnit.test('chat window should scroll to the newly posted message just after pos
for (let i = 0; i < 10; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
}
await this.start();
@@ -2023,7 +2026,8 @@ QUnit.test('[technical] chat window with a thread: keep scroll position in messa
for (let i = 0; i < 10; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
}
await this.start();
@@ -2121,7 +2125,7 @@ QUnit.test('chat window does not fetch messages if hidden', async function (asse
* 2 visible chat windows + hidden menu:
* 10 + 325 + 5 + 325 + 10 + 200 + 5 = 875 < 900
*/
- assert.expect(14);
+ assert.expect(17);
// 3 channels are expected to be found in the messaging menu, each with a
// random unique id that will be referenced in the test
@@ -2153,10 +2157,13 @@ QUnit.test('chat window does not fetch messages if hidden', async function (asse
},
mockRPC(route, args) {
if (args.method === 'message_fetch') {
- // domain should be like [['channel_id', 'in', [X]]] with X the channel id
- const channel_ids = args.kwargs.domain[0][2];
- assert.strictEqual(channel_ids.length, 1, "messages should be fetched channel per channel");
- assert.step(`rpc:message_fetch:${channel_ids[0]}`);
+ // domain should be like [['message_type', '=', 'user_notification'], ['model', '=', 'mail.channel'], ['res_id', '=', X]] with X the channel id
+ const channel_model = args.kwargs.domain[1][2];
+ const channel_id_field = args.kwargs.domain[2][0];
+ const channel_id = args.kwargs.domain[2][2];
+ assert.strictEqual(channel_model, "mail.channel", "messages should be on channel thread model");
+ assert.strictEqual(channel_id_field, "res_id", "messages should be fetched channel per channel using res_id field");
+ assert.step(`rpc:message_fetch:${channel_id}`);
}
return this._super(...arguments);
},
@@ -2243,7 +2250,6 @@ QUnit.test('new message separator is shown in a chat window of a chat on receivi
];
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [10],
model: 'mail.channel',
res_id: 10,
});
@@ -2348,7 +2354,6 @@ QUnit.test('focusing a chat window of a chat should make new message separator d
);
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [10],
model: 'mail.channel',
res_id: 10,
});
diff --git a/addons/mail/static/src/components/discuss/tests/discuss_domain_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_domain_tests.js
index 26431207467..92c2280a245 100644
--- a/addons/mail/static/src/components/discuss/tests/discuss_domain_tests.js
+++ b/addons/mail/static/src/components/discuss/tests/discuss_domain_tests.js
@@ -82,10 +82,12 @@ QUnit.test('discuss should keep filter domain on changing thread', async functio
this.data['mail.channel'].records.push({ id: 20 });
this.data['mail.message'].records.push({
body: "test",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
}, {
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
await this.start();
const channel = this.env.models['mail.thread'].findFromIdentifyingData({
diff --git a/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js
index 63b524eb81b..2ebbd13b53b 100644
--- a/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js
+++ b/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js
@@ -555,7 +555,6 @@ QUnit.test('subject should not be shown when subject is the same as the thread n
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
@@ -579,7 +578,6 @@ QUnit.test('subject should not be shown when subject is the same as the thread n
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
@@ -603,7 +601,6 @@ QUnit.test('subject should not be shown when subject differs from thread name on
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
@@ -627,7 +624,6 @@ QUnit.test('subject should not be shown when subject differs from thread name on
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
@@ -651,7 +647,6 @@ QUnit.test('subject should be shown when the thread name has an extra prefix com
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
@@ -675,7 +670,6 @@ QUnit.test('subject should not be shown when subject differs from thread name on
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
@@ -699,7 +693,6 @@ QUnit.test('subject should not be shown when subject differs from thread name on
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
needaction: true,
diff --git a/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js
index c4c53cb568e..fc29d5ff331 100644
--- a/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js
+++ b/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js
@@ -988,7 +988,6 @@ QUnit.test('as moderator, new pending moderation message posted by someone else'
const messageData = {
author_id: [10, 'john doe'], // random id, different than current partner
body: "not empty",
- channel_ids: [], // server do NOT return channel_id of the message if pending moderation
id: 1, // random unique id
model: 'mail.channel', // expected value to link message to channel
moderation_status: 'pending_moderation', // message is expected to be pending
diff --git a/addons/mail/static/src/components/discuss/tests/discuss_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_tests.js
index dc2005e5ac7..2a02984bb61 100644
--- a/addons/mail/static/src/components/discuss/tests/discuss_tests.js
+++ b/addons/mail/static/src/components/discuss/tests/discuss_tests.js
@@ -520,8 +520,9 @@ QUnit.test('sidebar: channel rendering with needaction counter', async function
// expected needaction message
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20], // link message to channel
id: 100, // random unique id, useful to link notification
+ model: "mail.channel",
+ res_id: 20,
});
// expected needaction notification
this.data['mail.notification'].records.push({
@@ -1194,7 +1195,6 @@ QUnit.test('load single message from channel initially', async function (assert)
this.data['mail.channel'].records.push({ id: 20 });
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
date: "2019-04-20 10:00:00",
id: 100,
model: 'mail.channel',
@@ -1215,7 +1215,11 @@ QUnit.test('load single message from channel initially', async function (assert)
);
assert.deepEqual(
args.kwargs.domain,
- [["channel_ids", "in", [20]]],
+ [
+ ["message_type", "!=", "user_notification"],
+ ["model", "=", "mail.channel"],
+ ["res_id", "=", 20]
+ ],
"should fetch messages from channel"
);
}
@@ -1288,7 +1292,6 @@ QUnit.test('basic rendering of message', async function (assert) {
this.data['mail.message'].records.push({
author_id: 11,
body: "body
",
- channel_ids: [20],
date: "2019-04-20 10:00:00",
id: 100,
model: 'mail.channel',
@@ -1390,7 +1393,6 @@ QUnit.test('basic rendering of squashed message', async function (assert) {
{
author_id: 11, // must be same author as other message
body: "body1
", // random body, set for consistency
- channel_ids: [20], // to link message to channel
date: "2019-04-20 10:00:00", // date must be within 1 min from other message
id: 100, // random unique id, will be referenced in the test
message_type: 'comment', // must be a squash-able type-
@@ -1400,7 +1402,6 @@ QUnit.test('basic rendering of squashed message', async function (assert) {
{
author_id: 11, // must be same author as other message
body: "body2
", // random body, will be asserted in the test
- channel_ids: [20], // to link message to channel
date: "2019-04-20 10:00:30", // date must be within 1 min from other message
id: 101, // random unique id, will be referenced in the test
message_type: 'comment', // must be a squash-able type
@@ -1498,7 +1499,6 @@ QUnit.test('inbox messages are never squashed', async function (assert) {
{
author_id: 11, // must be same author as other message
body: "body1
", // random body, set for consistency
- channel_ids: [20], // to link message to channel
date: "2019-04-20 10:00:00", // date must be within 1 min from other message
id: 100, // random unique id, will be referenced in the test
message_type: 'comment', // must be a squash-able type-
@@ -1510,7 +1510,6 @@ QUnit.test('inbox messages are never squashed', async function (assert) {
{
author_id: 11, // must be same author as other message
body: "body2
", // random body, will be asserted in the test
- channel_ids: [20], // to link message to channel
date: "2019-04-20 10:00:30", // date must be within 1 min from other message
id: 101, // random unique id, will be referenced in the test
message_type: 'comment', // must be a squash-able type
@@ -1563,7 +1562,6 @@ QUnit.test('load all messages from channel initially, less than fetch limit (29
for (let i = 28; i >= 0; i--) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
date: "2019-04-20 10:00:00",
model: 'mail.channel',
res_id: 20,
@@ -1623,7 +1621,6 @@ QUnit.test('load more messages from channel', async function (assert) {
for (let i = 0; i < 40; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
date: "2019-04-20 10:00:00",
model: 'mail.channel',
res_id: 20,
@@ -1695,7 +1692,6 @@ QUnit.test('auto-scroll to bottom of thread', async function (assert) {
for (let i = 1; i <= 25; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
model: 'mail.channel',
res_id: 20,
});
@@ -1743,7 +1739,6 @@ QUnit.test('load more messages from channel (auto-load on scroll)', async functi
for (let i = 0; i < 40; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
model: 'mail.channel',
res_id: 20,
});
@@ -1831,7 +1826,6 @@ QUnit.test('new messages separator [REQUIRE FOCUS]', async function (assert) {
for (let i = 1; i <= 25; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
id: 100 + i, // for setting proper value for seen_message_id
model: 'mail.channel',
res_id: 20,
@@ -1956,7 +1950,6 @@ QUnit.test('restore thread scroll position', async function (assert) {
for (let i = 1; i <= 25; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [11],
model: 'mail.channel',
res_id: 11,
});
@@ -1964,7 +1957,6 @@ QUnit.test('restore thread scroll position', async function (assert) {
for (let i = 1; i <= 24; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [12],
model: 'mail.channel',
res_id: 12,
});
@@ -2114,200 +2106,6 @@ QUnit.test('restore thread scroll position', async function (assert) {
);
});
-QUnit.test('message origin redirect to channel', async function (assert) {
- assert.expect(15);
-
- // channels expected to be rendered, with random unique id that will be referenced in the test
- this.data['mail.channel'].records.push({ id: 11 }, { id: 12 });
- this.data['mail.message'].records.push(
- {
- body: "not empty",
- channel_ids: [11, 12],
- id: 100,
- model: 'mail.channel',
- record_name: "channel11",
- res_id: 11,
- },
- {
- body: "not empty",
- channel_ids: [11, 12],
- id: 101,
- model: 'mail.channel',
- record_name: "channel12",
- res_id: 12,
- }
- );
- await this.start({
- discuss: {
- params: {
- default_active_id: 'mail.channel_11',
- },
- },
- });
- assert.strictEqual(
- document.querySelectorAll('.o_Discuss_thread .o_Message').length,
- 2,
- "should have 2 messages"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId
- }"]
- `).length,
- 1,
- "should have message1 (Id 100)"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- `).length,
- 1,
- "should have message2 (Id 101)"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId
- }"]
- .o_Message_originThread
- `).length,
- 0,
- "message1 should not have origin part in channel11 (same origin as channel)"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- .o_Message_originThread
- `).length,
- 1,
- "message2 should have origin part (origin is channel12 !== channel11)"
- );
- assert.strictEqual(
- document.querySelector(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- .o_Message_originThread
- `).textContent.trim(),
- "(from #channel12)",
- "message2 should display name of origin channel"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- .o_Message_originThreadLink
- `).length,
- 1,
- "message2 should have link to redirect to origin"
- );
-
- // click on origin link of message2 (= channel12)
- await afterNextRender(() =>
- document.querySelector(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- .o_Message_originThreadLink
- `).click()
- );
- assert.ok(
- document.querySelector(`
- .o_DiscussSidebar_groupChannel
- .o_DiscussSidebar_item[data-thread-local-id="${
- this.env.models['mail.thread'].findFromIdentifyingData({
- id: 12,
- model: 'mail.channel',
- }).localId
- }"]
- .o_DiscussSidebarItem_activeIndicator
- `).classList.contains('o-item-active'),
- "channel12 should be active channel on redirect from discuss app"
- );
- assert.strictEqual(
- document.querySelectorAll(`.o_Discuss_thread .o_Message`).length,
- 2,
- "should have 2 messages"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId
- }"]
- `).length,
- 1,
- "should have message1 (Id 100)"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- `).length,
- 1,
- "should have message2 (Id 101)"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId
- }"]
- .o_Message_originThread
- `).length,
- 1,
- "message1 should have origin thread part (= channel11 !== channel12)"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 101 }).localId
- }"]
- .o_Message_originThread
- `).length,
- 0,
- "message2 should not have origin thread part in channel12 (same as current channel)"
- );
- assert.strictEqual(
- document.querySelector(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId
- }"]
- .o_Message_originThread
- `).textContent.trim(),
- "(from #channel11)",
- "message1 should display name of origin channel"
- );
- assert.strictEqual(
- document.querySelectorAll(`
- .o_Discuss_thread
- .o_Message[data-message-local-id="${
- this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId
- }"]
- .o_Message_originThreadLink
- `).length,
- 1,
- "message1 should have link to redirect to origin channel"
- );
-});
-
QUnit.test('redirect to author (open chat)', async function (assert) {
assert.expect(7);
@@ -2333,7 +2131,6 @@ QUnit.test('redirect to author (open chat)', async function (assert) {
{
author_id: 7,
body: "not empty",
- channel_ids: [1],
id: 100,
model: 'mail.channel',
res_id: 1,
@@ -2572,7 +2369,6 @@ QUnit.test('inbox: mark all messages as read', async function (assert) {
// first expected message
{
body: "not empty",
- channel_ids: [20], // link message to channel
id: 100, // random unique id, useful to link notification
model: 'mail.channel',
// needaction needs to be set here for message_fetch domain, because
@@ -2583,7 +2379,6 @@ QUnit.test('inbox: mark all messages as read', async function (assert) {
// second expected message
{
body: "not empty",
- channel_ids: [20], // link message to channel
id: 101, // random unique id, useful to link notification
model: 'mail.channel',
// needaction needs to be set here for message_fetch domain, because
@@ -2742,7 +2537,6 @@ QUnit.test('toggle_star message', async function (assert) {
this.data['mail.channel'].records.push({ id: 20 });
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
id: 100,
model: 'mail.channel',
res_id: 20,
@@ -3326,7 +3120,6 @@ QUnit.test('mark channel as seen on last message visible [REQUIRE FOCUS]', async
this.data['mail.message'].records.push({
id: 12,
body: "not empty",
- channel_ids: [10],
model: 'mail.channel',
res_id: 10,
});
@@ -3645,7 +3438,6 @@ QUnit.test('load recent messages from thread (already loaded some old messages)'
for (let i = 0; i < 50; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20], // id of related channel
id: 100 + i, // random unique id, will be referenced in the test
model: 'mail.channel', // expected value to link message to channel
// needaction needs to be set here for message_fetch domain, because
@@ -4105,7 +3897,6 @@ QUnit.test('receive new chat message: out of odoo focus (notification, channel)'
// simulate receiving a new message with odoo focused
await afterNextRender(() => {
const messageData = {
- channel_ids: [20],
id: 126,
model: 'mail.channel',
res_id: 20,
@@ -4144,7 +3935,6 @@ QUnit.test('receive new chat message: out of odoo focus (notification, chat)', a
// simulate receiving a new message with odoo focused
await afterNextRender(() => {
const messageData = {
- channel_ids: [10],
id: 126,
model: 'mail.channel',
res_id: 10,
@@ -4196,7 +3986,6 @@ QUnit.test('receive new chat messages: out of odoo focus (tab title)', async fun
// simulate receiving a new message in chat 20 with odoo focused
await afterNextRender(() => {
const messageData1 = {
- channel_ids: [20],
id: 126,
model: 'mail.channel',
res_id: 20,
@@ -4209,7 +3998,6 @@ QUnit.test('receive new chat messages: out of odoo focus (tab title)', async fun
// simulate receiving a new message in chat 10 with odoo focused
await afterNextRender(() => {
const messageData2 = {
- channel_ids: [10],
id: 127,
model: 'mail.channel',
res_id: 10,
@@ -4222,7 +4010,6 @@ QUnit.test('receive new chat messages: out of odoo focus (tab title)', async fun
// simulate receiving another new message in chat 10 with odoo focused
await afterNextRender(() => {
const messageData3 = {
- channel_ids: [10],
id: 128,
model: 'mail.channel',
res_id: 10,
@@ -4355,12 +4142,14 @@ QUnit.test('mark channel as seen if last message is visible when switching chann
);
this.data['mail.message'].records.push({
body: 'oldest message',
- channel_ids: [10],
id: 10,
+ model: "mail.channel",
+ res_id: 10,
}, {
body: 'newest message',
- channel_ids: [11],
id: 11,
+ model: "mail.channel",
+ res_id: 11,
});
await this.start({
discuss: {
diff --git a/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js b/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
index d049ab7a5b3..af66bbba236 100644
--- a/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
+++ b/addons/mail/static/src/components/messaging_menu/messaging_menu_tests.js
@@ -504,7 +504,6 @@ QUnit.test('channel preview: basic rendering', async function (assert) {
this.data['mail.message'].records.push({
author_id: 7, // not current partner, will be asserted in the test
body: "test
", // random body, will be asserted in the test
- channel_ids: [20], // id of related channel
model: 'mail.channel', // necessary to link message to channel
res_id: 20, // id of related channel
});
@@ -597,12 +596,10 @@ QUnit.test('filtered previews', async function (assert) {
);
this.data['mail.message'].records.push(
{
- channel_ids: [10], // id of related channel
model: 'mail.channel', // to link message to channel
res_id: 10, // id of related channel
},
{
- channel_ids: [20], // id of related channel
model: 'mail.channel', // to link message to channel
res_id: 20, // id of related channel
},
@@ -781,7 +778,8 @@ QUnit.test('no code injection in message body preview', async function (assert)
this.data['mail.channel'].records.push({ id: 11 });
this.data['mail.message'].records.push({
body: "&shoulnotberaised
",
- channel_ids: [11],
+ model: "mail.channel",
+ res_id: 11,
});
await this.start();
@@ -822,7 +820,8 @@ QUnit.test('no code injection in message body preview from sanitized message', a
this.data['mail.channel'].records.push({ id: 11 });
this.data['mail.message'].records.push({
body: "<em>&shoulnotberaised</em><script>throw new Error('CodeInjectionError');</script>
",
- channel_ids: [11],
+ model: "mail.channel",
+ res_id: 11,
});
await this.start();
@@ -863,7 +862,8 @@ QUnit.test('
tags in message body preview are transformed in spaces', async
this.data['mail.channel'].records.push({ id: 11 });
this.data['mail.message'].records.push({
body: "a
b
c
d
",
- channel_ids: [11],
+ model: "mail.channel",
+ res_id: 11,
});
await this.start();
diff --git a/addons/mail/static/src/components/notification_list/notification_list_tests.js b/addons/mail/static/src/components/notification_list/notification_list_tests.js
index 24df5b22cdf..3cf756d4fe2 100644
--- a/addons/mail/static/src/components/notification_list/notification_list_tests.js
+++ b/addons/mail/static/src/components/notification_list/notification_list_tests.js
@@ -53,14 +53,12 @@ QUnit.test('marked as read thread notifications are ordered by last message date
);
this.data['mail.message'].records.push(
{
- channel_ids: [100],
date: "2019-01-01 00:00:00",
id: 42,
model: 'mail.channel',
res_id: 100,
},
{
- channel_ids: [200],
date: "2020-01-01 00:00:00",
id: 43,
model: 'mail.channel',
@@ -97,14 +95,12 @@ QUnit.test('thread notifications are re-ordered on receiving a new message', asy
);
this.data['mail.message'].records.push(
{
- channel_ids: [100],
date: "2019-01-01 00:00:00",
id: 42,
model: 'mail.channel',
res_id: 100,
},
{
- channel_ids: [200],
date: "2020-01-01 00:00:00",
id: 43,
model: 'mail.channel',
@@ -124,7 +120,6 @@ QUnit.test('thread notifications are re-ordered on receiving a new message', asy
const messageData = {
author_id: [7, "Demo User"],
body: "New message !
",
- channel_ids: [100],
date: "2020-03-23 10:00:00",
id: 44,
message_type: 'comment',
diff --git a/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js b/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js
index ca1fe22c785..3051f318ea9 100644
--- a/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js
+++ b/addons/mail/static/src/components/thread_needaction_preview/thread_needaction_preview_tests.js
@@ -361,49 +361,6 @@ QUnit.test('preview should display last needaction message preview even if there
);
});
-QUnit.test('needaction preview should only show on its origin thread', async function (assert) {
- assert.expect(2);
-
- this.data['mail.channel'].records.push({ id: 12 });
- this.data['mail.message'].records.push({
- channel_ids: [12],
- id: 21,
- model: 'res.partner',
- needaction: true,
- needaction_partner_ids: [this.data.currentPartnerId],
- res_id: 11,
- });
- this.data['mail.notification'].records.push({
- mail_message_id: 21,
- notification_status: 'sent',
- notification_type: 'inbox',
- res_partner_id: this.data.currentPartnerId,
- });
- await this.start({ hasMessagingMenu: true });
- await afterNextRender(() => this.afterEvent({
- eventName: 'o-thread-cache-loaded-messages',
- func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
- message: "should wait until inbox loaded initial needaction messages",
- predicate: ({ threadCache }) => {
- return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
- },
- }));
- assert.containsOnce(
- document.body,
- '.o_ThreadNeedactionPreview',
- "should have only one preview"
- );
- const thread = this.env.models['mail.thread'].findFromIdentifyingData({
- id: 11,
- model: 'res.partner',
- });
- assert.containsOnce(
- document.body,
- `.o_ThreadNeedactionPreview[data-thread-local-id="${thread.localId}"]`,
- "preview should be on the origin thread"
- );
-});
-
QUnit.test('chat window header should not have unread counter for non-channel thread', async function (assert) {
assert.expect(2);
diff --git a/addons/mail/static/src/components/thread_preview/thread_preview_tests.js b/addons/mail/static/src/components/thread_preview/thread_preview_tests.js
index 981abf6bca6..bc33f7cd0f8 100644
--- a/addons/mail/static/src/components/thread_preview/thread_preview_tests.js
+++ b/addons/mail/static/src/components/thread_preview/thread_preview_tests.js
@@ -47,7 +47,6 @@ QUnit.test('mark as read', async function (assert) {
message_unread_counter: 1,
});
this.data['mail.message'].records.push({
- channel_ids: [11],
id: 100,
model: 'mail.channel',
res_id: 11,
diff --git a/addons/mail/static/src/components/thread_view/thread_view_tests.js b/addons/mail/static/src/components/thread_view/thread_view_tests.js
index 87d33c89548..a3e1f15eb1a 100644
--- a/addons/mail/static/src/components/thread_view/thread_view_tests.js
+++ b/addons/mail/static/src/components/thread_view/thread_view_tests.js
@@ -106,7 +106,6 @@ QUnit.test('message list desc order', async function (assert) {
for (let i = 0; i <= 60; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
});
@@ -204,7 +203,6 @@ QUnit.test('message list asc order', async function (assert) {
for (let i = 0; i <= 60; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
});
@@ -466,7 +464,6 @@ QUnit.test('show message subject if thread is mailing channel', async function (
});
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [100],
model: 'mail.channel',
res_id: 100,
subject: "Salutations, voyageur",
@@ -513,8 +510,9 @@ QUnit.test('[technical] new messages separator on posting message', async functi
}];
this.data['mail.message'].records.push({
body: "first message",
- channel_ids: [20],
id: 10,
+ model: "mail.channel",
+ res_id: 20,
});
await this.start();
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
@@ -582,8 +580,9 @@ QUnit.test('new messages separator on receiving new message [REQUIRE FOCUS]', as
});
this.data['mail.message'].records.push({
body: "blah",
- channel_ids: [20],
id: 1,
+ model: "mail.channel",
+ res_id: 20,
});
await this.start();
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
@@ -724,7 +723,6 @@ QUnit.test('basic rendering of canceled notification', async function (assert) {
this.data['res.partner'].records.push({ id: 12, name: "Someone" });
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [11],
id: 10,
message_type: 'email',
model: 'mail.channel',
@@ -825,7 +823,8 @@ QUnit.test('should scroll to bottom on receiving new message if the list is init
for (let i = 0; i <= 10; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
}
await this.start();
@@ -896,7 +895,8 @@ QUnit.test('should not scroll on receiving new message if the list is initially
for (let i = 0; i <= 10; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [20],
+ model: "mail.channel",
+ res_id: 20,
});
}
await this.start();
@@ -973,8 +973,9 @@ QUnit.test("delete all attachments of message without content should no longer d
this.data['mail.message'].records.push(
{
attachment_ids: [143],
- channel_ids: [11],
id: 101,
+ model: "mail.channel",
+ res_id: 11,
}
);
await this.start();
@@ -1031,8 +1032,9 @@ QUnit.test('delete all attachments of a message with some text content should st
{
attachment_ids: [143],
body: "Some content",
- channel_ids: [11],
id: 101,
+ model: "mail.channel",
+ res_id: 11,
},
);
await this.start();
@@ -1088,8 +1090,9 @@ QUnit.test('delete all attachments of a message with tracking fields should stil
this.data['mail.message'].records.push(
{
attachment_ids: [143],
- channel_ids: [11],
id: 101,
+ model: "mail.channel",
+ res_id: 11,
tracking_value_ids: [6]
},
);
@@ -1573,8 +1576,9 @@ QUnit.test('show empty placeholder when thread contains only empty messages', as
this.data['mail.channel'].records.push({ id: 11 });
this.data['mail.message'].records.push(
{
- channel_ids: [11],
id: 101,
+ model: "mail.channel",
+ res_id: 11,
},
);
await this.start();
@@ -1621,8 +1625,9 @@ QUnit.test('message with subtype should be displayed (and not considered as empt
});
this.data['mail.message'].records.push(
{
- channel_ids: [11],
id: 101,
+ model: "mail.channel",
+ res_id: 11,
subtype_id: 10,
},
);
@@ -1673,12 +1678,14 @@ QUnit.test('[technical] message list with a full page of empty messages should s
for (let i = 0; i <= 30; i++) {
this.data['mail.message'].records.push({
body: "not empty",
- channel_ids: [11],
+ model: "mail.channel",
+ res_id: 11,
});
}
for (let i = 0; i <= 30; i++) {
this.data['mail.message'].records.push({
- channel_ids: [11],
+ model: "mail.channel",
+ res_id: 11,
});
}
await this.start();
@@ -1900,8 +1907,9 @@ QUnit.test('failure on loading more messages should not alter message list displ
this.data['mail.message'].records.push(...[...Array(60).keys()].map(id => {
return {
body: 'coucou',
- channel_ids: [20],
id,
+ model: "mail.channel",
+ res_id: 20,
};
}));
await this.start({
@@ -1950,8 +1958,9 @@ QUnit.test('failure on loading more messages should display error and prompt ret
this.data['mail.message'].records.push(...[...Array(60).keys()].map(id => {
return {
body: 'coucou',
- channel_ids: [20],
id,
+ model: "mail.channel",
+ res_id: 20,
};
}));
await this.start({
@@ -2009,8 +2018,9 @@ QUnit.test('Retry loading more messages on failed load more messages should load
this.data['mail.message'].records = [...Array(90).keys()].map(id => {
return {
body: 'coucou',
- channel_ids: [20],
id,
+ model: "mail.channel",
+ res_id: 20,
};
});
await this.start({
diff --git a/addons/mail/static/src/models/composer/composer.js b/addons/mail/static/src/models/composer/composer.js
index 2c0813ec50c..301ec2c9967 100644
--- a/addons/mail/static/src/models/composer/composer.js
+++ b/addons/mail/static/src/models/composer/composer.js
@@ -292,7 +292,6 @@ function factory(dependencies) {
let postData = {
attachment_ids: this.attachments.map(attachment => attachment.id),
body,
- channel_ids: this.mentionedChannels.map(channel => channel.id),
message_type: 'comment',
partner_ids: this.recipients.map(partner => partner.id),
};
diff --git a/addons/mail/static/src/models/message/message.js b/addons/mail/static/src/models/message/message.js
index a3cf9f20d24..7c0fdb8cb18 100644
--- a/addons/mail/static/src/models/message/message.js
+++ b/addons/mail/static/src/models/message/message.js
@@ -63,16 +63,6 @@ function factory(dependencies) {
if ('body' in data) {
data2.body = data.body;
}
- if ('channel_ids' in data && data.channel_ids) {
- const channels = data.channel_ids
- .map(channelId =>
- this.env.models['mail.thread'].findFromIdentifyingData({
- id: channelId,
- model: 'mail.channel',
- })
- ).filter(channel => !!channel);
- data2.serverChannels = [['replace', channels]];
- }
if ('date' in data && data.date) {
data2.date = moment(str_to_datetime(data.date));
}
@@ -545,7 +535,7 @@ function factory(dependencies) {
* @returns {mail.thread[]}
*/
_computeThreads() {
- const threads = [...this.serverChannels];
+ const threads = [];
if (this.isHistory) {
threads.push(this.env.messaging.history);
}
@@ -794,20 +784,12 @@ function factory(dependencies) {
'messagingModeration',
'messagingStarred',
'originThread',
- 'serverChannels',
],
inverse: 'messages',
}),
tracking_value_ids: attr({
default: [],
}),
- /**
- * All channels containing this message on the server.
- * Equivalent of python field `channel_ids`.
- */
- serverChannels: many2many('mail.thread', {
- inverse: 'messagesAsServerChannel',
- }),
};
Message.modelName = 'mail.message';
diff --git a/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js b/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js
index dcd8b09f688..0614984b974 100644
--- a/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js
+++ b/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js
@@ -540,11 +540,10 @@ function factory(dependencies) {
/**
* @private
* @param {Object} param0
- * @param {integer[]} [param0.channel_ids
* @param {integer[]} [param0.message_ids=[]]
* @param {integer} [param0.needaction_inbox_counter]
*/
- _handleNotificationPartnerMarkAsRead({ channel_ids, message_ids = [], needaction_inbox_counter }) {
+ _handleNotificationPartnerMarkAsRead({ message_ids = [], needaction_inbox_counter }) {
for (const message_id of message_ids) {
// We need to ignore all not yet known messages because we don't want them
// to be shown partially as they would be linked directly to mainCache
diff --git a/addons/mail/static/src/models/thread/thread.js b/addons/mail/static/src/models/thread/thread.js
index 6b2c68f06ec..b02f4a2739e 100644
--- a/addons/mail/static/src/models/thread/thread.js
+++ b/addons/mail/static/src/models/thread/thread.js
@@ -139,9 +139,7 @@ function factory(dependencies) {
* @return {Object}
*/
static convertData(data) {
- const data2 = {
- messagesAsServerChannel: [],
- };
+ const data2 = {};
if ('model' in data) {
data2.model = data.model;
}
@@ -171,12 +169,20 @@ function factory(dependencies) {
data2.isServerPinned = data.is_pinned;
}
if ('last_message' in data && data.last_message) {
- data2.messagesAsServerChannel.push(['insert', { id: data.last_message.id }]);
- data2.serverLastMessageId = data.last_message.id;
+ const messageData = this.env.models['mail.message'].convertData({
+ id: data.last_message.id,
+ model: data2.model,
+ res_id: data2.id,
+ });
+ data2.serverLastMessage = [['insert', messageData]];
}
if ('last_message_id' in data && data.last_message_id) {
- data2.messagesAsServerChannel.push(['insert', { id: data.last_message_id }]);
- data2.serverLastMessageId = data.last_message_id;
+ const messageData = this.env.models['mail.message'].convertData({
+ id: data.last_message_id,
+ model: data2.model,
+ res_id: data2.id,
+ });
+ data2.serverLastMessage = [['insert', messageData]];
}
if ('mass_mailing' in data) {
data2.mass_mailing = data.mass_mailing;
@@ -1247,7 +1253,7 @@ function factory(dependencies) {
// By default trust the server up to the last message it used
// because it's not possible to do better.
let baseCounter = this.serverMessageUnreadCounter;
- let countFromId = this.serverLastMessageId;
+ let countFromId = this.serverLastMessage ? this.serverLastMessage.id : 0;
// But if the client knows the last seen message that the server
// returned (and by assumption all the messages that come after),
// the counter can be computed fully locally, ignoring potentially
@@ -1843,7 +1849,7 @@ function factory(dependencies) {
'lastSeenByCurrentPartnerMessageId',
'messagingCurrentPartner',
'orderedMessages',
- 'serverLastMessageId',
+ 'serverLastMessage',
'serverMessageUnreadCounter',
],
}),
@@ -1893,13 +1899,6 @@ function factory(dependencies) {
messagesAsOriginThreadIsNeedaction: attr({
related: 'messagesAsOriginThread.isNeedaction',
}),
- /**
- * All messages that are contained on this channel on the server.
- * Equivalent to the inverse of python field `channel_ids`.
- */
- messagesAsServerChannel: many2many('mail.message', {
- inverse: 'serverChannels',
- }),
/**
* Contains the message fetched/seen indicators for all messages of this thread.
* FIXME This field should be readonly once task-2336946 is done.
@@ -2077,15 +2076,13 @@ function factory(dependencies) {
default: 'closed',
}),
/**
- * Last message id considered by the server.
+ * Last message considered by the server.
*
* Useful to compute localMessageUnreadCounter field.
*
* @see localMessageUnreadCounter
*/
- serverLastMessageId: attr({
- default: 0,
- }),
+ serverLastMessage: many2one('mail.message'),
/**
* Message unread counter coming from server.
*
diff --git a/addons/mail/static/src/models/thread_cache/thread_cache.js b/addons/mail/static/src/models/thread_cache/thread_cache.js
index f97222307da..da0752f5f46 100644
--- a/addons/mail/static/src/models/thread_cache/thread_cache.js
+++ b/addons/mail/static/src/models/thread_cache/thread_cache.js
@@ -253,9 +253,7 @@ function factory(dependencies) {
*/
_extendMessageDomain(domain) {
const thread = this.thread;
- if (thread.model === 'mail.channel') {
- return domain.concat([['channel_ids', 'in', [thread.id]]]);
- } else if (thread === this.env.messaging.inbox) {
+ if (thread === this.env.messaging.inbox) {
return domain.concat([['needaction', '=', true]]);
} else if (thread === this.env.messaging.starred) {
return domain.concat([
diff --git a/addons/mail/static/tests/helpers/mock_models.js b/addons/mail/static/tests/helpers/mock_models.js
index 70da8ce0393..bd1a06b6ad9 100644
--- a/addons/mail/static/tests/helpers/mock_models.js
+++ b/addons/mail/static/tests/helpers/mock_models.js
@@ -125,7 +125,6 @@ class MockModels {
attachment_ids: { string: "Attachments", type: 'many2many', relation: 'ir.attachment', default: [] },
author_id: { string: "Author", type: 'many2one', relation: 'res.partner', default() { return this.currentPartnerId; } },
body: { string: "Contents", type: 'html', default: "" },
- channel_ids: { string: "Channels", type: 'many2many', relation: 'mail.channel' },
date: { string: "Date", type: 'datetime' },
email_from: { string: "From", type: 'char' },
history_partner_ids: { string: "Partners with History", type: 'many2many', relation: 'res.partner' },
diff --git a/addons/mail/static/tests/helpers/mock_server.js b/addons/mail/static/tests/helpers/mock_server.js
index 1ce1b3c8766..c358a548e7a 100644
--- a/addons/mail/static/tests/helpers/mock_server.js
+++ b/addons/mail/static/tests/helpers/mock_server.js
@@ -598,7 +598,10 @@ MockServer.include({
_mockMailChannelChannelFetched(ids) {
const channels = this._getRecords('mail.channel', [['id', 'in', ids]]);
for (const channel of channels) {
- const channelMessages = this._getRecords('mail.message', [['channel_ids', 'in', channel.id]]);
+ const channelMessages = this._getRecords('mail.message', [
+ ['model', '=', 'mail.channel'],
+ ['res_id', '=', channel.id],
+ ]);
const lastMessage = channelMessages.reduce((lastMessage, message) => {
if (message.id > lastMessage.id) {
return message;
@@ -634,7 +637,10 @@ MockServer.include({
_mockMailChannelChannelFetchPreview(ids) {
const channels = this._getRecords('mail.channel', [['id', 'in', ids]]);
return channels.map(channel => {
- const channelMessages = this._getRecords('mail.message', [['channel_ids', 'in', channel.id]]);
+ const channelMessages = this._getRecords('mail.message', [
+ ['model', '=', 'mail.channel'],
+ ['res_id', '=', channel.id],
+ ]);
const lastMessage = channelMessages.reduce((lastMessage, message) => {
if (message.id > lastMessage.id) {
return message;
@@ -727,7 +733,8 @@ MockServer.include({
return channels.map(channel => {
const members = channel.members.map(partnerId => partnerInfos[partnerId]);
const messages = this._getRecords('mail.message', [
- ['channel_ids', 'in', [channel.id]],
+ ['model', '=', 'mail.channel'],
+ ['res_id', '=', channel.id],
]);
const lastMessageId = messages.reduce((lastMessageId, message) => {
if (!lastMessageId || message.id > lastMessageId) {
@@ -804,8 +811,9 @@ MockServer.include({
}
const channel = this._getRecords('mail.channel', [['id', '=', channel_id]])[0];
const messagesBeforeGivenLastMessage = this._getRecords('mail.message', [
- ['channel_ids', 'in', [channel.id]],
['id', '<=', last_message_id],
+ ['model', '=', 'mail.channel'],
+ ['res_id', '=', channel.id],
]);
if (!messagesBeforeGivenLastMessage || messagesBeforeGivenLastMessage.length === 0) {
return;
@@ -880,8 +888,9 @@ MockServer.include({
["dbName", 'res.partner', this.currentPartnerId],
{
'body': `${message}`,
- 'channel_ids': [channel.id],
'info': 'transient_message',
+ 'model': 'mail.channel',
+ 'res_id': channel.id,
}
];
this._widget.call('bus_service', 'trigger', 'notification', [notification]);
@@ -1267,7 +1276,7 @@ MockServer.include({
this._mockWrite('mail.message', [[message.id], {
moderation_status: 'accepted',
}]);
- this._mockMailThread_NotifyThread(model, message.channel_ids, message.id);
+ this._mockMailThread_NotifyThread(model, [message.res_id], message.id);
}
}
},
@@ -1333,9 +1342,7 @@ MockServer.include({
),
},
]);
- // NOTE server is sending grouped notifications per channel_ids but
- // this optimization is not needed here.
- const data = { type: 'mark_as_read', message_ids: [message.id], channel_ids: message.channel_ids, needaction_inbox_counter: this._mockResPartnerGetNeedactionCount() };
+ const data = { type: 'mark_as_read', message_ids: [message.id], needaction_inbox_counter: this._mockResPartnerGetNeedactionCount() };
const busNotifications = [[[false, 'res.partner', this.currentPartnerId], data]];
this._widget.call('bus_service', 'trigger', 'notification', busNotifications);
}
@@ -1636,7 +1643,7 @@ MockServer.include({
notifications.push([[false, 'res.partner', message.author_id], notificationData]);
}
// members
- const channels = this._getRecords('mail.channel', [['id', 'in', message.channel_ids]]);
+ const channels = this._getRecords('mail.channel', [['id', '=', message.res_id]]);
for (const channel of channels) {
notifications.push([[false, 'mail.channel', channel.id], messageFormat]);
}
diff --git a/addons/mail/tests/test_mail_channel.py b/addons/mail/tests/test_mail_channel.py
index e36272c1a50..2c3b138e965 100644
--- a/addons/mail/tests/test_mail_channel.py
+++ b/addons/mail/tests/test_mail_channel.py
@@ -206,7 +206,8 @@ class TestChannelInternals(MailCommon):
with self.mock_mail_gateway():
new_msg = channel.message_post(body="Test", message_type='comment', subtype_xmlid='mail.mt_comment')
self.assertNotSentEmail()
- self.assertEqual(new_msg.channel_ids, channel)
+ self.assertEqual(new_msg.model, self.test_channel._name)
+ self.assertEqual(new_msg.res_id, self.test_channel.id)
self.assertEqual(new_msg.partner_ids, self.env['res.partner'])
self.assertEqual(new_msg.notified_partner_ids, self.env['res.partner'])
@@ -223,7 +224,8 @@ class TestChannelInternals(MailCommon):
channel = self.env['mail.channel'].browse(self.test_channel.ids)
new_msg = channel.message_post(body="Test", message_type='comment', subtype_xmlid='mail.mt_comment')
self.assertNotSentEmail()
- self.assertEqual(new_msg.channel_ids, self.test_channel)
+ self.assertEqual(new_msg.model, self.test_channel._name)
+ self.assertEqual(new_msg.res_id, self.test_channel.id)
self.assertEqual(new_msg.partner_ids, self.env['res.partner'])
self.assertEqual(new_msg.notified_partner_ids, self.env['res.partner'])
@@ -320,12 +322,8 @@ class TestChannelInternals(MailCommon):
channel.write({'channel_type': 'chat'})
channel.action_follow()
- msg_1 = self._add_messages(
- self.test_channel, 'Body1', author=self.user_employee.partner_id,
- channel_ids=[self.test_channel.id])
- msg_2 = self._add_messages(
- self.test_channel, 'Body2', author=self.user_employee.partner_id,
- channel_ids=[self.test_channel.id])
+ msg_1 = self._add_messages(self.test_channel, 'Body1', author=self.user_employee.partner_id)
+ msg_2 = self._add_messages(self.test_channel, 'Body2', author=self.user_employee.partner_id)
self.test_channel.channel_seen(msg_2.id)
self.assertEqual(
@@ -440,12 +438,10 @@ class TestChannelModeration(MailCommon):
msg_c1_emplo2 = self._add_messages(self.channel, 'Body21', author=self.partner_employee_2, moderation_status='pending_moderation')
self._reset_bus()
- self.assertFalse(msg_c1_admin1.channel_ids | msg_c1_admin2.channel_ids | msg_c1_emplo2.channel_ids)
# accept
with self.assertBus([(self.cr.dbname, 'mail.channel', self.channel.id)]):
msg_c1_admin1.with_user(self.user_employee)._moderate('accept')
- self.assertEqual(msg_c1_admin1.channel_ids, self.channel)
self.assertEqual(msg_c1_admin1.moderation_status, 'accepted')
self.assertEqual(msg_c1_admin2.moderation_status, 'pending_moderation')
@@ -455,9 +451,6 @@ class TestChannelModeration(MailCommon):
(self.cr.dbname, 'mail.channel', self.channel.id),
(self.cr.dbname, 'mail.channel', self.channel.id)]):
(msg_c1_admin1 | msg_c1_emplo2).with_user(self.user_employee)._moderate('allow')
- self.assertEqual(msg_c1_admin1.channel_ids, self.channel)
- self.assertEqual(msg_c1_admin2.channel_ids, self.channel)
- self.assertEqual(msg_c1_emplo2.channel_ids, self.channel)
self.assertEqual(msg_c1_admin1.moderation_status, 'accepted')
self.assertEqual(msg_c1_admin2.moderation_status, 'accepted')
self.assertEqual(msg_c1_emplo2.moderation_status, 'accepted')
@@ -470,8 +463,6 @@ class TestChannelModeration(MailCommon):
msg_c1_portal = self._add_messages(self.channel, 'Body12
', author=self.partner_portal, moderation_status='pending_moderation')
id2, id4 = msg_c1_admin2.id, msg_c1_portal.id # save ids because unlink will discard them
- self.assertFalse(msg_c1_admin1.channel_ids | msg_c1_admin2.channel_ids | msg_c1_emplo2.channel_ids | msg_c1_portal.channel_ids)
-
# test reject: should also send a rejection email
with self.mock_mail_gateway():
(msg_c1_admin1 | msg_c1_emplo2).with_user(self.user_employee)._moderate('reject', title='RejectTitle', comment='RejectComment')
@@ -670,5 +661,3 @@ class TestChannelModeration(MailCommon):
self.assertFalse(msg_email1)
self.assertEqual(msg_admin, pending_messages)
self.assertEqual(accepted_messages, msg_moderator | msg_email2 | msg_notif)
- self.assertFalse(msg_admin.channel_ids)
- self.assertEqual(msg_email2.channel_ids, channel)
diff --git a/addons/mail/views/mail_message_views.xml b/addons/mail/views/mail_message_views.xml
index df65876ee14..401c4131e2c 100644
--- a/addons/mail/views/mail_message_views.xml
+++ b/addons/mail/views/mail_message_views.xml
@@ -64,7 +64,6 @@
-
diff --git a/addons/test_mail/tests/test_message_post.py b/addons/test_mail/tests/test_message_post.py
index 09370bd9ade..db0c27812dd 100644
--- a/addons/test_mail/tests/test_message_post.py
+++ b/addons/test_mail/tests/test_message_post.py
@@ -128,7 +128,6 @@ class TestMessagePost(TestMailCommon, TestRecipients):
self.assertEqual(msg.body, _body)
self.assertEqual(msg.partner_ids, self.partner_1 | self.partner_2)
self.assertEqual(msg.notified_partner_ids, self.user_admin.partner_id | self.partner_1 | self.partner_2)
- self.assertEqual(msg.channel_ids, self.env['mail.channel'])
# notifications emails should have been deleted
self.assertFalse(self.env['mail.mail'].sudo().search([('mail_message_id', '=', msg.id)]),
diff --git a/addons/website_crm_livechat/models/crm_lead.py b/addons/website_crm_livechat/models/crm_lead.py
index 1b2622aa8a8..9751c5bdb97 100644
--- a/addons/website_crm_livechat/models/crm_lead.py
+++ b/addons/website_crm_livechat/models/crm_lead.py
@@ -17,5 +17,5 @@ class Lead(models.Model):
def action_redirect_to_livechat_sessions(self):
visitors = self.visitor_ids
action = self.env["ir.actions.actions"]._for_xml_id("website_livechat.website_visitor_livechat_session_action")
- action['domain'] = [('livechat_visitor_id', 'in', visitors.ids), ('channel_message_ids', '!=', False)]
+ action['domain'] = [('livechat_visitor_id', 'in', visitors.ids), ('message_ids', '!=', False)]
return action
diff --git a/addons/website_livechat/models/mail_channel.py b/addons/website_livechat/models/mail_channel.py
index 6137dcc8e23..589027a70fa 100644
--- a/addons/website_livechat/models/mail_channel.py
+++ b/addons/website_livechat/models/mail_channel.py
@@ -18,7 +18,7 @@ class MailChannel(models.Model):
delete mail_channel as not useful to keep empty chat
"""
super(MailChannel, self)._execute_channel_pin(pinned)
- if self.livechat_active and not self.channel_message_ids:
+ if self.livechat_active and not self.message_ids:
self.unlink()
def channel_info(self, extra_info=False):
diff --git a/addons/website_livechat/models/website.py b/addons/website_livechat/models/website.py
index a4bd8b1513e..95874357ecb 100644
--- a/addons/website_livechat/models/website.py
+++ b/addons/website_livechat/models/website.py
@@ -41,7 +41,7 @@ class Website(models.Model):
('livechat_visitor_id', '=', visitor.id),
('livechat_channel_id', '=', self.channel_id.id),
('livechat_active', '=', True),
- ('channel_message_ids', '!=', False)
+ ('message_ids', '!=', False)
], order='create_date desc', limit=1)
if chat_request_channel:
return {
diff --git a/addons/website_livechat/models/website_visitor.py b/addons/website_livechat/models/website_visitor.py
index a70145abeff..ef387225894 100644
--- a/addons/website_livechat/models/website_visitor.py
+++ b/addons/website_livechat/models/website_visitor.py
@@ -31,7 +31,7 @@ class WebsiteVisitor(models.Model):
def _compute_session_count(self):
sessions = self.env['mail.channel'].search([('livechat_visitor_id', 'in', self.ids)])
session_count = dict.fromkeys(self.ids, 0)
- for session in sessions.filtered(lambda c: c.channel_message_ids):
+ for session in sessions.filtered(lambda c: c.message_ids):
session_count[session.livechat_visitor_id.id] += 1
for visitor in self:
visitor.session_count = session_count.get(visitor.id, 0)
diff --git a/addons/website_livechat/views/website_visitor_views.xml b/addons/website_livechat/views/website_visitor_views.xml
index 595e7b6b5a3..1787d1fdd21 100644
--- a/addons/website_livechat/views/website_visitor_views.xml
+++ b/addons/website_livechat/views/website_visitor_views.xml
@@ -5,7 +5,7 @@
mail.channel
tree,form
- [('livechat_visitor_id', '=', active_id), ('channel_message_ids', '!=', False)]
+ [('livechat_visitor_id', '=', active_id), ('message_ids', '!=', False)]
{
'search_default_livechat_visitor_id': [active_id],
'default_livechat_visitor_id': active_id,