@@ -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 # ------------------------------------------------------------
0 commit comments