diff options
| author | Thibault Delavallée <tde@odoo.com> | 2020-02-25 11:49:27 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-03-24 10:24:19 +0000 |
| commit | 822f468059c9702b0898016e7bfbaf036a2c4036 (patch) | |
| tree | 819a2fea2e95860120b5e556aaca3a326003ac2c /addons/mail/models/mail_template.py | |
| parent | a03f6483d6be83a81eac6e8f667ce317c8007dbe (diff) | |
[MOV] mail: move rendering code to mail render mixin
We also have to update code calling directly the rendering itself. Indeed
some code bits does some rendering directly on jinja-enabled input and not
through templates. Those calls have to be updated accordingly.
LINKS
Task ID 1963529
Community PR odoo/odoo#32397
Diffstat (limited to 'addons/mail/models/mail_template.py')
| -rw-r--r-- | addons/mail/models/mail_template.py | 174 |
1 files changed, 0 insertions, 174 deletions
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index df14bfef5f7..72183aabf01 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -1,15 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import babel import base64 -import copy -import datetime -import dateutil.relativedelta as relativedelta -import functools import logging -from werkzeug import urls from odoo import _, api, fields, models, tools from odoo.exceptions import UserError @@ -17,66 +11,6 @@ from odoo.exceptions import UserError _logger = logging.getLogger(__name__) -def format_date(env, date, pattern=False, lang_code=False): - try: - return tools.format_date(env, date, date_format=pattern, lang_code=lang_code) - except babel.core.UnknownLocaleError: - return date - - -def format_datetime(env, dt, tz=False, dt_format='medium', lang_code=False): - try: - return tools.format_datetime(env, dt, tz=tz, dt_format=dt_format, lang_code=lang_code) - except babel.core.UnknownLocaleError: - return dt - -try: - # We use a jinja2 sandboxed environment to render mako templates. - # Note that the rendering does not cover all the mako syntax, in particular - # arbitrary Python statements are not accepted, and not all expressions are - # allowed: only "public" attributes (not starting with '_') of objects may - # be accessed. - # This is done on purpose: it prevents incidental or malicious execution of - # Python code that may break the security of the server. - from jinja2.sandbox import SandboxedEnvironment - jinja_template_env = SandboxedEnvironment( - block_start_string="<%", - block_end_string="%>", - variable_start_string="${", - variable_end_string="}", - comment_start_string="<%doc>", - comment_end_string="</%doc>", - line_statement_prefix="%", - line_comment_prefix="##", - trim_blocks=True, # do not output newline after blocks - autoescape=True, # XML/HTML automatic escaping - ) - jinja_template_env.globals.update({ - 'str': str, - 'quote': urls.url_quote, - 'urlencode': urls.url_encode, - 'datetime': datetime, - 'len': len, - 'abs': abs, - 'min': min, - 'max': max, - 'sum': sum, - 'filter': filter, - 'reduce': functools.reduce, - 'map': map, - 'round': round, - - # dateutil.relativedelta is an old-style class and cannot be directly - # instanciated wihtin a jinja2 expression, so a lambda "proxy" is - # is needed, apparently. - 'relativedelta': lambda *a, **kw : relativedelta.relativedelta(*a, **kw), - }) - jinja_safe_template_env = copy.copy(jinja_template_env) - jinja_safe_template_env.autoescape = False -except ImportError: - _logger.warning("jinja2 not available, templating features will not work!") - - class MailTemplate(models.Model): "Templates for sending email" _name = "mail.template" @@ -180,114 +114,6 @@ class MailTemplate(models.Model): # RENDERING # ------------------------------------------------------------ - @api.model - def _render_jinja_eval_context(self): - """ Prepare jinja evaluation context, containing for all rendering - - * ``user``: current user browse record; - * ``ctx```: current context, named ctx to avoid clash with jinja - internals that already uses context; - * various formatting tools; - """ - render_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_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, - } - return render_context - - @api.model - def _render_template_jinja(self, template_txt, model, res_ids): - """ Render a string-based template on records given by a model and a list - of IDs, using jinja. - - In addition to the generic evaluation context given by _render_jinja_eval_context - some new variables are added, depending on each record - - * ``object``: record based on which the template is rendered; - - :param str template_txt: template text to render - :param str model: model name of records on which we want to perform rendering - :param list res_ids: list of ids of records (all belonging to same model) - - :return dict: {res_id: string of rendered template based on record} - """ - # TDE FIXME: remove that brol (6dde919bb9850912f618b561cd2141bffe41340c) - no_autoescape = self._context.get('safe') - results = dict.fromkeys(res_ids, u"") - if not template_txt: - return results - - # try to load the template - try: - jinja_env = jinja_safe_template_env if no_autoescape else jinja_template_env - template = jinja_env.from_string(tools.ustr(template_txt)) - except Exception: - _logger.info("Failed to load template %r", template_txt, exc_info=True) - return results - - # prepare template variables - variables = self._render_jinja_eval_context() - # TDE CHECKME - # records = self.env[model].browse(it for it in res_ids if it) # filter to avoid browsing [None] - if any(r is None for r in res_ids): - raise ValueError(_('Unsuspected None')) - - for record in self.env[model].browse(res_ids): - variables['object'] = record - try: - render_result = template.render(variables) - except Exception as e: - _logger.info("Failed to render template : %s" % e, exc_info=True) - raise UserError(_("Failed to render template : %s") % e) - if render_result == u"False": - render_result = u"" - results[record.id] = render_result - - return results - - @api.model - def _render_template_postprocess(self, rendered): - """ Tool method for post processing. In this method we ensure local - links ('/shop/Basil-1') are replaced by global links ('https://www. - mygardin.com/hop/Basil-1'). - - :param rendered: result of ``_render_template`` - - :return dict: updated version of rendered - """ - for res_id, html in rendered.items(): - rendered[res_id] = self.env['mail.thread']._replace_local_links(html) - return rendered - - @api.model - def _render_template(self, template_txt, model, res_ids, engine='jinja', post_process=False): - """ Render the given string on records designed by model / res_ids using - the given rendering engine. Currently only jinja is supported. - - :param str template_txt: template text to render - :param str model: model name of records on which we want to perform rendering - :param list res_ids: list of ids of records (all belonging to same model) - :param string engine: jinja - :param post_process: perform rendered str / html post processing (see - ``_render_template_postprocess``) - - :return dict: {res_id: string of rendered template based on record} - """ - if not isinstance(res_ids, (list, tuple)): - raise ValueError(_('Template rendering should be called only using on a list of IDs.')) - if engine != 'jinja': - raise ValueError(_('Template rendering supports only jinja.')) - - rendered = self._render_template_jinja(template_txt, model, res_ids) - if post_process: - rendered = self._render_template_postprocess(rendered) - - return rendered - def _render_lang(self, res_ids): """ Given some record ids, return the lang for each record based on lang field of template or through specific context-based key. |
