From e596723ba52be57669b8ed98471cd02ccee60cad Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Wed, 27 May 2026 11:40:17 -0400 Subject: [PATCH] fix(fusion_helpdesk): render message bodies as HTML, not escaped text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OWL dialog used on message bodies, but t-out escapes plain strings — it only renders raw when the value is a Markup instance. Bodies arrive over JSON-RPC as plain strings (Markup is a client-side type, doesn't cross the wire), so the customer was seeing literal "

This has been fixed.

" in the thread instead of the rendered HTML. Wrap incoming bodies in `markup()` at the boundary (openTicket + sendReply call sites) so the template renders them as the sanitised HTML the central chatter already produced. Trust is fine — the body is sanitised server-side by mail.thread before it ever leaves nexa. Bumps fusion_helpdesk to 19.0.1.7.1. --- fusion_helpdesk/__manifest__.py | 2 +- .../static/src/js/fusion_helpdesk_dialog.js | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/fusion_helpdesk/__manifest__.py b/fusion_helpdesk/__manifest__.py index 6c7882c1..942c9ce4 100644 --- a/fusion_helpdesk/__manifest__.py +++ b/fusion_helpdesk/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Helpdesk Reporter', - 'version': '19.0.1.7.0', + 'version': '19.0.1.7.1', 'category': 'Productivity', 'summary': 'One-click in-app bug reporting & feature requesting — ' 'auto-creates a helpdesk.ticket on a central Odoo Helpdesk.', diff --git a/fusion_helpdesk/static/src/js/fusion_helpdesk_dialog.js b/fusion_helpdesk/static/src/js/fusion_helpdesk_dialog.js index 13d6b6ea..937bf448 100644 --- a/fusion_helpdesk/static/src/js/fusion_helpdesk_dialog.js +++ b/fusion_helpdesk/static/src/js/fusion_helpdesk_dialog.js @@ -11,13 +11,25 @@ // Tickets are NOT copied locally — every list/thread/reply is a live call // to the central Helpdesk, scoped server-side to the logged-in user. -import { Component, useState, onWillStart } from "@odoo/owl"; +import { Component, markup, useState, onWillStart } from "@odoo/owl"; import { Dialog } from "@web/core/dialog/dialog"; import { rpc } from "@web/core/network/rpc"; import { user } from "@web/core/user"; import { useService } from "@web/core/utils/hooks"; import { _t } from "@web/core/l10n/translation"; +// Wrap message bodies in `markup()` so the OWL template's `t-out` renders them +// as HTML instead of escaping `

` literally. Bodies come from central as +// plain JSON strings (Markup doesn't survive JSON-RPC) but are already sanitised +// server-side by Odoo's mail.thread, so we trust them. Mutates the list in place +// because that's what the existing call sites assign straight to state. +function _markupBodies(messages) { + for (const m of messages || []) { + m.body = markup(m.body || ""); + } + return messages || []; +} + const MAX_BYTES_PER_FILE = 10 * 1024 * 1024; // 10 MB hard cap per file export class FusionHelpdeskDialog extends Component { @@ -193,6 +205,7 @@ export class FusionHelpdeskDialog extends Component { this.state.threadError = res.message || _t("Could not open this ticket."); return; } + _markupBodies(res.ticket.messages); this.state.current = res.ticket; this.state.tab = "thread"; // The ticket is now seen server-side; clear its unread flag locally. @@ -227,7 +240,7 @@ export class FusionHelpdeskDialog extends Component { if (!res.ok) { this.state.threadError = res.message || _t("Could not send your reply."); } else { - this.state.current.messages = res.messages || this.state.current.messages; + this.state.current.messages = _markupBodies(res.messages) || this.state.current.messages; this.state.replyBody = ""; this.notification.add(_t("Reply sent."), { type: "success" }); }