From 3a9a791be89485eacbfe2cd7171a251ce865fafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 22 Nov 2022 12:54:09 +0000 Subject: [PATCH] [IMP] mail: allow to render views from render mixin When calling "_render_template_qweb_view", parameter can currently be an XmlID or an id. It can now be a recordset, allowing easy calls from Odoo. Slug is also added in evaluation context to prepare further cleaning in message_post helpers. Some error messages are also improved while passing by. Task-2710804 (Mail: Clean MailThread Posting API) Part-of: odoo/odoo#99482 --- addons/mail/models/mail_render_mixin.py | 70 ++++++++++++++++++------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/addons/mail/models/mail_render_mixin.py b/addons/mail/models/mail_render_mixin.py index 63da0106246..523b122c50c 100644 --- a/addons/mail/models/mail_render_mixin.py +++ b/addons/mail/models/mail_render_mixin.py @@ -12,6 +12,7 @@ from werkzeug import urls from odoo import _, api, fields, models, tools from odoo.addons.base.models.ir_qweb import QWebException +from odoo.addons.http_routing.models.ir_http import slug from odoo.exceptions import UserError, AccessError from odoo.tools import is_html_empty from odoo.tools.rendering_tools import convert_inline_template_to_qweb, parse_inline_template, render_inline_template, template_env_globals @@ -241,7 +242,10 @@ class MailRenderMixin(models.AbstractModel): def _check_access_right_dynamic_template(self): if not self.env.su and not self.env.user.has_group('mail.group_mail_template_editor') and self._is_dynamic(): group = self.env.ref('mail.group_mail_template_editor') - raise AccessError(_('Only users belonging to the "%s" group can modify dynamic templates.', group.name)) + raise AccessError( + _('Only users belonging to the "%(group_name)s" group can modify dynamic templates.', + group_name=group.name) + ) # ------------------------------------------------------------ # RENDERING @@ -256,14 +260,15 @@ class MailRenderMixin(models.AbstractModel): * various formatting tools; """ render_context = { + 'ctx': self._context, 'format_date': lambda date, date_format=False, lang_code=False: format_date(self.env, date, date_format, lang_code), 'format_datetime': lambda dt, tz=False, dt_format=False, lang_code=False: format_datetime(self.env, dt, tz, dt_format, lang_code), 'format_time': lambda time, tz=False, time_format=False, lang_code=False: format_time(self.env, time, tz, time_format, lang_code), 'format_amount': lambda amount, currency, lang_code=False: tools.format_amount(self.env, amount, currency, lang_code), 'format_duration': lambda value: tools.format_duration(value), - 'user': self.env.user, - 'ctx': self._context, 'is_html_empty': is_html_empty, + 'slug': slug, + 'user': self.env.user, } render_context.update(copy.copy(template_env_globals)) return render_context @@ -314,15 +319,21 @@ class MailRenderMixin(models.AbstractModel): except Exception as e: if isinstance(e, QWebException) and isinstance(e.__cause__, PermissionError): group = self.env.ref('mail.group_mail_template_editor') - raise AccessError(_('Only users belonging to the "%s" group can modify dynamic templates.', group.name)) from e + raise AccessError( + _('Only users belonging to the "%(group_name)s" group can modify dynamic templates.', + group_name=group.name) + ) from e _logger.info("Failed to render template : %s", template_src, exc_info=True) - raise UserError(_("Failed to render QWeb template : %s)", template_src)) from e + raise UserError( + _("Failed to render QWeb template : %(template_src)s)", + template_src=template_src) + ) from e results[record.id] = render_result return results @api.model - def _render_template_qweb_view(self, view_xmlid, model, res_ids, + def _render_template_qweb_view(self, view_ref, model, res_ids, add_context=None, options=None): """ Render a QWeb template based on an ir.ui.view content. @@ -330,8 +341,9 @@ class MailRenderMixin(models.AbstractModel): variables are added: * ``object``: record based on which the template is rendered; - :param str view_xmlid: source QWeb template. It should be a string - XmlID allowing to fetch an ``ir.ui.view``; + :param str/int/record view_ref: source QWeb template. It should be an + XmlID allowing to fetch an ``ir.ui.view``, or an ID of a view or + an ``ir.ui.view`` record; :param str model: see ``MailRenderMixin._render_template()``; :param list res_ids: see ``MailRenderMixin._render_template()``; @@ -352,14 +364,23 @@ class MailRenderMixin(models.AbstractModel): if add_context: variables.update(**add_context) + view_ref = view_ref.id if isinstance(view_ref, models.BaseModel) else view_ref for record in self.env[model].browse(res_ids): variables['object'] = record try: - render_result = self.env['ir.qweb']._render(view_xmlid, variables, minimal_qcontext=True, raise_if_not_found=False, **(options or {})) + render_result = self.env['ir.qweb']._render( + view_ref, + variables, + minimal_qcontext=True, + raise_if_not_found=False, + **(options or {}) + ) results[record.id] = render_result except Exception as e: - _logger.info("Failed to render template : %s", view_xmlid, exc_info=True) - raise UserError(_("Failed to render template : %s") % view_xmlid) + _logger.info("Failed to render template : %s", view_ref, exc_info=True) + raise UserError( + _("Failed to render template : %(view_ref)s", view_ref=view_ref) + ) from e return results @@ -395,7 +416,10 @@ class MailRenderMixin(models.AbstractModel): if (not self._unrestricted_rendering and is_dynamic and not self.env.is_admin() and not self.env.user.has_group('mail.group_mail_template_editor')): group = self.env.ref('mail.group_mail_template_editor') - raise AccessError(_('Only users belonging to the "%s" group can modify dynamic templates.', group.name)) + raise AccessError( + _('Only users belonging to the "%(group_name)s" group can modify dynamic templates.', + group_name=group.name) + ) if not is_dynamic: # Either the content is a raw text without placeholders, either we fail to @@ -414,10 +438,16 @@ class MailRenderMixin(models.AbstractModel): variables['object'] = record try: - results[record.id] = render_inline_template(template_instructions, variables) + results[record.id] = render_inline_template( + template_instructions, + variables + ) except Exception as e: _logger.info("Failed to render inline_template: \n%s", str(template_txt), exc_info=True) - raise UserError(_("Failed to render inline_template template : %s)", e)) + raise UserError( + _("Failed to render inline_template template : %(template_txt)s)", + template_txt=template_txt) + ) from e return results @@ -467,9 +497,15 @@ class MailRenderMixin(models.AbstractModel): options = {} if not isinstance(res_ids, (list, tuple)): - raise ValueError(_('Template rendering should be called only using on a list of IDs.')) + raise ValueError( + _('Template rendering should be called only using on a list of IDs; received %(res_ids)r instead.', + res_ids=res_ids) + ) if engine not in ('inline_template', 'qweb', 'qweb_view'): - raise ValueError(_('Template rendering supports only inline_template, qweb, or qweb_view (view or raw).')) + raise ValueError( + _('Template rendering supports only inline_template, qweb, or qweb_view (view or raw); received %(engine)s instead.', + engine=engine) + ) if engine == 'qweb_view': rendered = self._render_template_qweb_view(template_src, model, res_ids, @@ -498,8 +534,6 @@ class MailRenderMixin(models.AbstractModel): :return dict: {res_id: lang code (i.e. en_US)} """ self.ensure_one() - if not isinstance(res_ids, (list, tuple)): - raise ValueError(_('Template rendering for language should be called with a list of IDs.')) rendered_langs = self._render_template(self.lang, self.render_model, res_ids, engine=engine) return dict(