Purpose ======= Purpose of this commit is to add a new group for the mail template designer. Goal is to make roles clearer: managers edit templates, users use them. This commit allow some designers / managers to make email template and to let others users use those email templates. Specifications ============== When this feature is enabled in the Settings page, a new group is required to modify email templates in a composer like wizard or to make dynamic content. This allows to separate managers editing / composing templates from standard users that use them. If the current does not have this group, the email body will be in readonly mode if he selected an email template. That way we force him to use the email template that the manager made. Technical ========= New Group --------- Only users in this group will be able to create / write email template or to write Jinja code in the mail composer (including other fields like subject in mailing). By default, all internal users have this group. Mass mailing users also have this group as writing mailings is about the same management level as writing templates. Mail Composer Mixin ------------------- In comment mode, the template is rendered and then saved on the body field so non-"Mail Template Editor" users can load email templates. But in mass mode, the body of the template is saved and then rendered and many things change the body (HTML sanitizer, web editor move inline CSS properties, add / remove spaces...). So in this case, we can not know if the user changed the body or not. That is why we put the body field in readonly mode so, it is not modified by the web editor. Jinja code detection -------------------- To detect dynamic Jinja content, we compile the template, and we browse the AST. If we do not have a single "Template Data" node, we assume that the template is dynamic. When we detect the template as static, we do not render it. That way we avoid unnecessary rendering. Code cleaning ------------- Move Jinja import into tools so that it is outside of mail framework code. Task-2187263 closes odoo/odoo#75840 Related: odoo/enterprise#20547 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models, _
|
|
|
|
|
|
class SMSTemplate(models.Model):
|
|
"Templates for sending SMS"
|
|
_name = "sms.template"
|
|
_inherit = ['mail.render.mixin']
|
|
_description = 'SMS Templates'
|
|
|
|
_unrestricted_rendering = True
|
|
|
|
@api.model
|
|
def default_get(self, fields):
|
|
res = super(SMSTemplate, self).default_get(fields)
|
|
if not fields or 'model_id' in fields and not res.get('model_id') and res.get('model'):
|
|
res['model_id'] = self.env['ir.model']._get(res['model']).id
|
|
return res
|
|
|
|
name = fields.Char('Name', translate=True)
|
|
model_id = fields.Many2one(
|
|
'ir.model', string='Applies to', required=True,
|
|
domain=['&', ('is_mail_thread_sms', '=', True), ('transient', '=', False)],
|
|
help="The type of document this template can be used with", ondelete='cascade')
|
|
model = fields.Char('Related Document Model', related='model_id.model', index=True, store=True, readonly=True)
|
|
body = fields.Char('Body', translate=True, required=True)
|
|
# Use to create contextual action (same as for email template)
|
|
sidebar_action_id = fields.Many2one('ir.actions.act_window', 'Sidebar action', readonly=True, copy=False,
|
|
help="Sidebar action to make this template available on records "
|
|
"of the related document model")
|
|
|
|
# Overrides of mail.render.mixin
|
|
@api.depends('model')
|
|
def _compute_render_model(self):
|
|
for template in self:
|
|
template.render_model = template.model
|
|
|
|
# ------------------------------------------------------------
|
|
# CRUD
|
|
# ------------------------------------------------------------
|
|
|
|
@api.returns('self', lambda value: value.id)
|
|
def copy(self, default=None):
|
|
default = dict(default or {},
|
|
name=_("%s (copy)", self.name))
|
|
return super(SMSTemplate, self).copy(default=default)
|
|
|
|
def unlink(self):
|
|
self.sudo().mapped('sidebar_action_id').unlink()
|
|
return super(SMSTemplate, self).unlink()
|
|
|
|
def action_create_sidebar_action(self):
|
|
ActWindow = self.env['ir.actions.act_window']
|
|
view = self.env.ref('sms.sms_composer_view_form')
|
|
|
|
for template in self:
|
|
button_name = _('Send SMS (%s)', template.name)
|
|
action = ActWindow.create({
|
|
'name': button_name,
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'sms.composer',
|
|
# Add default_composition_mode to guess to determine if need to use mass or comment composer
|
|
'context': "{'default_template_id' : %d, 'sms_composition_mode': 'guess', 'default_res_ids': active_ids, 'default_res_id': active_id}" % (template.id),
|
|
'view_mode': 'form',
|
|
'view_id': view.id,
|
|
'target': 'new',
|
|
'binding_model_id': template.model_id.id,
|
|
})
|
|
template.write({'sidebar_action_id': action.id})
|
|
return True
|
|
|
|
def action_unlink_sidebar_action(self):
|
|
for template in self:
|
|
if template.sidebar_action_id:
|
|
template.sidebar_action_id.unlink()
|
|
return True
|