Skip to content

Commit 1a3e713

Browse files
committed
[FIX] mail: allow regular users to create mail non-dynamic templates
closes odoo#88903 Signed-off-by: Denis Ledoux (dle) <[email protected]>
1 parent 992a68a commit 1a3e713

File tree

6 files changed

+102
-5
lines changed

6 files changed

+102
-5
lines changed

addons/mail/i18n/mail.pot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4869,6 +4869,7 @@ msgstr ""
48694869
#. module: mail
48704870
#: code:addons/mail/models/mail_render_mixin.py:0
48714871
#: code:addons/mail/models/mail_render_mixin.py:0
4872+
#: code:addons/mail/models/mail_render_mixin.py:0
48724873
#, python-format
48734874
msgid "Only users belonging to the \"%s\" group can modify dynamic templates."
48744875
msgstr ""

addons/mail/models/mail_render_mixin.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,23 @@ def _valid_field_parameter(self, field, name):
127127
# allow specifying rendering options directly from field when using the render mixin
128128
return name in ['render_engine', 'render_options'] or super()._valid_field_parameter(field, name)
129129

130+
@api.model_create_multi
131+
def create(self, values_list):
132+
record = super().create(values_list)
133+
if self._unrestricted_rendering:
134+
# If the rendering is unrestricted (e.g. mail.template),
135+
# check the user is part of the mail editor group to create a new template if the template is dynamic
136+
record._check_access_right_dynamic_template()
137+
return record
138+
139+
def write(self, vals):
140+
super().write(vals)
141+
if self._unrestricted_rendering:
142+
# If the rendering is unrestricted (e.g. mail.template),
143+
# check the user is part of the mail editor group to modify a template if the template is dynamic
144+
self._check_access_right_dynamic_template()
145+
return True
146+
130147
# ------------------------------------------------------------
131148
# TOOLS
132149
# ------------------------------------------------------------
@@ -219,6 +236,46 @@ def _prepend_preview(self, html, preview):
219236
""").format(preview_markup)
220237
return tools.prepend_html_content(html, html_preview)
221238
return html
239+
240+
# ------------------------------------------------------------
241+
# SECURITY
242+
# ------------------------------------------------------------
243+
244+
def _is_dynamic(self):
245+
for template in self:
246+
for fname, field in template._fields.items():
247+
engine = getattr(field, 'render_engine', 'inline_template')
248+
if engine in ('qweb', 'qweb_view'):
249+
if self._is_dynamic_template_qweb(template[fname]):
250+
return True
251+
else:
252+
if self._is_dynamic_template_inline_template(template[fname]):
253+
return True
254+
return False
255+
256+
@api.model
257+
def _is_dynamic_template_qweb(self, template_src):
258+
if template_src:
259+
try:
260+
node = html.fragment_fromstring(template_src, create_parent='div')
261+
self.env["ir.qweb"]._compile(node, options={'raise_on_code': True})
262+
except QWebCodeFound:
263+
return True
264+
return False
265+
266+
@api.model
267+
def _is_dynamic_template_inline_template(self, template_txt):
268+
if template_txt:
269+
template_instructions = parse_inline_template(str(template_txt))
270+
if len(template_instructions) > 1 or template_instructions[0][1]:
271+
return True
272+
return False
273+
274+
def _check_access_right_dynamic_template(self):
275+
if not self.env.su and not self.env.user.has_group('mail.group_mail_template_editor') and self._is_dynamic():
276+
group = self.env.ref('mail.group_mail_template_editor')
277+
raise AccessError(_('Only users belonging to the "%s" group can modify dynamic templates.', group.name))
278+
222279
# ------------------------------------------------------------
223280
# RENDERING
224281
# ------------------------------------------------------------

addons/mail/security/ir.model.access.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ access_mail_tracking_value_portal,mail.tracking.value.portal,model_mail_tracking
3131
access_mail_tracking_value_user,mail.tracking.value.user,model_mail_tracking_value,base.group_user,0,0,0,0
3232
access_mail_tracking_value_system,mail.tracking.value.system,model_mail_tracking_value,base.group_system,1,1,1,1
3333
access_publisher_warranty_contract_all,publisher.warranty.contract.all,model_publisher_warranty_contract,,1,1,1,1
34-
access_mail_template,mail.template,model_mail_template,base.group_user,1,0,0,0
34+
access_mail_template,mail.template,model_mail_template,base.group_user,1,1,1,1
3535
access_mail_template_editor,mail.template_editor,model_mail_template,mail.group_mail_template_editor,1,1,1,1
3636
access_mail_template_system,mail.template_system,model_mail_template,base.group_system,1,1,1,1
3737
access_mail_shortcode,mail.shortcode,model_mail_shortcode,base.group_user,1,1,1,1

addons/mail/security/mail_security.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,28 @@
6565
<field name="perm_unlink" eval="False"/>
6666
</record>
6767

68+
<record id="mail_template_employee_rule" model="ir.rule">
69+
<field name="name">Employees can only change their own templates</field>
70+
<field name="model_id" ref="model_mail_template"/>
71+
<field name="domain_force">[('create_uid', '=', user.id)]</field>
72+
<field name="groups" eval="[Command.link(ref('base.group_user'))]"/>
73+
<field name="perm_create" eval="True"/>
74+
<field name="perm_read" eval="False"/>
75+
<field name="perm_write" eval="True"/>
76+
<field name="perm_unlink" eval="True"/>
77+
</record>
78+
79+
<record id="mail_template_editor_rule" model="ir.rule">
80+
<field name="name">Mail Template Editors - Edit All Templates</field>
81+
<field name="model_id" ref="model_mail_template"/>
82+
<field name="domain_force">[(1, '=', 1)]</field>
83+
<field name="groups" eval="[Command.link(ref('group_mail_template_editor')), Command.link(ref('base.group_system'))]"/>
84+
<field name="perm_create" eval="True"/>
85+
<field name="perm_read" eval="False"/>
86+
<field name="perm_write" eval="True"/>
87+
<field name="perm_unlink" eval="True"/>
88+
</record>
89+
6890
<record id="res_users_settings_rule_admin" model="ir.rule">
6991
<field name="name">Administrators can access all User Settings.</field>
7092
<field name="model_id" ref="model_res_users_settings"/>

addons/mail/tests/test_mail_template.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,25 @@ def test_mail_template_acl(self):
5757
mail_template.with_user(self.user_admin).name = 'New name'
5858
self.assertEqual(mail_template.name, 'New name')
5959

60-
# Standard employee can not
60+
# Standard employee can create and edit non-dynamic templates
61+
employee_template = self.env['mail.template'].with_user(self.user_employee).create({'body_html': '<p>foo</p>'})
62+
63+
employee_template.with_user(self.user_employee).body_html = '<p>bar</p>'
64+
65+
employee_template = self.env['mail.template'].with_user(self.user_employee).create({'email_to': '[email protected]'})
66+
67+
employee_template.with_user(self.user_employee).email_to = '[email protected]'
68+
69+
# Standard employee cannot create and edit templates with dynamic qweb
70+
with self.assertRaises(AccessError):
71+
self.env['mail.template'].with_user(self.user_employee).create({'body_html': '<p t-esc="\'foo\'"></p>'})
72+
73+
with self.assertRaises(AccessError):
74+
mail_template.with_user(self.user_employee).body_html = '<p t-esc="\'foo\'"></p>'
75+
76+
# Standard employee cannot create and edit templates with dynamic inline fields
6177
with self.assertRaises(AccessError):
62-
self.env['mail.template'].with_user(self.user_employee).create({})
78+
self.env['mail.template'].with_user(self.user_employee).create({'email_to': '{{ object.partner_id.email }}'})
6379

6480
with self.assertRaises(AccessError):
65-
mail_template.with_user(self.user_employee).name = 'Test write'
81+
mail_template.with_user(self.user_employee).email_to = '{{ object.partner_id.email }}'

addons/mail/wizard/mail_compose_message_views.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@
7979
<button string="Send" attrs="{'invisible': [('is_log', '=', True)]}" name="action_send_mail" type="object" class="btn-primary o_mail_send" data-hotkey="q"/>
8080
<button string="Log" attrs="{'invisible': [('is_log', '=', False)]}" name="action_send_mail" type="object" class="btn-primary" data-hotkey="q"/>
8181
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z" />
82-
<button icon="fa-lg fa-save" type="object" groups="mail.group_mail_template_editor"
82+
<button icon="fa-lg fa-save" type="object"
8383
name="action_save_as_template" string="Save as new template"
84+
attrs="{'invisible': [('can_edit_body', '=', False)]}"
8485
class="float-right btn-secondary" help="Save as a new template"/>
8586
</footer>
8687
</form>

0 commit comments

Comments
 (0)