- - - -
Hello
You have messages to moderate, please go for the proceedings.
Thank you!
-Hello
Please find below the guidelines of the
-
test
", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - }); - await this.start(); - await this.afterEvent({ - eventName: 'o-thread-view-hint-processed', - func: () => { - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${this.env.messaging.moderation.localId}"] - `).click(); - }, - message: "should wait until moderation box is loaded after clicking on it", - predicate: ({ hint, threadViewer }) => { - return ( - hint.type === 'messages-loaded' && - threadViewer.thread.model === 'mail.box' && - threadViewer.thread.id === 'moderation' - ); - }, - }); - await this.afterEvent({ - eventName: 'o-thread-view-hint-processed', - func: () => { - // simulate control panel search - this.env.messaging.discuss.update({ - stringifiedDomain: JSON.stringify([['body', 'ilike', 'test']]), - }); - }, - message: "should wait until search filter is applied", - predicate: ({ hint, threadViewer }) => { - return ( - hint.type === 'messages-loaded' && - threadViewer.thread.model === 'mail.box' && - threadViewer.thread.id === 'moderation' - ); - }, - }); - assert.containsOnce( - document.body, - '.o_Message', - "should only have the 1 message containing 'test' in moderation box" - ); - assert.notOk( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should not be checked initially" - ); - - await afterNextRender(() => document.querySelector('.o_widget_Discuss_controlPanelButtonSelectAll').click()); - assert.ok( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should be checked after clicking on 'select all'" - ); - - await afterNextRender(() => document.querySelector('.o_widget_Discuss_controlPanelButtonUnselectAll').click()); - assert.notOk( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should be unchecked after clicking on 'unselect all'" - ); -}); - }); }); }); diff --git a/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js index a2b997532ef..8b137891791 100644 --- a/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js +++ b/addons/mail/static/src/components/discuss/tests/discuss_moderation_tests.js @@ -1,1176 +1 @@ -/** @odoo-module **/ -import { - afterEach, - afterNextRender, - beforeEach, - start, -} from '@mail/utils/test_utils'; - -QUnit.module('mail', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('discuss', {}, function () { -QUnit.module('discuss_moderation_tests.js', { - beforeEach() { - beforeEach(this); - - this.start = async params => { - const { env, widget } = await start(Object.assign({}, params, { - autoOpenDiscuss: true, - data: this.data, - hasDiscuss: true, - })); - this.env = env; - this.widget = widget; - }; - }, - afterEach() { - afterEach(this); - }, -}); - -QUnit.test('as moderator, moderated channel with pending moderation message', async function (assert) { - assert.expect(37); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // for consistency, but not used in the scope of this test - name: "general", // random name, will be asserted in the test - }); - this.data['mail.message'].records.push({ - body: "test
", // random body, will be asserted in the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending moderation - res_id: 20, // id of the channel - }); - await this.start(); - - assert.ok( - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `), - "should display the moderation box in the sidebar" - ); - const mailboxCounter = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - .o_DiscussSidebarItem_counter - `); - assert.ok( - mailboxCounter, - "there should be a counter next to the moderation mailbox in the sidebar" - ); - assert.strictEqual( - mailboxCounter.textContent.trim(), - "1", - "the mailbox counter of the moderation mailbox should display '1'" - ); - - // 1. go to moderation mailbox - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `).click() - ); - // check message - assert.containsOnce( - document.body, - '.o_Message', - "should be only one message in moderation box" - ); - assert.strictEqual( - document.querySelector('.o_Message_content').textContent, - "test", - "this message pending moderation should have the correct content" - ); - assert.containsOnce( - document.body, - '.o_Message_originThreadLink', - "thee message should have one origin" - ); - assert.strictEqual( - document.querySelector('.o_Message_originThreadLink').textContent, - "#general", - "the message pending moderation should have correct origin as its linked document" - ); - assert.containsOnce( - document.body, - '.o_Message_checkbox', - "there should be a moderation checkbox next to the message" - ); - assert.notOk( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should be unchecked by default" - ); - // check select all (enabled) / unselect all (disabled) buttons - assert.containsOnce( - document.body, - '.o_widget_Discuss_controlPanelButtonSelectAll', - "there should be a 'Select All' button in the control panel" - ); - assert.doesNotHaveClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonSelectAll'), - 'disabled', - "the 'Select All' button should not be disabled" - ); - assert.containsOnce( - document.body, - '.o_widget_Discuss_controlPanelButtonUnselectAll', - "there should be a 'Unselect All' button in the control panel" - ); - assert.hasClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonUnselectAll'), - 'disabled', - "the 'Unselect All' button should be disabled" - ); - // check moderate all buttons (invisible) - assert.containsN( - document.body, - '.o_widget_Discuss_controlPanelButtonModeration', - 3, - "there should be 3 buttons to moderate selected messages in the control panel" - ); - assert.containsOnce( - document.body, - '.o_widget_Discuss_controlPanelButtonModeration.o-accept', - "there should one moderate button to accept messages pending moderation" - ); - assert.isNotVisible( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept'), - "the moderate button 'Accept' should be invisible by default" - ); - assert.containsOnce( - document.body, - '.o_widget_Discuss_controlPanelButtonModeration.o-reject', - "there should one moderate button to reject messages pending moderation" - ); - assert.isNotVisible( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-reject'), - "the moderate button 'Reject' should be invisible by default" - ); - assert.containsOnce( - document.body, - '.o_widget_Discuss_controlPanelButtonModeration.o-discard', - "there should one moderate button to discard messages pending moderation" - ); - assert.isNotVisible( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-discard'), - "the moderate button 'Discard' should be invisible by default" - ); - - // click on message moderation checkbox - await afterNextRender(() => document.querySelector('.o_Message_checkbox').click()); - assert.ok( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should become checked after click" - ); - // check select all (disabled) / unselect all buttons (enabled) - assert.hasClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonSelectAll'), - 'disabled', - "the 'Select All' button should be disabled" - ); - assert.doesNotHaveClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonUnselectAll'), - 'disabled', - "the 'Unselect All' button should not be disabled" - ); - // check moderate all buttons updated (visible) - assert.isVisible( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept'), - "the moderate button 'Accept' should be visible" - ); - assert.isVisible( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-reject'), - "the moderate button 'Reject' should be visible" - ); - assert.isVisible( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-discard'), - "the moderate button 'Discard' should be visible" - ); - - // test select buttons - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonUnselectAll').click() - ); - assert.notOk( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should become unchecked after click" - ); - - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonSelectAll').click() - ); - assert.ok( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should become checked again after click" - ); - - // 2. go to channel 'general' - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `).click() - ); - // check correct message - assert.containsOnce( - document.body, - '.o_Message', - "should be only one message in general channel" - ); - assert.containsOnce( - document.body, - '.o_Message_checkbox', - "there should be a moderation checkbox next to the message" - ); - assert.notOk( - document.querySelector('.o_Message_checkbox').checked, - "the moderation checkbox should not be checked here" - ); - await afterNextRender(() => document.querySelector('.o_Message_checkbox').click()); - // Don't test moderation actions visibility, since it is similar to moderation box. - - // 3. test discard button - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-discard').click() - ); - assert.containsOnce( - document.body, - '.o_ModerationDiscardDialog', - "discard dialog should be open" - ); - // the dialog will be tested separately - await afterNextRender(() => - document.querySelector('.o_ModerationDiscardDialog .o-cancel').click() - ); - assert.containsNone( - document.body, - '.o_ModerationDiscardDialog', - "discard dialog should be closed" - ); - - // 4. test reject button - await afterNextRender(() => - document.querySelector(` - .o_widget_Discuss_controlPanelButtonModeration.o-reject - `).click() - ); - assert.containsOnce( - document.body, - '.o_ModerationRejectDialog', - "reject dialog should be open" - ); - // the dialog will be tested separately - await afterNextRender(() => - document.querySelector('.o_ModerationRejectDialog .o-cancel').click() - ); - assert.containsNone( - document.body, - '.o_ModerationRejectDialog', - "reject dialog should be closed" - ); - - // 5. test accept button - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept').click() - ); - assert.containsOnce( - document.body, - '.o_Message', - "should still be only one message in general channel" - ); - assert.containsNone( - document.body, - '.o_Message_checkbox', - "there should not be a moderation checkbox next to the message" - ); -}); - -QUnit.test('as moderator, accept pending moderation message', async function (assert) { - assert.expect(12); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // for consistency, but not used in the scope of this test - name: "general", // random name, will be asserted in the test - }); - this.data['mail.message'].records.push({ - body: "test
", // random body, will be asserted in the test - id: 100, // random unique id, will be asserted during the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending moderation - res_id: 20, // id of the channel - }); - await this.start({ - async mockRPC(route, args) { - if (args.method === 'moderate') { - assert.step('moderate'); - const messageIDs = args.args[0]; - const decision = args.args[1]; - assert.strictEqual( - messageIDs.length, - 1, - "should moderate one message" - ); - assert.strictEqual( - messageIDs[0], - 100, - "should moderate message with ID 100" - ); - assert.strictEqual( - decision, - 'accept', - "should accept the message" - ); - } - return this._super(...arguments); - }, - }); - - // 1. go to moderation box - const moderationBox = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `); - assert.ok( - moderationBox, - "should display the moderation box" - ); - - await afterNextRender(() => moderationBox.click()); - assert.ok( - document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - `), - "should display the message to moderate" - ); - const acceptButton = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - .o_Message_moderationAction.o-accept - `); - assert.ok(acceptButton, "should display the accept button"); - - await afterNextRender(() => acceptButton.click()); - assert.verifySteps(['moderate']); - assert.containsOnce( - document.body, - '.o_MessageList_emptyTitle', - "should now have no message displayed in moderation box" - ); - - // 2. go to channel 'general' - const channel = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `); - assert.ok( - channel, - "should display the general channel" - ); - - await afterNextRender(() => channel.click()); - const message = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - `); - assert.ok( - message, - "should display the accepted message" - ); - assert.containsNone( - message, - '.o_Message_moderationPending', - "the message should not be pending moderation" - ); -}); - -QUnit.test('as moderator, reject pending moderation message (reject with explanation)', async function (assert) { - assert.expect(23); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // for consistency, but not used in the scope of this test - name: "general", // random name, will be asserted in the test - }); - this.data['mail.message'].records.push({ - body: "test
", // random body, will be asserted in the test - id: 100, // random unique id, will be asserted during the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending moderation - res_id: 20, // id of the channel - }); - await this.start({ - async mockRPC(route, args) { - if (args.method === 'moderate') { - assert.step('moderate'); - const messageIDs = args.args[0]; - const decision = args.args[1]; - const kwargs = args.kwargs; - assert.strictEqual( - messageIDs.length, - 1, - "should moderate one message" - ); - assert.strictEqual( - messageIDs[0], - 100, - "should moderate message with ID 100" - ); - assert.strictEqual( - decision, - 'reject', - "should reject the message" - ); - assert.strictEqual( - kwargs.title, - "Message Rejected", - "should have correct reject message title" - ); - assert.strictEqual( - kwargs.comment, - "Your message was rejected by moderator.", - "should have correct reject message body / comment" - ); - } - return this._super(...arguments); - }, - }); - - // 1. go to moderation box - const moderationBox = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `); - assert.ok( - moderationBox, - "should display the moderation box" - ); - - await afterNextRender(() => moderationBox.click()); - const pendingMessage = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - `); - assert.ok( - pendingMessage, - "should display the message to moderate" - ); - const rejectButton = pendingMessage.querySelector(':scope .o_Message_moderationAction.o-reject'); - assert.ok( - rejectButton, - "should display the reject button" - ); - - await afterNextRender(() => rejectButton.click()); - const dialog = document.querySelector('.o_ModerationRejectDialog'); - assert.ok( - dialog, - "a dialog should be prompt to the moderator on click reject" - ); - assert.strictEqual( - dialog.querySelector('.modal-title').textContent, - "Send explanation to author", - "dialog should have correct title" - ); - - const messageTitle = dialog.querySelector(':scope .o_ModerationRejectDialog_title'); - assert.ok( - messageTitle, - "should have a title for rejecting" - ); - assert.hasAttrValue( - messageTitle, - 'placeholder', - "Subject", - "title for reject reason should have correct placeholder" - ); - assert.strictEqual( - messageTitle.value, - "Message Rejected", - "title for reject reason should have correct default value" - ); - - const messageComment = dialog.querySelector(':scope .o_ModerationRejectDialog_comment'); - assert.ok( - messageComment, - "should have a comment for rejecting" - ); - assert.hasAttrValue( - messageComment, - 'placeholder', - "Mail Body", - "comment for reject reason should have correct placeholder" - ); - assert.strictEqual( - messageComment.value, - "Your message was rejected by moderator.", - "comment for reject reason should have correct default text content" - ); - const confirmReject = dialog.querySelector(':scope .o-reject'); - assert.ok( - confirmReject, - "should have reject button" - ); - assert.strictEqual( - confirmReject.textContent, - "Reject" - ); - - await afterNextRender(() => confirmReject.click()); - assert.verifySteps(['moderate']); - assert.containsOnce( - document.body, - '.o_MessageList_emptyTitle', - "should now have no message displayed in moderation box" - ); - - // 2. go to channel 'general' - const channel = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `); - assert.ok( - channel, - 'should display the general channel' - ); - - await afterNextRender(() => channel.click()); - assert.containsNone( - document.body, - '.o_Message', - "should now have no message in channel" - ); -}); - -QUnit.test('as moderator, discard pending moderation message (reject without explanation)', async function (assert) { - assert.expect(16); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // for consistency, but not used in the scope of this test - name: "general", // random name, will be asserted in the test - }); - this.data['mail.message'].records.push({ - body: "test
", // random body, will be asserted in the test - id: 100, // random unique id, will be asserted during the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending moderation - res_id: 20, // id of the channel - }); - await this.start({ - async mockRPC(route, args) { - if (args.method === 'moderate') { - assert.step('moderate'); - const messageIDs = args.args[0]; - const decision = args.args[1]; - assert.strictEqual(messageIDs.length, 1, "should moderate one message"); - assert.strictEqual(messageIDs[0], 100, "should moderate message with ID 100"); - assert.strictEqual(decision, 'discard', "should discard the message"); - } - return this._super(...arguments); - }, - }); - - // 1. go to moderation box - const moderationBox = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `); - assert.ok( - moderationBox, - "should display the moderation box" - ); - - await afterNextRender(() => moderationBox.click()); - const pendingMessage = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - `); - assert.ok( - pendingMessage, - "should display the message to moderate" - ); - - const discardButton = pendingMessage.querySelector(` - :scope .o_Message_moderationAction.o-discard - `); - assert.ok( - discardButton, - "should display the discard button" - ); - - await afterNextRender(() => discardButton.click()); - const dialog = document.querySelector('.o_ModerationDiscardDialog'); - assert.ok( - dialog, - "a dialog should be prompt to the moderator on click discard" - ); - assert.strictEqual( - dialog.querySelector('.modal-title').textContent, - "Confirmation", - "dialog should have correct title" - ); - assert.strictEqual( - dialog.textContent, - "Confirmation×You are going to discard 1 message.Do you confirm the action?DiscardCancel", - "should warn the user on discard action" - ); - - const confirmDiscard = dialog.querySelector(':scope .o-discard'); - assert.ok( - confirmDiscard, - "should have discard button" - ); - assert.strictEqual( - confirmDiscard.textContent, - "Discard" - ); - - await afterNextRender(() => confirmDiscard.click()); - assert.verifySteps(['moderate']); - assert.containsOnce( - document.body, - '.o_MessageList_emptyTitle', - "should now have no message displayed in moderation box" - ); - - // 2. go to channel 'general' - const channel = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `); - assert.ok( - channel, - "should display the general channel" - ); - - await afterNextRender(() => channel.click()); - assert.containsNone( - document.body, - '.o_Message', - "should now have no message in channel" - ); -}); - -QUnit.test('as author, send message in moderated channel', async function (assert) { - assert.expect(4); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - moderation: true, // channel must be moderated to test the feature - name: "general", // random name, will be asserted in the test - }); - await this.start(); - const channel = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `); - assert.ok( - channel, - "should display the general channel" - ); - - // go to channel 'general' - await afterNextRender(() => channel.click()); - assert.containsNone( - document.body, - '.o_Message', - "should have no message in channel" - ); - - // post a message - await afterNextRender(() => { - const textInput = document.querySelector('.o_ComposerTextInput_textarea'); - textInput.focus(); - document.execCommand('insertText', false, "Some Text"); - }); - await afterNextRender(() => document.querySelector('.o_Composer_buttonSend').click()); - const messagePending = document.querySelector('.o_Message_moderationPending'); - assert.ok( - messagePending, - "should display the pending message with pending info" - ); - assert.hasClass( - messagePending, - 'o-author', - "the message should be pending moderation as author" - ); -}); - -QUnit.test('as author, sent message accepted in moderated channel', async function (assert) { - assert.expect(5); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - moderation: true, // for consistency, but not used in the scope of this test - name: "general", // random name, will be asserted in the test - }); - this.data['mail.message'].records.push({ - body: "not empty", - id: 100, // random unique id, will be referenced in the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending - res_id: 20, // id of the channel - }); - await this.start(); - - const channel = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `); - assert.ok( - channel, - "should display the general channel" - ); - - await afterNextRender(() => channel.click()); - const messagePending = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - .o_Message_moderationPending - `); - assert.ok( - messagePending, - "should display the pending message with pending info" - ); - assert.hasClass( - messagePending, - 'o-author', - "the message should be pending moderation as author" - ); - - // simulate accepted message - await afterNextRender(() => { - const messageData = { - id: 100, - moderation_status: 'accepted', - }; - const notification = [[false, 'mail.channel', 20], messageData]; - this.widget.call('bus_service', 'trigger', 'notification', [notification]); - }); - - // check message is accepted - const message = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - `); - assert.ok( - message, - "should still display the message" - ); - assert.containsNone( - message, - '.o_Message_moderationPending', - "the message should not be in pending moderation anymore" - ); -}); - -QUnit.test('as author, sent message rejected in moderated channel', async function (assert) { - assert.expect(4); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - moderation: true, // for consistency, but not used in the scope of this test - name: "general", // random name, will be asserted in the test - }); - this.data['mail.message'].records.push({ - body: "not empty", - id: 100, // random unique id, will be referenced in the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending - res_id: 20, // id of the channel - }); - await this.start(); - - const channel = document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }).localId - }"] - `); - assert.ok( - channel, - "should display the general channel" - ); - - await afterNextRender(() => channel.click()); - const messagePending = document.querySelector(` - .o_Message[data-message-local-id="${ - this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }).localId - }"] - .o_Message_moderationPending - `); - assert.ok( - messagePending, - "should display the pending message with pending info" - ); - assert.hasClass( - messagePending, - 'o-author', - "the message should be pending moderation as author" - ); - - // simulate reject from moderator - await afterNextRender(() => { - const notifData = { - type: 'deletion', - message_ids: [100], - }; - const notification = [[false, 'res.partner', this.env.messaging.currentPartner.id], notifData]; - this.widget.call('bus_service', 'trigger', 'notification', [notification]); - }); - // check no message - assert.containsNone( - document.body, - '.o_Message', - "message should be removed from channel after reject" - ); -}); - -QUnit.test('as moderator, pending moderation message accessibility', async function (assert) { - // pending moderation message should appear in moderation box and in origin thread - assert.expect(3); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // channel must be moderated to test the feature - }); - this.data['mail.message'].records.push({ - body: "not empty", - id: 100, // random unique id, will be referenced in the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending - res_id: 20, // id of the channel - }); - await this.start(); - - const thread = this.env.models['mail.thread'].findFromIdentifyingData({ id: 20, model: 'mail.channel' }); - assert.ok( - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `), - "should display the moderation box in the sidebar" - ); - - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${thread.localId}"] - `).click() - ); - const message = this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }); - assert.containsOnce( - document.body, - `.o_Message[data-message-local-id="${message.localId}"]`, - "the pending moderation message should be in the channel" - ); - - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `).click() - ); - assert.containsOnce( - document.body, - `.o_Message[data-message-local-id="${message.localId}"]`, - "the pending moderation message should be in moderation box" - ); -}); - -QUnit.test('as author, pending moderation message should appear in origin thread', async function (assert) { - assert.expect(1); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - moderation: true, // channel must be moderated to test the feature - }); - this.data['mail.message'].records.push({ - author_id: this.data.currentPartnerId, // test as author of message - body: "not empty", - id: 100, // random unique id, will be referenced in the test - model: 'mail.channel', // expected value to link message to channel - moderation_status: 'pending_moderation', // message is expected to be pending - res_id: 20, // id of the channel - }); - await this.start(); - const thread = this.env.models['mail.thread'].findFromIdentifyingData({ id: 20, model: 'mail.channel' }); - - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${thread.localId}"] - `).click() - ); - const message = this.env.models['mail.message'].findFromIdentifyingData({ id: 100 }); - assert.containsOnce( - document.body, - `.o_Message[data-message-local-id="${message.localId}"]`, - "the pending moderation message should be in the channel" - ); -}); - -QUnit.test('as moderator, new pending moderation message posted by someone else', async function (assert) { - // the message should appear in origin thread and moderation box if I moderate it - assert.expect(3); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // channel must be moderated to test the feature - }); - await this.start(); - const thread = this.env.models['mail.thread'].findFromIdentifyingData({ id: 20, model: 'mail.channel' }); - - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${thread.localId}"] - `).click() - ); - assert.containsNone( - document.body, - `.o_Message`, - "should have no message in the channel initially" - ); - - // simulate receiving the message - const messageData = { - author_id: [10, 'john doe'], // random id, different than current partner - body: "not empty", - 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 - res_id: 20, // id of the channel - }; - await afterNextRender(() => { - const notifications = [[ - ['my-db', 'res.partner', this.env.messaging.currentPartner.id], - { type: 'moderator', message: messageData }, - ]]; - this.widget.call('bus_service', 'trigger', 'notification', notifications); - }); - const message = this.env.models['mail.message'].findFromIdentifyingData({ id: 1 }); - assert.containsOnce( - document.body, - `.o_Message[data-message-local-id="${message.localId}"]`, - "the pending moderation message should be in the channel" - ); - - await afterNextRender(() => - document.querySelector(` - .o_DiscussSidebar_item[data-thread-local-id="${ - this.env.messaging.moderation.localId - }"] - `).click() - ); - assert.containsOnce( - document.body, - `.o_Message[data-message-local-id="${message.localId}"]`, - "the pending moderation message should be in moderation box" - ); -}); - -QUnit.test('accept multiple moderation messages', async function (assert) { - assert.expect(5); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // channel must be moderated to test the feature - }); - this.data['mail.message'].records.push( - { - body: "not empty", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - }, - { - body: "not empty", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - }, - { - body: "not empty", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - } - ); - - await this.start({ - discuss: { - params: { - default_active_id: 'mail.box_moderation', - }, - }, - }); - - assert.containsN( - document.body, - '.o_Message', - 3, - "should initially display 3 messages" - ); - - await afterNextRender(() => { - document.querySelectorAll('.o_Message_checkbox')[0].click(); - document.querySelectorAll('.o_Message_checkbox')[1].click(); - }); - assert.containsN( - document.body, - '.o_Message_checkbox:checked', - 2, - "2 messages should have been checked after clicking on their respective checkbox" - ); - assert.doesNotHaveClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept'), - 'o_hidden', - "global accept button should be displayed as two messages are selected" - ); - - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept').click() - ); - assert.containsN( - document.body, - '.o_Message', - 1, - "should display 1 message as the 2 others have been accepted" - ); - assert.hasClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept'), - 'o_hidden', - "global accept button should no longer be displayed as messages have been unselected" - ); -}); - -QUnit.test('accept multiple moderation messages after having accepted other messages', async function (assert) { - assert.expect(5); - - this.data['mail.channel'].records.push({ - id: 20, // random unique id, will be used to link message and will be referenced in the test - is_moderator: true, // current user is expected to be moderator of channel - moderation: true, // channel must be moderated to test the feature - }); - this.data['mail.message'].records.push( - { - body: "not empty", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - }, - { - body: "not empty", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - }, - { - body: "not empty", - model: 'mail.channel', - moderation_status: 'pending_moderation', - res_id: 20, - } - ); - await this.start({ - discuss: { - params: { - default_active_id: 'mail.box_moderation', - }, - }, - }); - assert.containsN( - document.body, - '.o_Message', - 3, - "should initially display 3 messages" - ); - - await afterNextRender(() => { - document.querySelectorAll('.o_Message_checkbox')[0].click(); - }); - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept').click() - ); - await afterNextRender(() => document.querySelectorAll('.o_Message_checkbox')[0].click()); - assert.containsOnce( - document.body, - '.o_Message_checkbox:checked', - "a message should have been checked after clicking on its checkbox" - ); - assert.doesNotHaveClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept'), - 'o_hidden', - "global accept button should be displayed as a message is selected" - ); - - await afterNextRender(() => - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept').click() - ); - assert.containsOnce( - document.body, - '.o_Message', - "should display only one message left after the two others has been accepted" - ); - assert.hasClass( - document.querySelector('.o_widget_Discuss_controlPanelButtonModeration.o-accept'), - 'o_hidden', - "global accept button should no longer be displayed as message has been unselected" - ); -}); - -}); -}); -}); diff --git a/addons/mail/static/src/components/message/message.js b/addons/mail/static/src/components/message/message.js index 91b873c0c9e..22434f0dfcc 100644 --- a/addons/mail/static/src/components/message/message.js +++ b/addons/mail/static/src/components/message/message.js @@ -5,9 +5,6 @@ import { useStore } from '@mail/component_hooks/use_store/use_store'; import { useUpdate } from '@mail/component_hooks/use_update/use_update'; import { AttachmentList } from '@mail/components/attachment_list/attachment_list'; import { MessageSeenIndicator } from '@mail/components/message_seen_indicator/message_seen_indicator'; -import { ModerationBanDialog } from '@mail/components/moderation_ban_dialog/moderation_ban_dialog'; -import { ModerationDiscardDialog } from '@mail/components/moderation_discard_dialog/moderation_discard_dialog'; -import { ModerationRejectDialog } from '@mail/components/moderation_reject_dialog/moderation_reject_dialog'; import { NotificationPopover } from '@mail/components/notification_popover/notification_popover'; import { PartnerImStatusIcon } from '@mail/components/partner_im_status_icon/partner_im_status_icon'; import { isEventHandled, markEventHandled } from '@mail/utils/utils'; @@ -24,9 +21,6 @@ const READ_LESS = _lt("read less"); const components = { AttachmentList, MessageSeenIndicator, - ModerationBanDialog, - ModerationDiscardDialog, - ModerationRejectDialog, NotificationPopover, PartnerImStatusIcon, }; @@ -39,12 +33,6 @@ export class Message extends Component { constructor(...args) { super(...args); this.state = useState({ - // Determine if the moderation ban dialog is displayed. - hasModerationBanDialog: false, - // Determine if the moderation discard dialog is displayed. - hasModerationDiscardDialog: false, - // Determine if the moderation reject dialog is displayed. - hasModerationRejectDialog: false, /** * Determine whether the message is clicked. When message is in * clicked state, it keeps displaying the commands. @@ -68,11 +56,7 @@ export class Message extends Component { authorImStatus: author && author.im_status, authorNameOrDisplayName: author && author.nameOrDisplayName, correspondent: thread && thread.correspondent, - hasMessageCheckbox: message ? message.hasCheckbox : false, isDeviceMobile: this.env.messaging.device.isMobile, - isMessageChecked: message && threadView - ? message.isChecked(thread, threadView.stringifiedDomain) - : false, isMessageSelected: message && threadView && threadView.threadViewer ? threadView.threadViewer.selectedMessage === message : false, @@ -486,13 +470,6 @@ export class Message extends Component { // Handlers //-------------------------------------------------------------------------- - /** - * @private - */ - _onChangeCheckbox() { - this.message.toggleCheck(this.threadView.thread, this.threadView.stringifiedDomain); - } - /** * @private * @param {MouseEvent} ev @@ -560,51 +537,6 @@ export class Message extends Component { this.message.openResendAction(); } - /** - * @private - * @param {MouseEvent} ev - */ - _onClickModerationAccept(ev) { - ev.preventDefault(); - this.message.moderate('accept'); - } - - /** - * @private - * @param {MouseEvent} ev - */ - _onClickModerationAllow(ev) { - ev.preventDefault(); - this.message.moderate('allow'); - } - - /** - * @private - * @param {MouseEvent} ev - */ - _onClickModerationBan(ev) { - ev.preventDefault(); - this.state.hasModerationBanDialog = true; - } - - /** - * @private - * @param {MouseEvent} ev - */ - _onClickModerationDiscard(ev) { - ev.preventDefault(); - this.state.hasModerationDiscardDialog = true; - } - - /** - * @private - * @param {MouseEvent} ev - */ - _onClickModerationReject(ev) { - ev.preventDefault(); - this.state.hasModerationRejectDialog = true; - } - /** * @private * @param {MouseEvent} ev @@ -648,34 +580,11 @@ export class Message extends Component { this.message.replyTo(); } } - - /** - * @private - */ - _onDialogClosedModerationBan() { - this.state.hasModerationBanDialog = false; - } - - /** - * @private - */ - _onDialogClosedModerationDiscard() { - this.state.hasModerationDiscardDialog = false; - } - - /** - * @private - */ - _onDialogClosedModerationReject() { - this.state.hasModerationRejectDialog = false; - } - } Object.assign(Message, { components, defaultProps: { - hasCheckbox: false, hasMarkAsReadIcon: false, hasReplyIcon: false, isSquashed: false, @@ -686,7 +595,6 @@ Object.assign(Message, { optional: true, validate: prop => ['auto', 'card', 'hover', 'none'].includes(prop), }, - hasCheckbox: Boolean, hasMarkAsReadIcon: Boolean, hasReplyIcon: Boolean, isSquashed: Boolean, diff --git a/addons/mail/static/src/components/message/message.scss b/addons/mail/static/src/components/message/message.scss index 2a742fb3947..1c7477b7292 100644 --- a/addons/mail/static/src/components/message/message.scss +++ b/addons/mail/static/src/components/message/message.scss @@ -28,10 +28,6 @@ margin-inline-end: map-get($spacers, 2); } -.o_Message_checkbox { - margin-inline-end: map-get($spacers, 2); -} - .o_Message_commandStar { font-size: 1.3em; } @@ -116,20 +112,6 @@ width: $o-mail-discuss-message-highlight-indicator-width; } -.o_Message_moderationAction { - margin-inline-end: map-get($spacers, 3); -} - -.o_Message_moderationPending { - margin-inline-end: map-get($spacers, 3); -} - -.o_Message_moderationSubHeader { - display: flex; - flex-flow: row wrap; - align-items: center; -} - .o_Message_originThread { margin-inline-end: map-get($spacers, 2); } @@ -344,37 +326,6 @@ font-size: x-small; } -.o_Message_moderationAction { - font-weight: $font-weight-bold; - font-style: italic; - - &.o-accept, - &.o-allow { - color: $o-mail-moderation-accept-color; - @include hover-focus { - color: darken($o-mail-moderation-accept-color, $emphasized-link-hover-darken-percentage); - } - } - - &.o-ban, - &.o-discard, - &.o-reject { - color: $o-mail-moderation-reject-color; - @include hover-focus { - color: darken($o-mail-moderation-reject-color, $emphasized-link-hover-darken-percentage); - } - } -} - -.o_Message_moderationPending { - font-style: italic; - - &.o-author { - color: o-text-color('danger'); - font-weight: $font-weight-bold; - } -} - .o_Message_notificationIconClickable { color: gray('600'); cursor: pointer; diff --git a/addons/mail/static/src/components/message/message.xml b/addons/mail/static/src/components/message/message.xml index 75891fc859c..260576c3dbf 100644 --- a/addons/mail/static/src/components/message/message.xml +++ b/addons/mail/static/src/components/message/message.xml @@ -96,9 +96,6 @@ -Test
", - id: 100, - moderation_status: 'pending_moderation', - originThread: link(thread), - }); - await this.createMessageComponent(message); - - assert.strictEqual( - document.querySelectorAll(`.o_Message_moderationPending.o-author`).length, - 1, - "should have the message pending moderation" - ); -}); - -QUnit.test('moderation: as moderator, moderated channel with pending moderation message', async function (assert) { - assert.expect(9); - - this.data['mail.channel'].records.push({ - id: 20, - is_moderator: true, - }); - await this.start(); - const thread = this.env.models['mail.thread'].findFromIdentifyingData({ - id: 20, - model: 'mail.channel', - }); - const message = this.env.models['mail.message'].create({ - author: insert({ id: 7, display_name: "Demo User" }), - body: "Test
", - id: 100, - moderation_status: 'pending_moderation', - originThread: link(thread), - }); - await this.createMessageComponent(message); - const messageEl = document.querySelector('.o_Message'); - assert.ok(messageEl, "should display a message"); - assert.containsOnce(messageEl, `.o_Message_moderationSubHeader`, - "should have the message pending moderation" - ); - assert.containsNone(messageEl, `.o_Message_checkbox`, - "should not have the moderation checkbox by default" - ); - assert.containsN(messageEl, '.o_Message_moderationAction', 5, - "there should be 5 contextual moderation decisions next to the message" - ); - assert.containsOnce(messageEl, '.o_Message_moderationAction.o-accept', - "there should be a contextual moderation decision to accept the message" - ); - assert.containsOnce(messageEl, '.o_Message_moderationAction.o-reject', - "there should be a contextual moderation decision to reject the message" - ); - assert.containsOnce(messageEl, '.o_Message_moderationAction.o-discard', - "there should be a contextual moderation decision to discard the message" - ); - assert.containsOnce(messageEl, '.o_Message_moderationAction.o-allow', - "there should be a contextual moderation decision to allow the user of the message)" - ); - assert.containsOnce(messageEl, '.o_Message_moderationAction.o-ban', - "there should be a contextual moderation decision to ban the user of the message" - ); - // The actions are tested as part of discuss tests. -}); - QUnit.test('Notification Sent', async function (assert) { assert.expect(9); diff --git a/addons/mail/static/src/components/message_list/message_list.js b/addons/mail/static/src/components/message_list/message_list.js index e0198220b63..5bc8ba772a0 100644 --- a/addons/mail/static/src/components/message_list/message_list.js +++ b/addons/mail/static/src/components/message_list/message_list.js @@ -315,12 +315,6 @@ export class MessageList extends Component { if (prevMessage.originThread !== message.originThread) { return false; } - if ( - prevMessage.moderation_status === 'pending_moderation' || - message.moderation_status === 'pending_moderation' - ) { - return false; - } if ( prevMessage.notifications.length > 0 || message.notifications.length > 0 @@ -583,7 +577,6 @@ export class MessageList extends Component { Object.assign(MessageList, { components, defaultProps: { - hasMessageCheckbox: false, hasScrollAdjust: true, hasSquashCloseMessages: false, haveMessagesMarkAsReadIcon: false, @@ -599,7 +592,6 @@ Object.assign(MessageList, { type: Function, optional: true, }, - hasMessageCheckbox: Boolean, hasSquashCloseMessages: Boolean, haveMessagesMarkAsReadIcon: Boolean, haveMessagesReplyIcon: Boolean, diff --git a/addons/mail/static/src/components/message_list/message_list.xml b/addons/mail/static/src/components/message_list/message_list.xml index 67bef1fdb6d..6d8c7051ea7 100644 --- a/addons/mail/static/src/components/message_list/message_list.xml +++ b/addons/mail/static/src/components/message_list/message_list.xml @@ -25,12 +25,6 @@ Messages marked as read will appear in the history. -