diff --git a/addons/mail/data/mail_data.xml b/addons/mail/data/mail_data.xml
index a6c9b62e019..fa48b112aa8 100644
--- a/addons/mail/data/mail_data.xml
+++ b/addons/mail/data/mail_data.xml
@@ -68,12 +68,12 @@
-
@@ -116,9 +116,9 @@
Sent by
-
+
-
+
using
Odoo.
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index 586c5e9c281..f5d4b4e3ac6 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -313,46 +313,9 @@ class MailTemplate(models.Model):
# RENDERING
# ----------------------------------------
- @api.model
- def _replace_local_links(self, html):
- """ Post-processing of html content to replace local links to absolute
- links, using web.base.url as base url. """
- if not html:
- return html
-
- # form a tree
- root = lxml.html.fromstring(html)
- if not len(root) and root.text is None and root.tail is None:
- html = u'%s
' % html
- root = lxml.html.fromstring(html, encoding='unicode')
-
- base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
- base = urls.url_parse(base_url)
-
- def _process_link(url):
- new_url = urls.url_parse(url)
- if new_url.scheme and (new_url.netloc or new_url.scheme == 'mailto'):
- return url
- return new_url.replace(scheme=base.scheme, netloc=base.netloc).to_url()
-
- # check all nodes, replace :
- # - img src -> check URL
- # - a href -> check URL
- for node in root.iter():
- if node.tag == 'a' and node.get('href'):
- node.set('href', _process_link(node.get('href')))
- elif node.tag == 'img' and not node.get('src', 'data').startswith(u'data'):
- node.set('src', _process_link(node.get('src')))
-
- html = lxml.html.tostring(root, pretty_print=False, method='html', encoding='unicode')
- # this is ugly, but lxml/etree tostring want to put everything in a 'div' that breaks the editor -> remove that
- if html.startswith(u'') and html.endswith(u'
'):
- html = html[5:-6]
- return html
-
@api.model
def render_post_process(self, html):
- html = self._replace_local_links(html)
+ html = self.env['mail.thread']._replace_local_links(html)
return html
@api.model
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 96d99fb85b5..8fcbed6ea16 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -23,9 +23,10 @@ from email.message import Message
from email.utils import formataddr
from lxml import etree
from werkzeug import url_encode
+from werkzeug import urls
from odoo import _, api, exceptions, fields, models, tools
-from odoo.tools import pycompat
+from odoo.tools import pycompat, ustr
from odoo.tools.safe_eval import safe_eval
@@ -374,6 +375,38 @@ class MailThread(models.AbstractModel):
# Technical methods / wrappers / tools
# ------------------------------------------------------
+ def _replace_local_links(self, html, base_url=None):
+ """ Replace local links by absolute links. It is required in various
+ cases, for example when sending emails on chatter or sending mass
+ mailings. It replaces
+
+ * href of links (mailto will not match the regex)
+ * src of images (base64 hardcoded data will not match the regex)
+ * styling using url like background-image: url
+
+ It is done using regex because it is shorten than using an html parser
+ to create a potentially complex soupe and hope to have a result that
+ has not been harmed.
+ """
+ if not html:
+ return html
+
+ html = ustr(html)
+
+ def _sub_relative2absolute(match):
+ # compute here to do it only if really necessary + cache will ensure it is done only once
+ # if not base_url
+ if not _sub_relative2absolute.base_url:
+ _sub_relative2absolute.base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url")
+ return match.group(1) + urls.url_join(_sub_relative2absolute.base_url, match.group(2))
+
+ _sub_relative2absolute.base_url = base_url
+ html = re.sub(r"""(
]*\ssrc=")(/[^/][^"]+)""", _sub_relative2absolute, html)
+ html = re.sub(r"""(]*\shref=")(/[^/][^"]+)""", _sub_relative2absolute, html)
+ html = re.sub(r"""(<[^>]+\bstyle="[^"]+\burl\('?)(/[^/'][^'")]+)""", _sub_relative2absolute, html)
+
+ return html
+
@api.model
def _garbage_collect_attachments(self):
""" Garbage collect lost mail attachments. Those are attachments
diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py
index 6999acc015b..4cee80af16a 100644
--- a/addons/mail/models/res_partner.py
+++ b/addons/mail/models/res_partner.py
@@ -73,17 +73,15 @@ class Partner(models.Model):
if message.res_id and message.model in self.env:
record = self.env[message.model].browse(message.res_id)
- company = user.company_id;
+ company = user.company_id
if record and hasattr(record, 'company_id'):
- company = record.company_id;
- company_name = company.name;
+ company = record.company_id
return {
'message': message,
'signature': signature,
'website_url': website_url,
'company': company,
- 'company_name': company_name,
'model_name': model_name,
'record': record,
'record_name': record_name,
@@ -187,6 +185,7 @@ class Partner(models.Model):
'subject': message.subject or (message.record_name and 'Re: %s' % message.record_name),
'body': base_template.render(template_ctx, engine='ir.qweb'),
}
+ fol_values['body'] = self.env['mail.thread']._replace_local_links(fol_values['body'])
# send email
new_emails, new_recipients_nbr = self._notify_send(fol_values['body'], fol_values['subject'], recipient_template_values['recipients'], **base_mail_values)
# update notifications
diff --git a/addons/mass_mailing/models/mail_mail.py b/addons/mass_mailing/models/mail_mail.py
index e67010ca3a7..5889bbeede1 100644
--- a/addons/mass_mailing/models/mail_mail.py
+++ b/addons/mass_mailing/models/mail_mail.py
@@ -71,15 +71,7 @@ class MailMail(models.Model):
new_href = href.replace(url, url + '/m/' + str(self.statistics_ids[0].id))
body = body.replace(href, new_href)
- # prepend tag for images using absolute urls
- domain = self.env["ir.config_parameter"].sudo().get_param("web.base.url")
- base = "" % 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('(
]*\ssrc=")(/[^/][^"]+)', _sub_relative2absolute, body)
- body = re.sub(r'(<[^>]+\bstyle="[^"]+\burl\(\'?)(/[^/\'][^\'")]+)', _sub_relative2absolute, body)
+ body = self.env['mail.thread']._replace_local_links(body)
# generate tracking URL
if self.statistics_ids:
diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py
index 3c7480abfb2..6989cf2b1a6 100644
--- a/addons/mass_mailing/models/mass_mailing.py
+++ b/addons/mass_mailing/models/mass_mailing.py
@@ -742,7 +742,7 @@ class MassMailing(models.Model):
raise UserError(_('Please select recipients.'))
# Convert links in absolute URLs before the application of the shortener
- mailing.body_html = self.env['mail.template']._replace_local_links(mailing.body_html)
+ mailing.body_html = self.env['mail.thread']._replace_local_links(mailing.body_html)
composer_values = {
'author_id': author_id,
diff --git a/addons/mass_mailing/wizard/test_mailing.py b/addons/mass_mailing/wizard/test_mailing.py
index 24b395c7c53..f1231fd2b38 100644
--- a/addons/mass_mailing/wizard/test_mailing.py
+++ b/addons/mass_mailing/wizard/test_mailing.py
@@ -20,7 +20,7 @@ class TestMassMailing(models.TransientModel):
test_emails = tools.email_split(self.email_to)
for test_mail in test_emails:
# Convert links in absolute URLs before the application of the shortener
- mailing.write({'body_html': self.env['mail.template']._replace_local_links(mailing.body_html)})
+ mailing.write({'body_html': self.env['mail.thread']._replace_local_links(mailing.body_html)})
mail_values = {
'email_from': mailing.email_from,
'reply_to': mailing.reply_to,
diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py
index 9505791bd98..8432cf54993 100644
--- a/addons/test_mail/tests/test_performance.py
+++ b/addons/test_mail/tests/test_performance.py
@@ -149,7 +149,7 @@ class TestAdvMailPerformance(TransactionCase):
'default_res_model': 'mail.test.activity',
})
- with self.assertQueryCount(admin=47, emp=53): # com runbot 46 - 52 // test_mail only: 35 - 41
+ with self.assertQueryCount(admin=47, emp=54): # com runbot 46 - 52 // test_mail only: 35 - 41
model.create({
'summary': 'Test Activity',
'res_id': record.id,
@@ -276,7 +276,7 @@ class TestHeavyMailPerformance(TransactionCase):
customer_id = self.customer.id
user_id = self.user_portal.id
- with self.assertQueryCount(admin=325, emp=388): # test_mail only: 308 - 368
+ with self.assertQueryCount(admin=325, emp=389): # test_mail only: 308 - 368
rec = self.env['mail.test.full'].create({
'name': 'Test',
'umbrella_id': umbrella_id,