From 0aae1ae1479d451b78c5c7d1c9afd8efc9d807f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20K=C3=BChn?= Date: Fri, 22 Mar 2024 19:17:30 +0100 Subject: [PATCH] [FIX] mail: opening chat with deleted new message should mark as read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, when a user of in chat posted a message and deleted it, all other users kept the chat as unread. Steps to reproduce: - Connect as Admin and March Demo - Send a message to Admin as Demo in DM chat - Demo deletes this message - Marc opens the chat => the unread counter is 1 and cannot be removed This happens because when a message is deleted, there's still a trace of it but the message is empty. However, empty messages could not be candidate of setting the last message being seing by a member, thus members were unable to mark the chat as read until someone else posted a newer message (and did not delete it). This commit fixes the issue by taking empty messages into account for setting last message message of member, which allow to mark thread as read even when newer messages have been deleted. opw-3764410 closes odoo/odoo#158943 Signed-off-by: Sébastien Theys (seb) --- .../static/src/core/common/thread_model.js | 20 ++++++++-- .../static/src/core/common/thread_service.js | 4 +- .../static/tests/discuss_app/discuss_tests.js | 38 +++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/addons/mail/static/src/core/common/thread_model.js b/addons/mail/static/src/core/common/thread_model.js index dffaf35247f..74e096683ff 100644 --- a/addons/mail/static/src/core/common/thread_model.js +++ b/addons/mail/static/src/core/common/thread_model.js @@ -456,13 +456,25 @@ export class Thread extends Record { return [...this.messages].reverse().find((msg) => Number.isInteger(msg.id)); } - newestPersistentNotEmptyOfAllMessage = Record.one("Message", { + newestPersistentAllMessages = Record.many("Message", { compute() { - const allPersistentMessages = this.allMessages.filter( - (message) => Number.isInteger(message.id) && !message.isEmpty + const allPersistentMessages = this.allMessages.filter((message) => + Number.isInteger(message.id) ); allPersistentMessages.sort((m1, m2) => m2.id - m1.id); - return allPersistentMessages[0]; + return allPersistentMessages; + }, + }); + + newestPersistentOfAllMessage = Record.one("Message", { + compute() { + return this.newestPersistentAllMessages[0]; + }, + }); + + newestPersistentNotEmptyOfAllMessage = Record.one("Message", { + compute() { + return this.newestPersistentAllMessages.find((message) => !message.isEmpty); }, }); diff --git a/addons/mail/static/src/core/common/thread_service.js b/addons/mail/static/src/core/common/thread_service.js index a4d14d713c5..1941b488963 100644 --- a/addons/mail/static/src/core/common/thread_service.js +++ b/addons/mail/static/src/core/common/thread_service.js @@ -100,7 +100,7 @@ export class ThreadService { * @param {import("models").Thread} thread */ markAsRead(thread) { - const newestPersistentMessage = thread.newestPersistentNotEmptyOfAllMessage; + const newestPersistentMessage = thread.newestPersistentOfAllMessage; if (!newestPersistentMessage && !thread.isLoaded) { thread.isLoadedDeferred .then(() => new Promise(setTimeout)) @@ -132,7 +132,7 @@ export class ThreadService { } } - updateSeen(thread, lastSeenId = thread.newestPersistentNotEmptyOfAllMessage?.id) { + updateSeen(thread, lastSeenId = thread.newestPersistentOfAllMessage?.id) { const lastReadIndex = thread.messages.findIndex((message) => message.id === lastSeenId); let newNeedactionCounter = 0; let newUnreadCounter = 0; diff --git a/addons/mail/static/tests/discuss_app/discuss_tests.js b/addons/mail/static/tests/discuss_app/discuss_tests.js index b6c02b5381e..e99ef98cc9b 100644 --- a/addons/mail/static/tests/discuss_app/discuss_tests.js +++ b/addons/mail/static/tests/discuss_app/discuss_tests.js @@ -2056,3 +2056,41 @@ QUnit.test("Newly created chat should be at the top of the direct message list", before: [".o-mail-DiscussSidebar-item", { text: "Albert" }], }); }); + +QUnit.test("Read of unread chat where new message is deleted should mark as read.", async () => { + const pyEnv = await startServer(); + const partnerId = pyEnv["res.partner"].create({ name: "Marc Demo" }); + const channelId = pyEnv["discuss.channel"].create({ + channel_member_ids: [ + Command.create({ partner_id: pyEnv.currentPartnerId }), + Command.create({ partner_id: partnerId }), + ], + channel_type: "chat", + }); + const messageId = pyEnv["mail.message"].create({ + author_id: partnerId, + body: "Heyo", + model: "discuss.channel", + res_id: channelId, + message_type: "comment", + }); + const [memberId] = pyEnv["discuss.channel.member"].search([ + ["channel_id", "=", channelId], + ["partner_id", "=", pyEnv.currentPartnerId], + ]); + pyEnv["discuss.channel.member"].write([memberId], { + seen_message_id: messageId, + message_unread_counter: 1, + }); + const { env, openDiscuss } = await start(); + await openDiscuss(); + await contains("button", { text: "Marc Demo", contains: [".badge", { text: "1" }] }); + // simulate deleted message + await env.services.rpc("/mail/message/update_content", { + message_id: messageId, + body: "", + attachment_ids: [], + }); + await click("button", { text: "Marc Demo" }); + await contains("button", { text: "Marc Demo", contains: [".badge", { count: 0 }] }); +});