[FIX] base, web_editor, mail, digest: preserve comments in sent e-mails

For email design in the context of Microsoft Outlook, we want to keep
some magic Microsoft comments (Outlook conditional comment), which -
until this commit - were skipped by QWeb. These allow us to change the
rendering exclusively for Outlook so as to overcome some of its
limitations. This commit introduces a qweb rendering option
(`preserve_comments`) for when - like in mass mailing and digest - we
want to keep comments.

Part-of: odoo/odoo#80621
This commit is contained in:
Antoine Guenet
2021-12-08 09:35:03 +00:00
parent 0ba08b558b
commit aceb086854
7 changed files with 23 additions and 24 deletions
+2 -1
View File
@@ -144,7 +144,8 @@ class Digest(models.Model):
'tips': self._compute_tips(user.company_id, user, tips_count=tips_count, consumed=consum_tips),
'preferences': self._compute_preferences(user.company_id, user),
},
post_process=True
post_process=True,
options={'preserve_comments': True}
)[self.id]
full_mail = self.env['mail.render.mixin']._render_encapsulate(
'digest.digest_mail_layout',
+7 -3
View File
@@ -276,8 +276,12 @@ class MailRenderMixin(models.AbstractModel):
for record in self.env[model].browse(res_ids):
variables['object'] = record
try:
render_result = self.env['ir.qweb']._render(html.fragment_fromstring(
template_src, create_parent='div'), variables, raise_on_code=is_restricted)
render_result = self.env['ir.qweb']._render(
html.fragment_fromstring(template_src, create_parent='div'),
variables,
raise_on_code=is_restricted,
**(options or {})
)
# remove the rendered tag <div> that was added in order to wrap potentially multiples nodes into one.
render_result = render_result[5:-6]
except QWebCodeFound:
@@ -329,7 +333,7 @@ class MailRenderMixin(models.AbstractModel):
for record in self.env[model].browse(res_ids):
variables['object'] = record
try:
render_result = view._render(variables, engine='ir.qweb', minimal_qcontext=True)
render_result = view._render(variables, engine='ir.qweb', minimal_qcontext=True, options=options)
except Exception as e:
_logger.info("Failed to render template : %s (%d)", template_src, view.id, exc_info=True)
raise UserError(_("Failed to render template : %(xml_id)s (%(view_id)d)",
+4 -14
View File
@@ -47,14 +47,9 @@ class TestMailComposer(MailCommon):
values = mail_compose_message.get_mail_values(self.partner_employee.ids)
self.assertIn("""<div>
<h1>Hello sir!</h1>
<p>Here! <a href="https://www.example.com">
A link for you!
</a> Make good use of it.</p>
</div>""",
self.assertIn(self.body_html,
values[self.partner_employee.id]['body_html'],
'We must remove comments')
'We must preserve (mso) comments in email html')
@users('employee')
def test_mail_mass_mode_compose_with_mso(self):
@@ -74,11 +69,6 @@ class TestMailComposer(MailCommon):
values = composer.get_mail_values(self.partner_employee.ids)
self.assertIn("""<div>
<h1>Hello sir!</h1>
<p>Here! <a href="https://www.example.com">
A link for you!
</a> Make good use of it.</p>
</div>""",
self.assertIn(self.body_html,
values[self.partner_employee.id]['body_html'],
'We must remove comments')
'We must preserve (mso) comments in email html')
+2 -1
View File
@@ -598,7 +598,8 @@ class MailComposer(models.TransientModel):
res_ids = [res_ids]
subjects = self._render_field('subject', res_ids, options={"render_safe": True})
bodies = self._render_field('body', res_ids, post_process=True)
# We want to preserve comments in emails so as to keep mso conditionals
bodies = self._render_field('body', res_ids, post_process=True, options={'preserve_comments': self.composition_mode == 'mass_mail'})
emails_from = self._render_field('email_from', res_ids)
replies_to = self._render_field('reply_to', res_ids)
default_recipients = {}
+2 -2
View File
@@ -18,7 +18,7 @@ EDITING_ATTRIBUTES = ['data-oe-model', 'data-oe-id', 'data-oe-field', 'data-oe-x
class IrUiView(models.Model):
_inherit = 'ir.ui.view'
def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False):
def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False, options=None):
if values and values.get('editable'):
try:
self.check_access_rights('write')
@@ -26,7 +26,7 @@ class IrUiView(models.Model):
except AccessError:
values['editable'] = False
return super(IrUiView, self)._render(values=values, engine=engine, minimal_qcontext=minimal_qcontext)
return super(IrUiView, self)._render(values=values, engine=engine, minimal_qcontext=minimal_qcontext, options=options)
#------------------------------------------------------
# Save from html
+2 -2
View File
@@ -1974,13 +1974,13 @@ actual arch.
def _render_template(self, template, values=None, engine='ir.qweb'):
return self.browse(self.get_view_id(template))._render(values, engine)
def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False):
def _render(self, values=None, engine='ir.qweb', minimal_qcontext=False, options=None):
assert isinstance(self.id, int)
qcontext = dict() if minimal_qcontext else self._prepare_qcontext()
qcontext.update(values or {})
return self.env[engine]._render(self.id, qcontext)
return self.env[engine]._render(self.id, qcontext, **(options or {}))
@api.model
def _prepare_qcontext(self):
+4 -1
View File
@@ -951,7 +951,10 @@ class QWeb(object):
body = []
if el.getchildren():
for item in el:
if not isinstance(item, etree._Comment):
if isinstance(item, etree._Comment):
if options.get('preserve_comments'):
self._appendText("<!--%s-->" % item.text, options)
else:
body.extend(self._compile_node(item, options, indent))
# comments can also contains tail text
if item.tail is not None: