From 10f0766b3ed3cc9ebf4c61595d6f875a11803be7 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Tue, 20 Nov 2018 14:13:52 +0000 Subject: [PATCH] [FIX] mail: no link special character mention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we mention for example `@hell'o`, the user will be added as subscriber but he is not linked. This is because there is two part of mentions: - inserting the mention in the message: at this point the mention is not escaped (only space are replaced with non-breaking space). - wrapping a link around the mention in a message that is being posted: at this time the message has been escaped ( for &<>"`' ). Thus when wrapping the mention, we have to search the escaped content. In the case of canned response, the system is different with defined substitution that replaced the "shortcut" so this makes no change to that. Added test without fix failed with: 8. should contain a link in the message content (expected:1, result:0) 9. should have correct mention link in the message content (expected:"@ЅpëciãlUser<&>\"`' ツ", result: "") opw-1909300 closes #28846 --- .../src/js/composers/mention_manager.js | 4 + addons/mail/static/tests/discuss_tests.js | 90 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/addons/mail/static/src/js/composers/mention_manager.js b/addons/mail/static/src/js/composers/mention_manager.js index 98d295b83f9..7acecadc062 100644 --- a/addons/mail/static/src/js/composers/mention_manager.js +++ b/addons/mail/static/src/js/composers/mention_manager.js @@ -417,6 +417,10 @@ var MentionManager = Widget.extend({ this._setCursorPosition(textLeft.length+substitution.length+2); this.set('mention_suggestions', []); this._composer.focus('body'); // to trigger autoresize + // suggestion after inserting will be used with escaped content + if (selectedSuggestion.name) { + selectedSuggestion.name = _.escape(selectedSuggestion.name); + } }, /** * @private diff --git a/addons/mail/static/tests/discuss_tests.js b/addons/mail/static/tests/discuss_tests.js index 68aee02ded6..31f479d50cc 100644 --- a/addons/mail/static/tests/discuss_tests.js +++ b/addons/mail/static/tests/discuss_tests.js @@ -423,6 +423,96 @@ QUnit.test('@ mention in channel', function (assert) { }); }); +QUnit.test('@ mention with special chars', function (assert) { + assert.expect(9); + var done = assert.async(); + var fetchListenersDef = $.Deferred(); + var receiveMessageDef = $.Deferred(); + this.data.initMessaging = { + channel_slots: { + channel_channel: [{ + id: 1, + channel_type: "channel", + name: "general", + }], + }, + }; + var objectDiscuss; + createDiscuss({ + id: 1, + context: {}, + params: {}, + data: this.data, + services: this.services, + mockRPC: function (route, args) { + if (args.method === 'channel_fetch_listeners') { + fetchListenersDef.resolve(); + return $.when([ + {id: 1, name: '\u0405pëciãlUser<&>"`\' \u30C4'}, + ]); + } + if (args.method === 'message_post') { + var data = { + author_id: ["42", "Me"], + body: args.kwargs.body, + channel_ids: [1], + }; + var notification = [[false, 'mail.channel', 1], data]; + objectDiscuss.call('bus_service', 'trigger', 'notification', [notification]); + receiveMessageDef.resolve(); + return $.when(42); + } + return this._super.apply(this, arguments); + }, + }) + .then(function (discuss) { + objectDiscuss = discuss; + var $general = discuss.$('.o_mail_discuss_sidebar') + .find('.o_mail_discuss_item[data-thread-id=1]'); + // click on general + $general.click(); + var $input = discuss.$('textarea.o_composer_text_field').first(); + assert.ok($input.length, "should display a composer input"); + // Note: focus is needed in order to trigger rpc 'channel_fetch_listeners' + $input.focus(); + $input.val("@"); + $input.trigger('keyup'); + fetchListenersDef + .then(concurrency.delay.bind(concurrency, 0)) + .then(function () { + var $mention = discuss.$('.o_mention_proposition'); + // correct mention proposition + assert.ok($mention.hasClass('active'), + "first partner mention should be active"); + assert.strictEqual($mention.data('id'), 1, + "first partner mention should link to the correct partner id"); + assert.strictEqual($mention.find('.o_mention_name').text(), '\u0405pëciãlUser<&>"`\' \u30C4', + "first partner mention should display the correct partner name"); + // equivalent to $mentionPropositions.find('active').click(); + $input.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER})); + assert.strictEqual(discuss.$('.o_mention_proposition').length, 0, + "should not have any partner mention proposition after ENTER"); + assert.strictEqual($input.val().trim() , "@\u0405pëciãlUser<&>\"`'\u00A0\u30C4", + "should have the correct mention link in the composer input"); + // send message + $input.trigger($.Event('keydown', {which: $.ui.keyCode.ENTER})); + receiveMessageDef + .then(concurrency.delay.bind(concurrency, 0)) + .then(function () { + assert.strictEqual(discuss.$('.o_thread_message_content').length, 1, + "should display one message with some content"); + assert.strictEqual(discuss.$('.o_thread_message_content a').length, 1, + "should contain a link in the message content"); + assert.strictEqual(discuss.$('.o_thread_message_content a').text(), + "@\u0405pëciãlUser<&>\"`' \u30C4", + "should have correct mention link in the message content"); + discuss.destroy(); + done(); + }); + }); + }); +}); + QUnit.test('no crash focusout emoji button', function (assert) { assert.expect(3); var done = assert.async();