diff --git a/addons/mail/static/src/core/common/channel_member_service.js b/addons/mail/static/src/core/common/channel_member_service.js index 1794ecef424..2ddc394de5a 100644 --- a/addons/mail/static/src/core/common/channel_member_service.js +++ b/addons/mail/static/src/core/common/channel_member_service.js @@ -39,8 +39,8 @@ export class ChannelMemberService { channelId: memberData.persona.guest ? memberData.channel.id : null, }); } - member.threadId = memberData.threadId ?? member.threadId ?? memberData.channel.id; - if (!member.thread) { + member.threadId = memberData.threadId ?? member.threadId ?? memberData.channel?.id; + if (member.threadId && !member.thread) { // this prevents cyclic dependencies between mail.thread and discuss.channel.member this.env.bus.trigger("mail.thread/insert", { id: member.threadId, @@ -50,7 +50,7 @@ export class ChannelMemberService { switch (command) { case "insert": { - if (!member.thread.channelMembers.includes(member)) { + if (member.thread && !member.thread.channelMembers.includes(member)) { member.thread.channelMembers.push(member); } } @@ -59,7 +59,9 @@ export class ChannelMemberService { removeFromArray(this.store.channelMembers, member); // eslint-disable-next-line no-fallthrough case "insert-and-unlink": - removeFromArray(member.thread.channelMembers, member); + if (member.thread) { + removeFromArray(member.thread.channelMembers, member); + } break; } } diff --git a/addons/mail/static/tests/composer/composer_tests.js b/addons/mail/static/tests/composer/composer_tests.js index f1dff6e6f8d..1a9f39fd44a 100644 --- a/addons/mail/static/tests/composer/composer_tests.js +++ b/addons/mail/static/tests/composer/composer_tests.js @@ -486,6 +486,27 @@ QUnit.test("leave command on channel", async (assert) => { assert.verifySteps(["You unsubscribed from general."]); }); +QUnit.test("Can handle leave notification from unknown member", async (assert) => { + const pyEnv = await startServer(); + const userId = pyEnv["res.users"].create({ name: "Dobby" }); + const partnerId = pyEnv["res.partner"].create({ name: "Dobby", user_ids: [userId] }); + const channelId = pyEnv["discuss.channel"].create({ + name: "general", + channel_member_ids: [ + Command.create({ partner_id: pyEnv.currentPartnerId }), + Command.create({ partner_id: partnerId }), + ], + }); + const { env, openDiscuss } = await start(); + await openDiscuss(channelId); + await env.services.orm.call("discuss.channel", "action_unfollow", [channelId], { + context: { mockedUserId: userId }, + }); + await click("button[title='Show Member List']"); + assert.containsOnce($, ".o-discuss-ChannelMember:contains(Mitchell)"); + assert.containsNone($, ".o-discuss-ChannelMember:contains(Dobby)"); +}); + QUnit.test("leave command on chat", async (assert) => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({ name: "Chuck Norris" }); diff --git a/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js b/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js index cccc0602aad..3ad7c7287a7 100644 --- a/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js +++ b/addons/mail/static/tests/helpers/mock_server/models/discuss_channel.js @@ -91,7 +91,7 @@ patch(MockServer.prototype, "mail/models/discuss_channel", { return this._mockDiscussChannelCreateGroup(partners_to); } if (args.model === "discuss.channel" && args.method === "execute_command_leave") { - return this._mockDiscussChannelExecuteCommandLeave(args); + return this._mockDiscussChannelExecuteCommandLeave(args, args.kwargs?.context); } if (args.model === "discuss.channel" && args.method === "execute_command_who") { return this._mockDiscussChannelExecuteCommandWho(args); @@ -218,9 +218,6 @@ patch(MockServer.prototype, "mail/models/discuss_channel", { ["channel_id", "in", ids], ["partner_id", "=", partnerId], ]); - const formattedChannelMember = this._mockDiscussChannelMember_DiscussChannelMemberFormat([ - channelMember.id, - ])[0]; if (!channelMember) { return true; } @@ -241,7 +238,7 @@ patch(MockServer.prototype, "mail/models/discuss_channel", { this.pyEnv["bus.bus"]._sendone(channel, "mail.record/insert", { Channel: { id: channel.id, - channelMembers: [["insert-and-unlink", formattedChannelMember]], + channelMembers: [["insert-and-unlink", { id: channelMember.id }]], memberCount: this.pyEnv["discuss.channel.member"].searchCount([ ["channel_id", "=", channel.id], ]), @@ -844,10 +841,10 @@ patch(MockServer.prototype, "mail/models/discuss_channel", { * * @private */ - _mockDiscussChannelExecuteCommandLeave(args) { + _mockDiscussChannelExecuteCommandLeave(args, context = {}) { const channel = this.getRecords("discuss.channel", [["id", "in", args.args[0]]])[0]; if (channel.channel_type === "channel") { - this._mockDiscussChannelActionUnfollow([channel.id]); + this._mockDiscussChannelActionUnfollow([channel.id], context); } else { this._mockDiscussChannelChannelPin([channel.id], false); }