You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.7 KiB
126 lines
4.7 KiB
# -*- coding: utf-8 -*-
|
|
# Copyright 2019 Therp BV <https://therp.nl>
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
|
import uuid
|
|
from werkzeug.routing import Rule, Map
|
|
from odoo import models
|
|
from odoo.tools.image import image_resize_image
|
|
from odoo.addons.web.controllers.main import Binary
|
|
from odoo.modules import get_resource_path
|
|
from odoo.addons.base.ir.ir_mail_server import encode_header_param
|
|
from lxml.html.soupparser import fromstring
|
|
from lxml.etree import tostring
|
|
from base64 import b64encode, b64decode
|
|
from email.mime.image import MIMEImage
|
|
from email import Encoders
|
|
|
|
|
|
class IrMailServer(models.Model):
|
|
_inherit = 'ir.mail_server'
|
|
|
|
def build_email(
|
|
self,
|
|
email_from,
|
|
email_to,
|
|
subject,
|
|
body,
|
|
email_cc=None,
|
|
email_bcc=None,
|
|
reply_to=None,
|
|
attachments=None,
|
|
message_id=None,
|
|
references=None,
|
|
object_id=None,
|
|
subtype='plain',
|
|
headers=None,
|
|
body_alternative=None,
|
|
subtype_alternative='plain'):
|
|
result = super(IrMailServer, self).build_email(
|
|
email_from=email_from,
|
|
email_to=email_to,
|
|
subject=subject,
|
|
body=body,
|
|
email_cc=email_cc,
|
|
email_bcc=email_bcc,
|
|
reply_to=reply_to,
|
|
attachments=attachments,
|
|
message_id=message_id,
|
|
references=references,
|
|
object_id=object_id,
|
|
subtype=subtype,
|
|
headers=headers,
|
|
body_alternative=body_alternative,
|
|
subtype_alternative=subtype_alternative,
|
|
)
|
|
return self._build_email_replace_img_src(result, result)
|
|
|
|
def _build_email_replace_img_src(self, email, email_part):
|
|
""" Given a message, find it's img tags and if they
|
|
are URLs, replace them with cids.
|
|
|
|
:param email: The root email.message.Message, used for reference
|
|
:param email_part: The current part of email being examined
|
|
"""
|
|
if email_part.is_multipart():
|
|
for part in email_part.get_payload():
|
|
self._build_email_replace_img_src(email, part)
|
|
else:
|
|
if email_part.get_content_subtype() == 'html':
|
|
body = email_part.get_payload(decode=True)
|
|
root = fromstring(body)
|
|
for img in root.xpath(
|
|
"//img[starts-with(@src, '/web/image')]"):
|
|
base_url = self.env['ir.config_parameter'].get_param(
|
|
'web.base.url')
|
|
response = self._get_image(base_url, img.get('src'))
|
|
cid = uuid.uuid4().hex
|
|
filename_rfc2047 = encode_header_param(cid)
|
|
part = MIMEImage(response)
|
|
part.set_param('name', filename_rfc2047)
|
|
part.add_header(
|
|
'Content-Disposition',
|
|
'inline',
|
|
cid=cid,
|
|
filename=filename_rfc2047,
|
|
)
|
|
part.set_payload(response)
|
|
Encoders.encode_base64(part)
|
|
# attach the image into the email as attachment
|
|
email.attach(part)
|
|
img.set('src', 'cid:%s' % (cid))
|
|
email_part.set_payload(b64encode(tostring(root)))
|
|
return email
|
|
|
|
def _get_image(self, base_url, src):
|
|
""" This function emulates the operations of
|
|
odoo.addons.web.controllers.main.Binary.content_image() because
|
|
we cannot call this from here
|
|
Given an absolute url, return the raw image data.
|
|
"""
|
|
routes = Binary.content_image.routing['routes']
|
|
map_rules = Map([Rule(x) for x in routes])
|
|
urls = map_rules.bind(base_url)
|
|
endpoint, kwargs = urls.match(src)
|
|
status, headers, content = self.env['ir.http'].binary_content(
|
|
env=self.env, **kwargs)
|
|
height = int(kwargs.get('height', 0))
|
|
width = int(kwargs.get('width', 0))
|
|
if content and (height or width):
|
|
if height > 500:
|
|
height = 500
|
|
if width > 500:
|
|
width = 500
|
|
content = image_resize_image(
|
|
content,
|
|
(width or None, height or None),
|
|
filetype='PNG',
|
|
)
|
|
if content:
|
|
content = b64decode(content)
|
|
else:
|
|
path_placeholder = '/web/static/src/img/placeholder.png'
|
|
with open(get_resource_path(path_placeholder)) as f:
|
|
content = f.read()
|
|
else:
|
|
content = b64decode(content)
|
|
return content
|