import logging import re from odoo import _, api, fields, models from odoo.exceptions import ValidationError from .redner import Redner logger = logging.getLogger(__name__) PREFIX = "tmpl_" expression_pattern = re.compile( r""" (?P<open_bracket>\{\{) # Match opening brackets {{ (?P<content>.*) # Match anything (?P<close_bracket>\}\}) # Match closing brackets }} """, re.VERBOSE, ) # Match every words which starts with PREFIX variable_pattern = re.compile(r"(?P<variable>%s[\w]+)" % PREFIX, re.VERBOSE) def get_redner_tmpl_keys(data) -> list: # noqa """Retrieve every substitution template variables, should be prefixed by ``tmpl_``. Args: data(string): xml body i.e:: <mjml><mj-body>{{tmpl_replace_me}}</mj-body></mjml> Returns: list: of keywords """ if not data: return [] return list( set( [ v.group("variable") for e in expression_pattern.finditer(data) for v in variable_pattern.finditer(e.group("content")) ] ) ) class RednerTemplate(models.Model): _name = "redner.template" name = fields.Char( string="Name", required=True, help="This is a name of template mjml redner", ) body = fields.Text( string="Template remote Id", translate=True, required=True, help="Code for the mjml redner template must be added here", ) slug = fields.Char(string="Slug") publish = fields.Boolean( string="Publish", default=False, help="set to false to add a draft template without publishing", ) is_mjml = fields.Boolean( string="Is MJML", default=True, help="set to false if your template doesn't contain MJML", ) detected_keywords = fields.Text( string="Keywords", readonly=True, compute="_compute_keywords" ) language = fields.Selection( string=_("Language"), selection=[("mustache", "mustache"), ("handlebar", "handlebar")], default="mustache", required=True, help="templating language", ) redner_id = fields.Char(string="Redner ID", readonly=True) produces = fields.Selection( selection=[("text/mjml", "MJML"), ("text/html", "HTML")], string="Produces", default="text/mjml", ) _redner = None @property def redner(self): """Try to avoid Redner instance to be over created""" if self._redner is None: # Bypass security rules when reading these configuration params. By # default, only some administrators have access to that model. config_model = self.env["ir.config_parameter"].sudo() self._redner = Redner( config_model.get_param("redner.api_key"), config_model.get_param("redner.server_url"), config_model.get_param("redner.account"), ) return self._redner @api.model def create(self, vals): """Overwrite create to create redner template""" # We depend on the API for consistency here # So raised error should not result with a created template vals["redner_id"] = self.redner.templates.account_template_add( vals.get("language"), vals.get("body"), name=vals.get("name"), produces=vals.get("produces"), ) return super(RednerTemplate, self).create(vals) @api.multi def write(self, vals): """Overwrite write to update redner template""" # Similar to the "send_to_rednerd_server" method; not worth factoring # out. # We depend on the API for consistency here # So raised error should not result with an updated template try: vals["redner_id"] = self.redner.templates.account_template_update( self.redner_id, vals.get("language", self.language), vals.get("body", self.body), produces=vals.get("produces"), ) except ValidationError: vals["redner_id"] = self.redner.templates.account_template_add( vals.get("language", self.language), vals.get("body", self.body), name=vals.get("name", self.name), produces=vals.get("produces"), ) return super(RednerTemplate, self).write(vals) @api.multi def unlink(self): """Overwrite unlink to delete redner template""" # We do NOT depend on the API for consistency here # So raised error should not result block template deletion try: self.redner.templates.account_template_delete(self.redner_id) except Exception: pass return super(RednerTemplate, self).unlink() @api.one @api.depends("body") def _compute_keywords(self): self.detected_keywords = get_redner_tmpl_keys(self.body) @api.model def get_keywords(self): """ Return mjml redner keywords """ return get_redner_tmpl_keys(self.body) @api.one def send_to_rednerd_server(self): """Send templates to the rednerd server. Useful when you have existing templates you want to register onto a new rednerd server (or with a new user). """ # Similar to the "write" method override; not worth factoring out. try: self.redner.templates.account_template_update( self.redner_id, self.language, self.body, self.name ) except ValidationError: self.redner_id = self.redner.templates.account_template_add( self.language, self.body, self.name )