def send_get_mail_body(self, partner=None): """ Override to add the tracking URL to the body and to add Statistic_id in shorted urls """ # TDE: temporary addition (mail was parameter) due to semi-new-API self.ensure_one() body = super(MailMail, self).send_get_mail_body(partner=partner) if self.mailing_id and body and self.statistics_ids: for match in re.findall(URL_REGEX, self.body_html): href = match[0] url = match[1] parsed = werkzeug.urls.url_parse(url, scheme='http') if parsed.scheme.startswith('http') and parsed.path.startswith( '/r/'): new_href = href.replace( url, url + '/m/' + str(self.statistics_ids[0].id)) body = body.replace(href, new_href) # prepend <base> tag for images using absolute urls domain = self.env["ir.config_parameter"].sudo().get_param( "web.base.url") base = "<base href='%s'>" % domain body = tools.append_content_to_html(base, body, plaintext=False, container_tag='div') # resolve relative image url to absolute for outlook.com def _sub_relative2absolute(match): return match.group(1) + werkzeug.urls.url_join( domain, match.group(2)) body = re.sub('(<img(?=\s)[^>]*\ssrc=")(/[^/][^"]+)', _sub_relative2absolute, body) body = re.sub(r'(<[^>]+\bstyle="[^"]+\burl\(\'?)(/[^/\'][^\'")]+)', _sub_relative2absolute, body) # generate tracking URL if self.statistics_ids: tracking_url = self._get_tracking_url(partner) if tracking_url: body = tools.append_content_to_html(body, tracking_url, plaintext=False, container_tag='div') return body
def send_get_mail_body(self, partner=None): """ Short-circuit parent method for mail groups, replace the default footer with one appropriate for mailing-lists.""" if self.model == 'mail.channel' and self.res_id: # no super() call on purpose, no private links that could be quoted! channel = self.env['mail.channel'].browse(self.res_id) base_url = self.env['ir.config_parameter'].sudo().get_param( 'web.base.url') vals = { 'maillist': _('Mailing-List'), 'post_to': _('Post to'), 'unsub': _('Unsubscribe'), 'mailto': 'mailto:%s@%s' % (channel.alias_name, channel.alias_domain), 'group_url': '%s/groups/%s' % (base_url, slug(channel)), 'unsub_url': '%s/groups?unsubscribe' % (base_url, ), } footer = """_______________________________________________ %(maillist)s: %(group_url)s %(post_to)s: %(mailto)s %(unsub)s: %(unsub_url)s """ % vals body = tools.append_content_to_html(self.body, footer, container_tag='div') return body else: return super(MailMail, self).send_get_mail_body(partner=partner)
def test_append_to_html(self): test_samples = [ ('<!DOCTYPE...><HTML encoding="blah">some <b>content</b></HtMl>', '--\nYours truly', True, True, False, '<!DOCTYPE...><html encoding="blah">some <b>content</b>\n<pre>--\nYours truly</pre>\n</html>' ), ('<!DOCTYPE...><HTML encoding="blah">some <b>content</b></HtMl>', '--\nYours truly', True, False, False, '<!DOCTYPE...><html encoding="blah">some <b>content</b>\n<p>--<br/>Yours truly</p>\n</html>' ), ('<html><body>some <b>content</b></body></html>', '<!DOCTYPE...>\n<html><body>\n<p>--</p>\n<p>Yours truly</p>\n</body>\n</html>', False, False, False, '<html><body>some <b>content</b>\n\n\n<p>--</p>\n<p>Yours truly</p>\n\n\n</body></html>' ), ] for html, content, plaintext_flag, preserve_flag, container_tag, expected in test_samples: self.assertEqual( append_content_to_html(html, content, plaintext_flag, preserve_flag, container_tag), expected, 'append_content_to_html is broken')
def generate_email(self, res_ids, fields=None): """Generates an email from the template for given the given model based on records given by res_ids. :param template_id: id of the template to render. :param res_id: id of the record to use for rendering the template (model is taken from template definition) :returns: a dict containing all relevant fields for creating a new mail.mail entry, with one extra key ``attachments``, in the format [(report_name, data)] where data is base64 encoded. """ self.ensure_one() multi_mode = True if isinstance(res_ids, pycompat.integer_types): res_ids = [res_ids] multi_mode = False if fields is None: fields = [ 'subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'scheduled_date' ] res_ids_to_templates = self.get_email_template(res_ids) # templates: res_id -> template; template -> res_ids templates_to_res_ids = {} for res_id, template in res_ids_to_templates.items(): templates_to_res_ids.setdefault(template, []).append(res_id) results = dict() for template, template_res_ids in templates_to_res_ids.items(): Template = self.env['mail.template'] # generate fields value for all res_ids linked to the current template if template.lang: Template = Template.with_context( lang=template._context.get('lang')) for field in fields: Template = Template.with_context(safe=field in {'subject'}) generated_field_values = Template.render_template( getattr(template, field), template.model, template_res_ids, post_process=(field == 'body_html')) for res_id, field_value in generated_field_values.items(): results.setdefault(res_id, dict())[field] = field_value # compute recipients if any(field in fields for field in ['email_to', 'partner_to', 'email_cc']): results = template.generate_recipients(results, template_res_ids) # update values for all res_ids for res_id in template_res_ids: values = results[res_id] # body: add user signature, sanitize if 'body_html' in fields and template.user_signature: signature = self.env.user.signature if signature: values['body_html'] = tools.append_content_to_html( values['body_html'], signature, plaintext=False) if values.get('body_html'): values['body'] = tools.html_sanitize(values['body_html']) # technical settings values.update( mail_server_id=template.mail_server_id.id or False, auto_delete=template.auto_delete, model=template.model, res_id=res_id or False, attachment_ids=[ attach.id for attach in template.attachment_ids ], ) # Add report in attachments: generate once for all template_res_ids if template.report_template: for res_id in template_res_ids: attachments = [] report_name = self.render_template(template.report_name, template.model, res_id) report = template.report_template report_service = report.report_name if report.report_type not in ['qweb-html', 'qweb-pdf']: raise UserError( _('Unsupported report type %s found.') % report.report_type) result, format = report.render_qweb_pdf([res_id]) # TODO in trunk, change return format to binary to match message_post expected format result = base64.b64encode(result) if not report_name: report_name = 'report.' + report_service ext = "." + format if not report_name.endswith(ext): report_name += ext attachments.append((report_name, result)) results[res_id]['attachments'] = attachments return multi_mode and results or results[res_ids[0]]
def onchange_template_id(self, template_id, composition_mode, model, res_id): """ - mass_mailing: we cannot render, so return the template values - normal mode: return rendered values /!\ for x2many field, this onchange return command instead of ids """ if template_id and composition_mode == 'mass_mail': template = self.env['mail.template'].browse(template_id) fields = [ 'subject', 'body_html', 'email_from', 'reply_to', 'mail_server_id' ] values = dict((field, getattr(template, field)) for field in fields if getattr(template, field)) if template.attachment_ids: values['attachment_ids'] = [ att.id for att in template.attachment_ids ] if template.mail_server_id: values['mail_server_id'] = template.mail_server_id.id if template.user_signature and 'body_html' in values: signature = self.env.user.signature values['body_html'] = tools.append_content_to_html( values['body_html'], signature, plaintext=False) elif template_id: values = self.generate_email_for_composer(template_id, [res_id])[res_id] # transform attachments into attachment_ids; not attached to the document because this will # be done further in the posting process, allowing to clean database if email not send Attachment = self.env['ir.attachment'] for attach_fname, attach_datas in values.pop('attachments', []): data_attach = { 'name': attach_fname, 'datas': attach_datas, 'datas_fname': attach_fname, 'res_model': 'mail.compose.message', 'res_id': 0, 'type': 'binary', # override default_type from context, possibly meant for another model! } values.setdefault('attachment_ids', list()).append( Attachment.create(data_attach).id) else: default_values = self.with_context( default_composition_mode=composition_mode, default_model=model, default_res_id=res_id).default_get([ 'composition_mode', 'model', 'res_id', 'parent_id', 'partner_ids', 'subject', 'body', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id' ]) values = dict((key, default_values[key]) for key in [ 'subject', 'body', 'partner_ids', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id' ] if key in default_values) if values.get('body_html'): values['body'] = values.pop('body_html') # This onchange should return command instead of ids for x2many field. # ORM handle the assignation of command list on new onchange (api.v8), # this force the complete replacement of x2many field with # command and is compatible with onchange api.v7 values = self._convert_to_write(values) return {'value': values}