From 0dc68dcc94ab9bb2e47943967fa2bc31780d20fa Mon Sep 17 00:00:00 2001 From: tsm-odoo <tsm@odoo.com> Date: Wed, 24 May 2023 06:18:12 +0000 Subject: [PATCH] [FIX] mail: invalid url regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since [1], comma can be included in url by the discuss regex. This should not be the case if the comma is at the end of the url/line since it could be part of a sentance. This PR applies the same logic to the dot and the semicolon character since they could also be used as punctuation. [1] https://github.com/odoo/odoo/pull/122093 closes odoo/odoo#122227 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com> --- addons/mail/static/src/js/utils.js | 2 +- .../utils/mail_utils_tests.js | 66 ++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/js/utils.js b/addons/mail/static/src/js/utils.js index ee588948b14a..b93b115ebe91 100644 --- a/addons/mail/static/src/js/utils.js +++ b/addons/mail/static/src/js/utils.js @@ -65,7 +65,7 @@ var _escapeEntities = (function () { // Suggested URL Javascript regex of http://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url // Adapted to make http(s):// not required if (and only if) www. is given. So `should.notmatch` does not match. // And further extended to include Latin-1 Supplement, Latin Extended-A, Latin Extended-B and Latin Extended Additional. -var urlRegexp = /\b(?:https?:\/\/\d{1,3}(?:\.\d{1,3}){3}|(?:https?:\/\/|(?:www\.))[-a-z0-9@:%._+~#=\u00C0-\u024F\u1E00-\u1EFF]{2,256}\.[a-z]{2,13})\b(?:[-a-z0-9@:%_+.~#?&[\]^|{}`\\,'$//=;\u00C0-\u024F\u1E00-\u1EFF]*)/gi; +var urlRegexp = /\b(?:https?:\/\/\d{1,3}(?:\.\d{1,3}){3}|(?:https?:\/\/|(?:www\.))[-a-z0-9@:%_+~#=\u00C0-\u024F\u1E00-\u1EFF]{2,256}\.[a-z]{2,13})\b(?:[-a-z0-9@:%_+~#?&[\]^|{}`\\'$//=\u00C0-\u024F\u1E00-\u1EFF]|,(?!$| )|\.(?!$| |\.)|;(?!$| ))*/gi; /** * @param {string} text * @param {Object} [attrs={}] diff --git a/addons/mail/static/tests/qunit_suite_tests/utils/mail_utils_tests.js b/addons/mail/static/tests/qunit_suite_tests/utils/mail_utils_tests.js index cd86f0c225e5..11a63975ede9 100644 --- a/addons/mail/static/tests/qunit_suite_tests/utils/mail_utils_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/utils/mail_utils_tests.js @@ -152,6 +152,70 @@ QUnit.test("url", async (assert) => { await insertText(".o_ComposerTextInput_textarea", messageBody); await click("button:contains(Send)"); assert.containsOnce($, `.o_Message a:contains(${messageBody})`); -}) +}); + +QUnit.test("url with comma at the end", async (assert) => { + const pyEnv = await startServer(); + const channelId = pyEnv["mail.channel"].create({ name: "General" }); + const { click, insertText, openDiscuss } = await start({ + discuss: { + context: { active_id: channelId }, + }, + }); + await openDiscuss(); + const messageBody = "Go to https://odoo.com, it's great!"; + await insertText(".o_ComposerTextInput_textarea", messageBody); + await click("button:contains(Send)"); + assert.containsOnce($, `.o_Message a:contains(https://odoo.com)`); + assert.containsOnce($, `.o_Message:contains(${messageBody})`); +}); + +QUnit.test("url with dot at the end", async (assert) => { + const pyEnv = await startServer(); + const channelId = pyEnv["mail.channel"].create({ name: "General" }); + const { click, insertText, openDiscuss } = await start({ + discuss: { + context: { active_id: channelId }, + }, + }); + await openDiscuss(); + const messageBody = "Go to https://odoo.com. It's great!"; + await insertText(".o_ComposerTextInput_textarea", messageBody); + await click("button:contains(Send)"); + assert.containsOnce($, `.o_Message a:contains(https://odoo.com)`); + assert.containsOnce($, `.o_Message:contains(${messageBody})`); +}); + +QUnit.test("url with semicolon at the end", async (assert) => { + const pyEnv = await startServer(); + const channelId = pyEnv["mail.channel"].create({ name: "General" }); + const { click, insertText, openDiscuss } = await start({ + discuss: { + context: { active_id: channelId }, + }, + }); + await openDiscuss(); + const messageBody = "Go to https://odoo.com; it's great!"; + await insertText(".o_ComposerTextInput_textarea", messageBody); + await click("button:contains(Send)"); + assert.containsOnce($, `.o_Message a:contains(https://odoo.com)`); + assert.containsOnce($, `.o_Message:contains(${messageBody})`); +}); + +QUnit.test("url with ellipsis at the end", async (assert) => { + const pyEnv = await startServer(); + const channelId = pyEnv["mail.channel"].create({ name: "General" }); + const { click, insertText, openDiscuss } = await start({ + discuss: { + context: { active_id: channelId }, + }, + }); + await openDiscuss(); + const messageBody = "Go to https://odoo.com... it's great!"; + await insertText(".o_ComposerTextInput_textarea", messageBody); + await click("button:contains(Send)"); + assert.containsOnce($, `.o_Message a:contains(https://odoo.com)`); + assert.containsOnce($, `.o_Message:contains(${messageBody})`); +}); }); -- GitLab