From 281b65a9437db8cae82b2c8b04a582bc0925b059 Mon Sep 17 00:00:00 2001 From: Barad Mahendra Date: Tue, 12 Oct 2021 13:13:31 +0000 Subject: [PATCH] [FIX] web,*_*: fix the html content in notification Currently markup-ification of the legacy notifications system display the html content in notification layout for some of the notification of document and planning from commit: https://github.com/odoo/enterprise/commit/ba44461fea337ed2e5adbdfa1e8eede00b036def So here in this commit, we make the method `makeLegacyNotificationService` always `_.escape(message)` and pass `messageIsHtml: true` to the owl notifications system so notification with html content will be displayed properly. Task-2657391 closes odoo/odoo#78627 X-original-commit: 7ce6d8d70be79c9c626865598b898dce9a18b045 Related: odoo/enterprise#21782 Signed-off-by: LTU-Odoo --- .../static/src/js/partner_autocomplete_core.js | 6 ++---- .../legacy/js/views/basic/basic_controller.js | 4 ++-- .../src/legacy/js/widgets/attach_document.js | 4 ++-- addons/web/static/src/legacy/utils.js | 5 ++--- .../tests/legacy/fields/basic_fields_tests.js | 4 ++-- .../web/static/tests/legacy/views/form_tests.js | 2 +- .../static/src/js/editor/snippets.editor.js | 5 +++-- .../web_editor/static/tests/field_html_tests.js | 11 ++++------- .../static/src/js/content/website_root.js | 16 +++++++--------- .../static/src/js/editor/snippets.options.js | 5 +++-- .../static/src/js/register_toaster_widget.js | 4 ++-- .../src/js/slides_certification_upload_toast.js | 9 ++++----- 12 files changed, 34 insertions(+), 41 deletions(-) diff --git a/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js b/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js index 1418c52d456..8831b9312b4 100644 --- a/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js +++ b/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js @@ -339,9 +339,8 @@ var PartnerAutocompleteMixin = { }); self.displayNotification({ title, - message: content, + message: utils.Markup(content), className: 'o_partner_autocomplete_no_credits_notify', - messageIsHtml: true, // the message is coming from a QWeb template using safe instructions }); }); }, @@ -360,9 +359,8 @@ var PartnerAutocompleteMixin = { }); self.displayNotification({ title, - message: content, + message: utils.Markup(content), className: 'o_partner_autocomplete_no_credits_notify', - messageIsHtml: true, // the message is coming from a QWeb template using safe instructions }); } else { diff --git a/addons/web/static/src/legacy/js/views/basic/basic_controller.js b/addons/web/static/src/legacy/js/views/basic/basic_controller.js index 24daed9bcf7..356717500f3 100644 --- a/addons/web/static/src/legacy/js/views/basic/basic_controller.js +++ b/addons/web/static/src/legacy/js/views/basic/basic_controller.js @@ -11,6 +11,7 @@ var AbstractController = require('web.AbstractController'); var core = require('web.core'); var Dialog = require('web.Dialog'); var FieldManagerMixin = require('web.FieldManagerMixin'); +var {Markup} = require('web.utils'); var TranslationDialog = require('web.TranslationDialog'); var _t = core._t; @@ -592,9 +593,8 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { warnings.push(''); this.displayNotification({ title: _t("Invalid fields:"), - message: warnings.join(''), + message: Markup(warnings.join('')), type: 'danger', - messageIsHtml: true, // dynamic parts of the message are escaped above }); }, /** diff --git a/addons/web/static/src/legacy/js/widgets/attach_document.js b/addons/web/static/src/legacy/js/widgets/attach_document.js index d84dcad9ac3..d206e2c8ac3 100644 --- a/addons/web/static/src/legacy/js/widgets/attach_document.js +++ b/addons/web/static/src/legacy/js/widgets/attach_document.js @@ -3,6 +3,7 @@ odoo.define('web.AttachDocument', function (require) { var core = require('web.core'); var framework = require('web.framework'); +var {Markup} = require('web.utils'); var widgetRegistry = require('web.widget_registry'); var Widget = require('web.Widget'); @@ -64,9 +65,8 @@ var AttachDocument = Widget.extend({ warnings.push(''); this.displayNotification({ title: _t("Invalid fields:"), - message: warnings.join(''), + message: Markup(warnings.join('')), type: 'danger', - messageIsHtml: true, // dynamic parts of the message are escaped above }); }, diff --git a/addons/web/static/src/legacy/utils.js b/addons/web/static/src/legacy/utils.js index 72ee1334671..af515c76bcb 100644 --- a/addons/web/static/src/legacy/utils.js +++ b/addons/web/static/src/legacy/utils.js @@ -211,7 +211,6 @@ export function makeLegacyNotificationService(legacyEnv) { type, className, onClose, - messageIsHtml, }) { if (subtitle) { title = [title, subtitle].filter(Boolean).join(" "); @@ -230,14 +229,14 @@ export function makeLegacyNotificationService(legacyEnv) { }; }); - const removeFn = env.services.notification.add(message, { + const removeFn = env.services.notification.add(_.escape(message), { sticky, title, type, className, onClose, buttons, - messageIsHtml, + messageIsHtml: true, }); const id = ++notifId; idsToRemoveFn[id] = removeFn; diff --git a/addons/web/static/tests/legacy/fields/basic_fields_tests.js b/addons/web/static/tests/legacy/fields/basic_fields_tests.js index 0e529cdb985..1c289277fb5 100644 --- a/addons/web/static/tests/legacy/fields/basic_fields_tests.js +++ b/addons/web/static/tests/legacy/fields/basic_fields_tests.js @@ -3923,7 +3923,7 @@ QUnit.module('basic_fields', { if (ev.data.service === 'notification') { assert.strictEqual(ev.data.method, 'notify'); assert.strictEqual(ev.data.args[0].title, 'Invalid fields:'); - assert.strictEqual(ev.data.args[0].message, ''); + assert.strictEqual(ev.data.args[0].message.toString(), ''); } } }, @@ -6102,7 +6102,7 @@ QUnit.module('basic_fields', { if (ev.data.service === 'notification') { assert.strictEqual(ev.data.method, 'notify'); assert.strictEqual(ev.data.args[0].title, 'Invalid fields:'); - assert.strictEqual(ev.data.args[0].message, ''); + assert.strictEqual(ev.data.args[0].message.toString(), ''); } } }, diff --git a/addons/web/static/tests/legacy/views/form_tests.js b/addons/web/static/tests/legacy/views/form_tests.js index cf9b2b61b77..a400a034ac4 100644 --- a/addons/web/static/tests/legacy/views/form_tests.js +++ b/addons/web/static/tests/legacy/views/form_tests.js @@ -3664,7 +3664,7 @@ QUnit.module('Views', { } assert.strictEqual(params.title, 'Invalid fields:', "should have a warning with correct title"); - assert.strictEqual(params.message, '', + assert.strictEqual(params.message.toString(), '', "should have a warning with correct message"); } }, diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index c9a9a4634bc..07c4d9e7b81 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -5,6 +5,7 @@ var concurrency = require('web.concurrency'); var core = require('web.core'); var Dialog = require('web.Dialog'); var dom = require('web.dom'); +const {Markup, sprintf} = require('web.utils'); var Widget = require('web.Widget'); var options = require('web_editor.snippets.options'); const {ColorPaletteWidget} = require('web_editor.ColorPalette'); @@ -2778,11 +2779,11 @@ var SnippetsMenu = Widget.extend({ }).guardedCatch(reason => { reason.event.preventDefault(); this.close(); + const message = sprintf(Markup(_t("Could not install module %s")), name); self.displayNotification({ - message: _.str.sprintf(_t("Could not install module %s"), owl.utils.escape(name)), + message: message, type: 'danger', sticky: true, - messageIsHtml: true, // dynamic parts of the message are escaped above }); }); }, diff --git a/addons/web_editor/static/tests/field_html_tests.js b/addons/web_editor/static/tests/field_html_tests.js index 18f3cd32ea5..7450d72ba19 100644 --- a/addons/web_editor/static/tests/field_html_tests.js +++ b/addons/web_editor/static/tests/field_html_tests.js @@ -198,7 +198,7 @@ QUnit.module('web_editor', {}, function () { }); QUnit.test('check if required field is set', async function (assert) { - assert.expect(1); + assert.expect(3); var form = await testUtils.createView({ View: FormView, @@ -212,12 +212,9 @@ QUnit.module('web_editor', {}, function () { testUtils.mock.intercept(form, 'call_service', function (ev) { if (ev.data.service === 'notification') { - assert.deepEqual(ev.data.args[0], { - "message": "", - "messageIsHtml": true, - "title": "Invalid fields:", - "type": "danger" - }); + assert.strictEqual(ev.data.args[0].title, 'Invalid fields:'); + assert.strictEqual(ev.data.args[0].message.toString(), ''); + assert.strictEqual(ev.data.args[0].type, 'danger'); } }, true); diff --git a/addons/website/static/src/js/content/website_root.js b/addons/website/static/src/js/content/website_root.js index a7710edb095..987b04d2e47 100644 --- a/addons/website/static/src/js/content/website_root.js +++ b/addons/website/static/src/js/content/website_root.js @@ -3,6 +3,7 @@ import ajax from 'web.ajax'; import { _t } from 'web.core'; import KeyboardNavigationMixin from 'web.KeyboardNavigationMixin'; +import {Markup} from 'web.utils'; import session from 'web.session'; import publicRootData from 'web.public.root'; import "web.zoomodoo"; @@ -146,19 +147,16 @@ export const WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMi if (!key) { if (!editableMode && session.is_admin) { + const message = _t("Cannot load google map."); + const urlTitle = _t("Check your configuration."); this.displayNotification({ type: 'warning', sticky: true, message: - $('
').append( - $('', {text: _t("Cannot load google map.")}), - $('
'), - $('', { - href: "/web#action=website.action_website_configuration", - text: _t("Check your configuration."), - }), - )[0].outerHTML, - messageIsHtml: true, // HTML is built with only safe static parts + Markup`
+ ${message}
+
${urlTitle} +
`, }); } resolve(false); diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index bbed1a84b91..2415535bdb7 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -6,6 +6,7 @@ const {ColorpickerWidget} = require('web.Colorpicker'); const config = require('web.config'); var core = require('web.core'); var Dialog = require('web.Dialog'); +const {Markup, sprintf} = require('web.utils'); const weUtils = require('web_editor.utils'); var options = require('web_editor.snippets.options'); const wLinkPopoverWidget = require('@website/js/widgets/link_popover_widget')[Symbol.for("default")]; @@ -2188,11 +2189,11 @@ options.registry.anchor = options.Class.extend({ const clipboard = new ClipboardJS(this.$button[0], {text: () => this._getAnchorLink()}); clipboard.on('success', () => { const anchor = decodeURIComponent(this._getAnchorLink()); + const message = sprintf(Markup(_t("Anchor copied to clipboard
Link: %s")), anchor); this.displayNotification({ type: 'success', - message: _.str.sprintf(_t("Anchor copied to clipboard
Link: %s"), owl.utils.escape(anchor)), + message: message, buttons: [{text: _t("Edit"), click: () => this.openAnchorDialog(), primary: true}], - messageIsHtml: true, // dynamic parts of the message are escaped above }); }); diff --git a/addons/website_event/static/src/js/register_toaster_widget.js b/addons/website_event/static/src/js/register_toaster_widget.js index 798e484abe6..fd2f944c78d 100644 --- a/addons/website_event/static/src/js/register_toaster_widget.js +++ b/addons/website_event/static/src/js/register_toaster_widget.js @@ -2,6 +2,7 @@ odoo.define('website_event.register_toaster_widget', function (require) { 'use strict'; let core = require('web.core'); +const {Markup} = require('web.utils'); let _t = core._t; let publicWidget = require('web.public.widget'); @@ -18,9 +19,8 @@ publicWidget.registry.RegisterToasterWidget = publicWidget.Widget.extend({ if (message && message.length) { this.displayNotification({ title: _t("Register"), - message: message, + message: Markup(message), type: 'info', - messageIsHtml: true, // the message is coming from a QWeb template using safe instructions }); } return this._super.apply(this, arguments); diff --git a/addons/website_slides_survey/static/src/js/slides_certification_upload_toast.js b/addons/website_slides_survey/static/src/js/slides_certification_upload_toast.js index 03775f68d8c..519af24a4b0 100644 --- a/addons/website_slides_survey/static/src/js/slides_certification_upload_toast.js +++ b/addons/website_slides_survey/static/src/js/slides_certification_upload_toast.js @@ -2,6 +2,7 @@ odoo.define('website_slides_survey.certification_upload_toast', function (requir 'use strict'; var publicWidget = require('web.public.widget'); +var {Markup, sprintf} = require('web.utils'); var sessionStorage = window.sessionStorage; var core = require('web.core'); @@ -19,15 +20,13 @@ publicWidget.registry.CertificationUploadToast = publicWidget.Widget.extend({ this._super.apply(this, arguments).then(function () { var url = sessionStorage.getItem("survey_certification_url"); if (url) { + var message = sprintf(Markup( + _t('Follow this link to add questions to your certification. Edit certification')), url); self.displayNotification({ type: 'info', title: _t('Certification created'), - message: _.str.sprintf( - _t('Follow this link to add questions to your certification. Edit certification'), - _.escape(url) - ), + message: message, sticky: true, - messageIsHtml: true, // dynamic parts of the message are escaped above }); sessionStorage.removeItem("survey_certification_url"); }