diff --git a/addons/mail/controllers/discuss/channel.py b/addons/mail/controllers/discuss/channel.py index 814999ae98b..1a645f3fb39 100644 --- a/addons/mail/controllers/discuss/channel.py +++ b/addons/mail/controllers/discuss/channel.py @@ -58,7 +58,7 @@ class ChannelController(http.Controller): messages = channel_member_sudo.env["mail.message"]._message_fetch(domain, before, after, around, limit) if not request.env.user._is_public() and not around: messages.set_message_done() - return messages.sorted("id", reverse=True).message_format() + return messages.message_format() @http.route("/discuss/channel/pinned_messages", methods=["POST"], type="json", auth="public") def discuss_channel_pins(self, channel_id): diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 887423881b9..584c432a6cb 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -932,17 +932,20 @@ class Message(models.Model): :param around: fetch messages around this message id i.e. limit//2 before and limit//2 after. :param limit: the maximum amount of messages to get; - :returns: record set of mail.message + :returns: record set of mail.message sorted in descending order. """ if around: messages_before = self.search(domain=[*domain, ('id', '<=', around)], limit=limit // 2, order="id DESC") messages_after = self.search(domain=[*domain, ('id', '>', around)], limit=limit // 2, order='id ASC') - return messages_after + messages_before + return (messages_after + messages_before).sorted('id', reverse=True) if before: domain = expression.AND([domain, [('id', '<', before)]]) if after: domain = expression.AND([domain, [('id', '>', after)]]) - return self.search(domain, limit=limit) + message_ids = self.search(domain, limit=limit, order='id ASC' if after else 'id DESC') + if after: + message_ids = message_ids.sorted('id', reverse=True) + return message_ids def message_format(self, format_reply=True, msg_vals=None): """ Get the message values in the format for web client. Since message diff --git a/addons/mail/static/src/js/tours/load_message_order_tour.js b/addons/mail/static/src/js/tours/load_message_order_tour.js new file mode 100644 index 00000000000..29deb4f11c5 --- /dev/null +++ b/addons/mail/static/src/js/tours/load_message_order_tour.js @@ -0,0 +1,62 @@ +/* @odoo-module */ + +import { registry } from "@web/core/registry"; + +registry.category("web_tour.tours").add("mail.load_message_order", { + test: true, + steps: [ + { + trigger: ".o-mail-DiscussCategoryItem:contains(MyTestChannel)", + run: "click", + }, + { + trigger: "*[title='Pinned Messages']", + run: "click", + }, + { + trigger: ".o-discuss-PinnedMessagesPanel-jump", + run: "click", + }, + { + // Messages depends on FETCH_LIMIT (currently set to 30) in + // the thread service. Thus, at first load the message range + // will be (31 - 60). This trigger ensures the next messages + // are fetched after jumping to the message. + trigger: ".o-mail-Thread .o-mail-Message:first:not(:contains(31))", + async run() { + // ensure 1 - 16 are loaded in order: 15 below and the + // one we're loading messages around. + const messages = Array.from( + document.querySelectorAll(".o-mail-Thread .o-mail-Message-content") + ).map((el) => el.innerText); + for (let i = 0; i < 16; i++) { + if (messages[i] !== (i + 1).toString()) { + throw new Error("Wrong message order after loading around"); + } + } + const thread = document.querySelector(".o-mail-Thread"); + thread.scrollTop = thread.scrollHeight - thread.clientHeight; + }, + }, + { + // After jumping to the pinned message, the message range + // was (1 -16): 15 before (but none were found), 15 after + // and the pinned message itself. This trigger ensures the + // next messages are fetched after scrolling to the bottom. + trigger: ".o-mail-Thread .o-mail-Message:contains(17)", + run() { + // ensure 1 - 46 are loaded in order. + const messages = Array.from( + document.querySelectorAll(".o-mail-Thread .o-mail-Message-content") + ).map((el) => el.innerText); + for (let i = 0; i < 46; i++) { + if (messages[i] !== (i + 1).toString()) { + throw new Error("Wrong message order after loading after"); + } + } + const thread = document.querySelector(".o-mail-Thread"); + thread.scrollTop = thread.scrollHeight - thread.clientHeight; + }, + }, + ], +}); diff --git a/addons/mail/tests/discuss/__init__.py b/addons/mail/tests/discuss/__init__.py index 869faaf2e50..a12db1a96a8 100644 --- a/addons/mail/tests/discuss/__init__.py +++ b/addons/mail/tests/discuss/__init__.py @@ -3,4 +3,5 @@ from . import test_discuss_channel from . import test_discuss_channel_as_guest from . import test_discuss_channel_member +from . import test_load_messages from . import test_rtc diff --git a/addons/mail/tests/discuss/test_load_messages.py b/addons/mail/tests/discuss/test_load_messages.py new file mode 100644 index 00000000000..29fffc2f239 --- /dev/null +++ b/addons/mail/tests/discuss/test_load_messages.py @@ -0,0 +1,21 @@ + +import odoo.tests +from odoo import Command + + +@odoo.tests.tagged('post_install', '-at_install') +class TestLoadMessages(odoo.tests.HttpCase): + def test_01_load_message_order(self): + partner_admin = self.env.ref('base.partner_admin') + channel_id = self.env["discuss.channel"].create({ + "name": "MyTestChannel", + "channel_member_ids": [Command.create({"partner_id": partner_admin.id})], + }) + self.env["mail.message"].create([{ + "body": n, + "model": "discuss.channel", + "pinned_at": odoo.fields.Datetime.now() if n == 1 else None, + "res_id": channel_id.id, + "author_id": partner_admin.id, + } for n in range(1, 61)]) + self.start_tour("/web#action=mail.action_discuss", "mail.load_message_order", login="admin")