Jinja as a templating engine was problematic in differents respect:
- introduce external dependency to Odoo (less controll)
- add another templating mechanism in the stack
- specific feature in qweb cannot be reused
- difficulty in rendering easily editable templates
- more knowledge required with no betterment
By replacing jinja with qweb we can now build tools to edit a qweb
that will work with the previously jinja encoded document
(essentially `mail.template` records).
There is a catch however. Some email fields (eg. email_to) used jinja
syntax for rendering dynamic variables (ie. ${object.something} and
${object.something_that_should_not_be_escaped | safe}).
We still want user to use dynamic variables for some char fields (eg.
subject, from, to, ...). We made a new rendering engine called
"inline_template" that will render an expression enclosed by `{{` and
`}}`.
To be able to edit the templates from the backend interface, a
plugin to the Odoo editor has been made for seamlessly edit the
document.
This qweb plugin includes:
- make dynamic variables (eg. `<t t-out="variable"/>`) not editable
(for preventing the user to shoot himself in the foot)
- group and hide related logical branching (ie. t-if, t-elif, and t-else)
in order to see only one at once
- a floating select input to switch visibility of a particular logical
branching
Task-27033
X-original-commit: odoo/odoo@68182baff4
Part-of: odoo/odoo#77377
94 lines
4.0 KiB
Python
94 lines
4.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models, tools, _
|
|
|
|
|
|
class MailComposerMixin(models.AbstractModel):
|
|
""" Mixin used to edit and render some fields used when sending emails or
|
|
notifications based on a mail template.
|
|
|
|
Main current purpose is to hide details related to subject and body computation
|
|
and rendering based on a mail.template. It also give the base tools to control
|
|
who is allowed to edit body, notably when dealing with templating language
|
|
like inline_template or qweb.
|
|
|
|
It is meant to evolve in a near future with upcoming support of qweb and fine
|
|
grain control of rendering access.
|
|
"""
|
|
_name = 'mail.composer.mixin'
|
|
_inherit = 'mail.render.mixin'
|
|
_description = 'Mail Composer Mixin'
|
|
|
|
# Content
|
|
subject = fields.Char('Subject', compute='_compute_subject', readonly=False, store=True)
|
|
body = fields.Html('Contents', compute='_compute_body', render_engine='qweb', store=True, readonly=False, sanitize=False)
|
|
template_id = fields.Many2one('mail.template', 'Mail Template', domain="[('model', '=', render_model)]")
|
|
# Access
|
|
is_mail_template_editor = fields.Boolean('Is Editor', compute='_compute_is_mail_template_editor')
|
|
can_edit_body = fields.Boolean('Can Edit Body', compute='_compute_can_edit_body')
|
|
|
|
@api.depends('template_id')
|
|
def _compute_subject(self):
|
|
for composer_mixin in self:
|
|
if composer_mixin.template_id:
|
|
composer_mixin.subject = composer_mixin.template_id.subject
|
|
elif not composer_mixin.subject:
|
|
composer_mixin.subject = False
|
|
|
|
@api.depends('template_id')
|
|
def _compute_body(self):
|
|
for composer_mixin in self:
|
|
if composer_mixin.template_id:
|
|
composer_mixin.body = composer_mixin.template_id.body_html
|
|
elif not composer_mixin.body:
|
|
composer_mixin.body = False
|
|
|
|
@api.depends_context('uid')
|
|
def _compute_is_mail_template_editor(self):
|
|
is_mail_template_editor = self.env.is_admin() or self.env.user.has_group('mail.group_mail_template_editor')
|
|
for record in self:
|
|
record.is_mail_template_editor = is_mail_template_editor
|
|
|
|
@api.depends('template_id', 'is_mail_template_editor')
|
|
def _compute_can_edit_body(self):
|
|
for record in self:
|
|
record.can_edit_body = (
|
|
record.is_mail_template_editor
|
|
or not record.template_id
|
|
)
|
|
|
|
def _render_field(self, field, *args, **kwargs):
|
|
"""Render the given field on the given records.
|
|
This method bypass the rights when needed to
|
|
be able to render the template values in mass mode.
|
|
"""
|
|
if field not in self._fields:
|
|
raise ValueError(_("The field %s does not exist on the model %s", field, self._name))
|
|
|
|
composer_value = self[field]
|
|
|
|
if (
|
|
not self.template_id
|
|
or self.is_mail_template_editor
|
|
):
|
|
# Do not need to bypass the verification
|
|
return super(MailComposerMixin, self)._render_field(field, *args, **kwargs)
|
|
|
|
template_field = 'body_html' if field == 'body' else field
|
|
assert template_field in self.template_id._fields
|
|
template_value = self.template_id[template_field]
|
|
|
|
if field == 'body':
|
|
sanitized_template_value = tools.html_sanitize(template_value)
|
|
if not self.can_edit_body or composer_value in (sanitized_template_value, template_value):
|
|
# Take the previous body which we can trust without HTML editor reformatting
|
|
self.body = self.template_id.body_html
|
|
return super(MailComposerMixin, self.sudo())._render_field(field, *args, **kwargs)
|
|
|
|
elif composer_value == template_value:
|
|
# The value is the same as the mail template so we trust it
|
|
return super(MailComposerMixin, self.sudo())._render_field(field, *args, **kwargs)
|
|
|
|
return super(MailComposerMixin, self)._render_field(field, *args, **kwargs)
|