[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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">You're welcome, have a nice day!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_0'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=5)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_4_data" model="mail.message">
|
||||
@@ -47,7 +46,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Great! Thanks for the info</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_0'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=4)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_3_data" model="mail.message">
|
||||
@@ -56,7 +54,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Yes, you can use our Timesheets application and Awesome Timesheets to record your time efficiently!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_0'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=3)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_2_data" model="mail.message">
|
||||
@@ -65,7 +62,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">I'm looking for an application to record my timesheet, any tips?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_0'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=2)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_1_data" model="mail.message">
|
||||
@@ -74,7 +70,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_0'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=1)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 1 -->
|
||||
@@ -99,7 +94,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="body">You're welcome, enjoy Odoo!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_1'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=10)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_9_data" model="mail.message">
|
||||
@@ -108,7 +102,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Awesome, thanks!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_1'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=9)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_8_data" model="mail.message">
|
||||
@@ -117,7 +110,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="body">Yes, we just released a new application called Social Marketing that should fit your needs! Check it out :)</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_1'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=8)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_7_data" model="mail.message">
|
||||
@@ -126,7 +118,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">I was wondering if Odoo has an application to easily manage social media for my business..</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_1'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=7)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_6_data" model="mail.message">
|
||||
@@ -135,7 +126,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_1'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=6)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 2 -->
|
||||
@@ -160,7 +150,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo_portal"/>
|
||||
<field name="body">Oh :(</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_2'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=14)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_13_data" model="mail.message">
|
||||
@@ -169,7 +158,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Nope, sorry to disappoint :(</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_2'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=13)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_12_data" model="mail.message">
|
||||
@@ -178,7 +166,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo_portal"/>
|
||||
<field name="body">Hello, are you single?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_2'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=12)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_11_data" model="mail.message">
|
||||
@@ -187,7 +174,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_2'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=11)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 3 -->
|
||||
@@ -212,7 +198,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo_portal"/>
|
||||
<field name="body">Thanks for the info, I'll look into it!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_3'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-3, minutes=17)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_16_data" model="mail.message">
|
||||
@@ -221,7 +206,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="body">Hello Joel Willis, you're at the right place! You can customize Odoo using our Studio application in just a few clicks.</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_3'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-3, minutes=16)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_15_data" model="mail.message">
|
||||
@@ -230,7 +214,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo_portal"/>
|
||||
<field name="body">Hello, I'm looking for a software that can be easily updated with my needs.</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_3'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-3, minutes=15)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 4 -->
|
||||
@@ -255,7 +238,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Ok.. Will do, thanks</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_4'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=21)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_20_data" model="mail.message">
|
||||
@@ -264,7 +246,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Hi, if you need help with your database, feel free to contact our support via http://www.odoo.com/help</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_4'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=20)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_19_data" model="mail.message">
|
||||
@@ -273,7 +254,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Hello, it seems that I can't log in to my database. Can you help?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_4'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=19)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_18_data" model="mail.message">
|
||||
@@ -282,7 +262,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_4'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=18)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 5 -->
|
||||
@@ -307,7 +286,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Thanks!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_5'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=25)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_24_data" model="mail.message">
|
||||
@@ -316,7 +294,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Yes, of course, you can find it here: https://www.odoo.com/documentation/user/14.0/</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_5'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=24)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_23_data" model="mail.message">
|
||||
@@ -325,7 +302,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Hello, I'm a bit lost in the Invetory module, is there some documentation I could find?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_5'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=23)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_22_data" model="mail.message">
|
||||
@@ -334,7 +310,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_5'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=22)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 6 -->
|
||||
@@ -359,7 +334,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo_portal"/>
|
||||
<field name="body">Good to hear, thanks!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_6'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=29)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_28_data" model="mail.message">
|
||||
@@ -368,7 +342,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Joel Willis, you'll need our Inventory and Sales application to do so. You can try them for 15 days, FOR FREE :)</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_6'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=28)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_27_data" model="mail.message">
|
||||
@@ -377,7 +350,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo_portal"/>
|
||||
<field name="body">Hi, I need a software to easily manage my stock, and generate sales orders.</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_6'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=27)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_26_data" model="mail.message">
|
||||
@@ -386,7 +358,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_6'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=26)" name="date"/>
|
||||
</record>
|
||||
<!-- Session 7 -->
|
||||
@@ -411,7 +382,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">I'm great, thanks for asking!</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_7'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=33)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_32_data" model="mail.message">
|
||||
@@ -420,7 +390,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="body">I'm fine, and you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_7'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=32)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_31_data" model="mail.message">
|
||||
@@ -429,7 +398,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field eval="False" name="author_id"/>
|
||||
<field name="body">Heeeey Marc, how are you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_7'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=31)" name="date"/>
|
||||
</record>
|
||||
<record id="im_livechat_mail_message_30_data" model="mail.message">
|
||||
@@ -438,7 +406,6 @@
|
||||
<field name="message_type">email</field>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field eval="[(4, ref('im_livechat.im_livechat_mail_channel_data_7'))]" name="channel_ids"/>
|
||||
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=30)" name="date"/>
|
||||
</record>
|
||||
|
||||
@@ -458,7 +425,6 @@
|
||||
<field name="body">Hi</field>
|
||||
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="channel_ids" eval="[(6, False, [mail_channel_livechat_1])]"/>
|
||||
</record>
|
||||
<record id="mail_message_livechat_2" model="mail.message">
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
@@ -467,7 +433,6 @@
|
||||
<field name="body">Hello, how may I help you?</field>
|
||||
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="channel_ids" eval="[(6, False, [mail_channel_livechat_1])]"/>
|
||||
</record>
|
||||
<record id="mail_message_livechat_3" model="mail.message">
|
||||
<field name="author_id" eval="False"/>
|
||||
@@ -477,7 +442,6 @@
|
||||
<field name="body">I would like to know more about the CRM application</field>
|
||||
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="channel_ids" eval="[(6, False, [mail_channel_livechat_1])]"/>
|
||||
</record>
|
||||
<record id="mail_message_livechat_4" model="mail.message">
|
||||
<field name="author_id" ref="base.partner_admin"/>
|
||||
@@ -486,7 +450,6 @@
|
||||
<field name="body">The CRM application helps you to track leads, close opportunities and get accurate forecasts. You can test it for free on our website.</field>
|
||||
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="channel_ids" eval="[(6, False, [mail_channel_livechat_1])]"/>
|
||||
</record>
|
||||
<record id="mail_message_livechat_5" model="mail.message">
|
||||
<field name="author_id" eval="False"/>
|
||||
@@ -496,7 +459,6 @@
|
||||
<field name="body">Great, thanks!</field>
|
||||
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="channel_ids" eval="[(6, False, [mail_channel_livechat_1])]"/>
|
||||
</record>
|
||||
<record id="mail_message_livechat_6" model="mail.message">
|
||||
<field name="author_id" eval="False"/>
|
||||
@@ -506,7 +468,6 @@
|
||||
<field name="body">Rating: :-)</field>
|
||||
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="channel_ids" eval="[(6, False, [mail_channel_livechat_1])]"/>
|
||||
</record>
|
||||
<record id="rating_rating_livechat_1" model="rating.rating">
|
||||
<field name="res_model_id" ref="mail.model_mail_channel"/>
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
{
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<tree string="History" create="false" default_order="create_date desc">
|
||||
<field name="create_date" string="Session Date"/>
|
||||
<field name="name" string="Attendees"/>
|
||||
<field name="channel_message_ids" string="# Messages"/>
|
||||
<field name="message_ids" string="# Messages"/>
|
||||
<field name="rating_last_image" string="Rating" widget="image" options='{"size": [20, 20]}'/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -129,7 +129,7 @@
|
||||
<field name="name">Sessions</field>
|
||||
<field name="res_model">mail.channel</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('livechat_channel_id', 'in', [active_id]), ('channel_message_ids', '!=', False)]</field>
|
||||
<field name="domain">[('livechat_channel_id', 'in', [active_id]), ('message_ids', '!=', False)]</field>
|
||||
<field name="context">{
|
||||
'search_default_livechat_channel_id': [active_id],
|
||||
'default_livechat_channel_id': active_id,
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<record model="mail.message" id="module_install_notification">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="mail.channel_all_employees"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_all_employees'))]"/>
|
||||
<field name="message_type">email</field>
|
||||
<field name="subtype_id" ref="mail.mt_comment"/>
|
||||
<field name="subject">Welcome to Odoo!</field>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
<field name="body"><![CDATA[<p>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.</p>]]></field>
|
||||
<field name="message_type">comment</field>
|
||||
<field name="subtype_id" ref="mt_comment"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_1'))]"/>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="date" eval="(DateTime.today() - timedelta(days=5)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
</record>
|
||||
@@ -33,7 +32,6 @@
|
||||
<field name="body"><![CDATA[<p>I noted I can not manage efficiently my pipeline when I have more than 50 opportunities in the qualification stage.</p><p>Any advice on this? How do you organize your activities with more than 50 opportunities?</p>]]></field>
|
||||
<field name="message_type">comment</field>
|
||||
<field name="subtype_id" ref="mt_comment"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_1'))]"/>
|
||||
<field name="author_id" ref="base.partner_root"/>
|
||||
<field name="date" eval="(DateTime.today() - timedelta(days=4)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
</record>
|
||||
@@ -44,7 +42,6 @@
|
||||
<field name="message_type">comment</field>
|
||||
<field name="parent_id" ref="mail_message_channel_1_2"/>
|
||||
<field name="subtype_id" ref="mt_comment"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_1'))]"/>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="date" eval="(DateTime.today() - timedelta(days=3)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
</record>
|
||||
@@ -53,7 +50,6 @@
|
||||
<record id="mail_message_channel_whole_1" model="mail.message">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="mail.channel_all_employees"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_all_employees'))]"/>
|
||||
<field name="body"><![CDATA[
|
||||
<p>
|
||||
Great news!<br/>
|
||||
@@ -70,7 +66,6 @@
|
||||
<record id="mail_message_channel_whole_2" model="mail.message">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="mail.channel_all_employees"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_all_employees'))]"/>
|
||||
<field name="body"><![CDATA[<p>Your monthly meal vouchers arrived. You can get them at the HR's office.</p>
|
||||
<p>This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</p>]]></field>
|
||||
<field name="message_type">comment</field>
|
||||
@@ -81,7 +76,6 @@
|
||||
<record id="mail_message_channel_whole_2_1" model="mail.message">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="channel_all_employees"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_all_employees'))]"/>
|
||||
<field name="body"><![CDATA[<p>Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!</p>]]></field>
|
||||
<field name="parent_id" ref="mail_message_channel_whole_2"/>
|
||||
<field name="message_type">comment</field>
|
||||
@@ -92,7 +86,6 @@
|
||||
<record id="mail_message_channel_whole_2_2" model="mail.message">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="channel_all_employees"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_all_employees'))]"/>
|
||||
<field name="body"><![CDATA[<p>Building B3, second floor on the right :-).</p>]]></field>
|
||||
<field name="parent_id" ref="mail_message_channel_whole_2"/>
|
||||
<field name="message_type">comment</field>
|
||||
@@ -158,7 +151,6 @@
|
||||
]]></field>
|
||||
<field name="message_type">comment</field>
|
||||
<field name="subtype_id" ref="mt_comment"/>
|
||||
<field name="channel_ids" eval="[Command.link(ref('mail.channel_2'))]"/>
|
||||
<field name="author_id" ref="base.partner_demo"/>
|
||||
<field name="date" eval="(DateTime.today() - timedelta(days=3)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
</record>
|
||||
|
||||
@@ -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': "<span class='o_mail_notification'>" + content + "</span>",
|
||||
'channel_ids': [self.id],
|
||||
'info': 'transient_message',
|
||||
})
|
||||
self.env['bus.bus'].sendone(
|
||||
(self._cr.dbname, 'res.partner', partner_to.id),
|
||||
{'body': "<span class='o_mail_notification'>" + content + "</span>",
|
||||
'info': 'transient_message',
|
||||
'model': self._name,
|
||||
'res_id': self.id,
|
||||
}
|
||||
)
|
||||
|
||||
def _define_command_help(self):
|
||||
return {'help': _("Show a helper message")}
|
||||
|
||||
@@ -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',
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
+16
-11
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: "<p>body</p>",
|
||||
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: "<p>body1</p>", // 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: "<p>body2</p>", // 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: "<p>body1</p>", // 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: "<p>body2</p>", // 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: {
|
||||
|
||||
@@ -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: "<p>test</p>", // 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: "<p><em>&shoulnotberaised</em><script>throw new Error('CodeInjectionError');</script></p>",
|
||||
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: "<p><em>&shoulnotberaised</em><script>throw new Error('CodeInjectionError');</script></p>",
|
||||
channel_ids: [11],
|
||||
model: "mail.channel",
|
||||
res_id: 11,
|
||||
});
|
||||
await this.start();
|
||||
|
||||
@@ -863,7 +862,8 @@ QUnit.test('<br/> 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: "<p>a<br/>b<br>c<br />d<br ></p>",
|
||||
channel_ids: [11],
|
||||
model: "mail.channel",
|
||||
res_id: 11,
|
||||
});
|
||||
await this.start();
|
||||
|
||||
|
||||
@@ -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: "<p>New message !</p>",
|
||||
channel_ids: [100],
|
||||
date: "2020-03-23 10:00:00",
|
||||
id: 44,
|
||||
message_type: 'comment',
|
||||
|
||||
-43
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
+1
-2
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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: "<p></p>" },
|
||||
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' },
|
||||
|
||||
@@ -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': `<span class="o_mail_notification">${message}</span>`,
|
||||
'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]);
|
||||
}
|
||||
|
||||
@@ -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, '<p>Body12</p>', 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)
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_ids" widget="many2many_tags"/>
|
||||
<field name="channel_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="notified_partner_ids" widget="many2many_tags"/>
|
||||
|
||||
@@ -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)]),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<field name="res_model">mail.channel</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="im_livechat.mail_channel_view_tree"/>
|
||||
<field name="domain">[('livechat_visitor_id', '=', active_id), ('channel_message_ids', '!=', False)]</field>
|
||||
<field name="domain">[('livechat_visitor_id', '=', active_id), ('message_ids', '!=', False)]</field>
|
||||
<field name="context">{
|
||||
'search_default_livechat_visitor_id': [active_id],
|
||||
'default_livechat_visitor_id': active_id,
|
||||
|
||||
Reference in New Issue
Block a user