[MIG] mail_tracking_mailgun: Migration to 11.0
This commit is contained in:
parent
02d0c30d3c
commit
ccee1257d8
@ -47,11 +47,12 @@ You can also config partner email autocheck with this system parameter:
|
||||
Usage
|
||||
=====
|
||||
|
||||
In your mail tracking status screens (explained on module *mail_tracking*), you will
|
||||
see a more accurate information, like the 'Received' or 'Bounced' status, which are
|
||||
not usually detected by normal SMTP servers.
|
||||
In your mail tracking status screens (explained on module *mail_tracking*), you
|
||||
will see a more accurate information, like the 'Received' or 'Bounced' status,
|
||||
which are not usually detected by normal SMTP servers.
|
||||
|
||||
It's also possible to make some checks to the partner's email addresses against the Mailgun API:
|
||||
It's also possible to make some checks to the partner's email addresses against
|
||||
the Mailgun API:
|
||||
|
||||
- Check if the partner's email is in Mailgun's bounced list.
|
||||
- Check the validity of the partner's mailbox.
|
||||
@ -64,7 +65,7 @@ short lifespan, so after 24h they won't be recoverable.
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/205/9.0
|
||||
:target: https://runbot.odoo-community.org/runbot/205/11.0
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import models
|
||||
|
@ -1,15 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2016 Tecnativa - Carlos Dauden
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# Copyright 2017 Tecnativa - David Vidal
|
||||
# Copyright 2017-18 Tecnativa - David Vidal
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
{
|
||||
"name": "Mail tracking for Mailgun",
|
||||
"summary": "Mail tracking and Mailgun webhooks integration",
|
||||
"version": "10.0.1.1.3",
|
||||
"version": "11.0.1.0.2",
|
||||
"category": "Social Network",
|
||||
"website": "https://odoo-community.org/",
|
||||
"website": "https://github.com/OCA/social",
|
||||
"author": "Tecnativa, "
|
||||
"Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import ir_mail_server
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from odoo import _, api, fields, models
|
||||
@ -60,8 +59,8 @@ class MailTrackingEmail(models.Model):
|
||||
|
||||
def _mailgun_signature(self, api_key, timestamp, token):
|
||||
return hmac.new(
|
||||
key=str(api_key),
|
||||
msg='{}{}'.format(str(timestamp), str(token)),
|
||||
key=bytes(api_key, 'utf-8'),
|
||||
msg=bytes('{}{}'.format(str(timestamp), str(token)), 'utf-8'),
|
||||
digestmod=hashlib.sha256).hexdigest()
|
||||
|
||||
def _mailgun_values(self):
|
||||
@ -115,7 +114,7 @@ class MailTrackingEmail(models.Model):
|
||||
ts = event.get('timestamp', False)
|
||||
try:
|
||||
ts = float(ts)
|
||||
except:
|
||||
except Exception:
|
||||
ts = False
|
||||
if ts:
|
||||
dt = datetime.utcfromtimestamp(ts)
|
||||
@ -135,7 +134,7 @@ class MailTrackingEmail(models.Model):
|
||||
'ua_type': 'client-type',
|
||||
'url': 'url',
|
||||
}
|
||||
for k, v in mapping.iteritems():
|
||||
for k, v in mapping.items():
|
||||
if event.get(v, False):
|
||||
metadata[k] = event[v]
|
||||
# Special field mapping
|
||||
@ -238,7 +237,7 @@ class MailTrackingEmail(models.Model):
|
||||
if not res or res.status_code != 200:
|
||||
raise ValidationError(_(
|
||||
"Couldn't retrieve Mailgun information"))
|
||||
content = json.loads(res.content, res.apparent_encoding)
|
||||
content = res.json()
|
||||
if "items" not in content:
|
||||
raise ValidationError(_("Event information not longer stored"))
|
||||
for item in content["items"]:
|
||||
|
@ -6,7 +6,6 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import requests
|
||||
import json
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import UserError
|
||||
@ -57,7 +56,7 @@ class ResPartner(models.Model):
|
||||
raise UserError(_(
|
||||
'Error %s trying to '
|
||||
'check mail' % res.status_code or 'of connection'))
|
||||
content = json.loads(res.content, res.apparent_encoding)
|
||||
content = res.json()
|
||||
if 'mailbox_verification' not in content:
|
||||
if not self.env.context.get('mailgun_auto_check'):
|
||||
raise UserError(
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import test_mailgun
|
||||
|
@ -7,7 +7,6 @@ from odoo.tools import mute_logger
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
import mock
|
||||
import json
|
||||
|
||||
_packagepath = 'odoo.addons.mail_tracking_mailgun'
|
||||
|
||||
@ -29,12 +28,12 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestMailgun, self).setUp()
|
||||
self.recipient = u'to@example.com'
|
||||
self.recipient = 'to@example.com'
|
||||
self.mail, self.tracking_email = self.mail_send()
|
||||
self.api_key = u'key-12345678901234567890123456789012'
|
||||
self.domain = u'example.com'
|
||||
self.token = u'f1349299097a51b9a7d886fcb5c2735b426ba200ada6e9e149'
|
||||
self.timestamp = u'1471021089'
|
||||
self.api_key = 'key-12345678901234567890123456789012'
|
||||
self.domain = 'example.com'
|
||||
self.token = 'f1349299097a51b9a7d886fcb5c2735b426ba200ada6e9e149'
|
||||
self.timestamp = '1471021089'
|
||||
self.signature = ('4fb6d4dbbe10ce5d620265dcd7a3c0b8'
|
||||
'ca0dede1433103891bc1ae4086e9d5b2')
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
@ -46,17 +45,17 @@ class TestMailgun(TransactionCase):
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
'mailgun.auto_check_partner_email', '')
|
||||
self.event = {
|
||||
'Message-Id': u'<xxx.xxx.xxx-openerp-xxx-res.partner@test_db>',
|
||||
'X-Mailgun-Sid': u'WyIwNjgxZSIsICJ0b0BleGFtcGxlLmNvbSIsICI3MG'
|
||||
'Message-Id': '<xxx.xxx.xxx-openerp-xxx-res.partner@test_db>',
|
||||
'X-Mailgun-Sid': 'WyIwNjgxZSIsICJ0b0BleGFtcGxlLmNvbSIsICI3MG'
|
||||
'I0MWYiXQ==',
|
||||
'token': self.token,
|
||||
'timestamp': self.timestamp,
|
||||
'signature': self.signature,
|
||||
'domain': u'example.com',
|
||||
'message-headers': u'[]',
|
||||
'domain': 'example.com',
|
||||
'message-headers': '[]',
|
||||
'recipient': self.recipient,
|
||||
'odoo_db': self.env.cr.dbname,
|
||||
'tracking_email_id': u'%s' % self.tracking_email.id
|
||||
'tracking_email_id': '%s' % self.tracking_email.id
|
||||
}
|
||||
self.metadata = {
|
||||
'ip': '127.0.0.1',
|
||||
@ -110,8 +109,8 @@ class TestMailgun(TransactionCase):
|
||||
'.mail_tracking_email')
|
||||
def test_bad_signature(self):
|
||||
self.event.update({
|
||||
'event': u'delivered',
|
||||
'signature': u'bad_signature',
|
||||
'event': 'delivered',
|
||||
'signature': 'bad_signature',
|
||||
})
|
||||
response = self.env['mail.tracking.email'].event_process(
|
||||
None, self.event, self.metadata)
|
||||
@ -121,7 +120,7 @@ class TestMailgun(TransactionCase):
|
||||
'.mail_tracking_email')
|
||||
def test_bad_event_type(self):
|
||||
self.event.update({
|
||||
'event': u'bad_event',
|
||||
'event': 'bad_event',
|
||||
})
|
||||
response = self.env['mail.tracking.email'].event_process(
|
||||
None, self.event, self.metadata)
|
||||
@ -131,19 +130,19 @@ class TestMailgun(TransactionCase):
|
||||
'.mail_tracking_email')
|
||||
def test_bad_db(self):
|
||||
self.event.update({
|
||||
'event': u'delivered',
|
||||
'odoo_db': u'bad_db',
|
||||
'event': 'delivered',
|
||||
'odoo_db': 'bad_db',
|
||||
})
|
||||
response = self.env['mail.tracking.email'].event_process(
|
||||
None, self.event, self.metadata)
|
||||
self.assertEqual('ERROR: Invalid DB', response)
|
||||
|
||||
def test_bad_ts(self):
|
||||
timestamp = u'7a' # Now time will be used instead
|
||||
timestamp = '7a' # Now time will be used instead
|
||||
signature = ('06cc05680f6e8110e59b41152b2d1c0f'
|
||||
'1045d755ef2880ff922344325c89a6d4')
|
||||
self.event.update({
|
||||
'event': u'delivered',
|
||||
'event': 'delivered',
|
||||
'timestamp': timestamp,
|
||||
'signature': signature,
|
||||
})
|
||||
@ -155,8 +154,8 @@ class TestMailgun(TransactionCase):
|
||||
'.mail_tracking_email')
|
||||
def test_tracking_not_found(self):
|
||||
self.event.update({
|
||||
'event': u'delivered',
|
||||
'tracking_email_id': u'bad_id',
|
||||
'event': 'delivered',
|
||||
'tracking_email_id': 'bad_id',
|
||||
})
|
||||
response = self.env['mail.tracking.email'].event_process(
|
||||
None, self.event, self.metadata)
|
||||
@ -165,7 +164,7 @@ class TestMailgun(TransactionCase):
|
||||
# https://documentation.mailgun.com/user_manual.html#tracking-deliveries
|
||||
def test_event_delivered(self):
|
||||
self.event.update({
|
||||
'event': u'delivered',
|
||||
'event': 'delivered',
|
||||
})
|
||||
response = self.env['mail.tracking.email'].event_process(
|
||||
None, self.event, self.metadata)
|
||||
@ -176,20 +175,20 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
# https://documentation.mailgun.com/user_manual.html#tracking-opens
|
||||
def test_event_opened(self):
|
||||
ip = u'127.0.0.1'
|
||||
user_agent = u'Odoo Test/8.0 Gecko Firefox/11.0'
|
||||
os_family = u'Linux'
|
||||
ua_family = u'Firefox'
|
||||
ua_type = u'browser'
|
||||
ip = '127.0.0.1'
|
||||
user_agent = 'Odoo Test/8.0 Gecko Firefox/11.0'
|
||||
os_family = 'Linux'
|
||||
ua_family = 'Firefox'
|
||||
ua_type = 'browser'
|
||||
self.event.update({
|
||||
'event': u'opened',
|
||||
'city': u'Mountain View',
|
||||
'country': u'US',
|
||||
'region': u'CA',
|
||||
'event': 'opened',
|
||||
'city': 'Mountain View',
|
||||
'country': 'US',
|
||||
'region': 'CA',
|
||||
'client-name': ua_family,
|
||||
'client-os': os_family,
|
||||
'client-type': ua_type,
|
||||
'device-type': u'desktop',
|
||||
'device-type': 'desktop',
|
||||
'ip': ip,
|
||||
'user-agent': user_agent,
|
||||
})
|
||||
@ -209,21 +208,21 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
# https://documentation.mailgun.com/user_manual.html#tracking-clicks
|
||||
def test_event_clicked(self):
|
||||
ip = u'127.0.0.1'
|
||||
user_agent = u'Odoo Test/8.0 Gecko Firefox/11.0'
|
||||
os_family = u'Linux'
|
||||
ua_family = u'Firefox'
|
||||
ua_type = u'browser'
|
||||
url = u'https://odoo-community.org'
|
||||
ip = '127.0.0.1'
|
||||
user_agent = 'Odoo Test/8.0 Gecko Firefox/11.0'
|
||||
os_family = 'Linux'
|
||||
ua_family = 'Firefox'
|
||||
ua_type = 'browser'
|
||||
url = 'https://odoo-community.org'
|
||||
self.event.update({
|
||||
'event': u'clicked',
|
||||
'city': u'Mountain View',
|
||||
'country': u'US',
|
||||
'region': u'CA',
|
||||
'event': 'clicked',
|
||||
'city': 'Mountain View',
|
||||
'country': 'US',
|
||||
'region': 'CA',
|
||||
'client-name': ua_family,
|
||||
'client-os': os_family,
|
||||
'client-type': ua_type,
|
||||
'device-type': u'tablet',
|
||||
'device-type': 'tablet',
|
||||
'ip': ip,
|
||||
'user-agent': user_agent,
|
||||
'url': url,
|
||||
@ -244,20 +243,20 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
# https://documentation.mailgun.com/user_manual.html#tracking-unsubscribes
|
||||
def test_event_unsubscribed(self):
|
||||
ip = u'127.0.0.1'
|
||||
user_agent = u'Odoo Test/8.0 Gecko Firefox/11.0'
|
||||
os_family = u'Linux'
|
||||
ua_family = u'Firefox'
|
||||
ua_type = u'browser'
|
||||
ip = '127.0.0.1'
|
||||
user_agent = 'Odoo Test/8.0 Gecko Firefox/11.0'
|
||||
os_family = 'Linux'
|
||||
ua_family = 'Firefox'
|
||||
ua_type = 'browser'
|
||||
self.event.update({
|
||||
'event': u'unsubscribed',
|
||||
'city': u'Mountain View',
|
||||
'country': u'US',
|
||||
'region': u'CA',
|
||||
'event': 'unsubscribed',
|
||||
'city': 'Mountain View',
|
||||
'country': 'US',
|
||||
'region': 'CA',
|
||||
'client-name': ua_family,
|
||||
'client-os': os_family,
|
||||
'client-type': ua_type,
|
||||
'device-type': u'mobile',
|
||||
'device-type': 'mobile',
|
||||
'ip': ip,
|
||||
'user-agent': user_agent,
|
||||
})
|
||||
@ -278,7 +277,7 @@ class TestMailgun(TransactionCase):
|
||||
# user_manual.html#tracking-spam-complaints
|
||||
def test_event_complained(self):
|
||||
self.event.update({
|
||||
'event': u'complained',
|
||||
'event': 'complained',
|
||||
})
|
||||
response = self.env['mail.tracking.email'].event_process(
|
||||
None, self.event, self.metadata)
|
||||
@ -290,12 +289,12 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
# https://documentation.mailgun.com/user_manual.html#tracking-bounces
|
||||
def test_event_bounced(self):
|
||||
code = u'550'
|
||||
error = (u"5.1.1 The email account does not exist.\n"
|
||||
code = '550'
|
||||
error = ("5.1.1 The email account does not exist.\n"
|
||||
"5.1.1 double-checking the recipient's email address")
|
||||
notification = u"Please, check recipient's email address"
|
||||
notification = "Please, check recipient's email address"
|
||||
self.event.update({
|
||||
'event': u'bounced',
|
||||
'event': 'bounced',
|
||||
'code': code,
|
||||
'error': error,
|
||||
'notification': notification,
|
||||
@ -312,11 +311,11 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
# https://documentation.mailgun.com/user_manual.html#tracking-failures
|
||||
def test_event_dropped(self):
|
||||
reason = u'hardfail'
|
||||
code = u'605'
|
||||
description = u'Not delivering to previously bounced address'
|
||||
reason = 'hardfail'
|
||||
code = '605'
|
||||
description = 'Not delivering to previously bounced address'
|
||||
self.event.update({
|
||||
'event': u'dropped',
|
||||
'event': 'dropped',
|
||||
'reason': reason,
|
||||
'code': code,
|
||||
'description': description,
|
||||
@ -336,10 +335,10 @@ class TestMailgun(TransactionCase):
|
||||
self.partner.email_bounced = False
|
||||
mock_request.get.return_value.apparent_encoding = 'ascii'
|
||||
mock_request.get.return_value.status_code = 200
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
mock_request.get.return_value.json.return_value = {
|
||||
'is_valid': True,
|
||||
'mailbox_verification': 'true',
|
||||
}, ensure_ascii=True)
|
||||
}
|
||||
# Trigger email auto validation in partner
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
'mailgun.auto_check_partner_email', 'True')
|
||||
@ -347,24 +346,24 @@ class TestMailgun(TransactionCase):
|
||||
self.assertFalse(self.partner.email_bounced)
|
||||
self.partner.email = 'xoxoxoxo@tecnativa.com'
|
||||
# Not a valid mailbox
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
mock_request.get.return_value.json.return_value = {
|
||||
'is_valid': True,
|
||||
'mailbox_verification': 'false',
|
||||
}, ensure_ascii=True)
|
||||
}
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
# Not a valid mail address
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
mock_request.get.return_value.json.return_value = {
|
||||
'is_valid': False,
|
||||
'mailbox_verification': 'false',
|
||||
}, ensure_ascii=True)
|
||||
}
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
# Unable to fully validate
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
mock_request.get.return_value.json.return_value = {
|
||||
'is_valid': True,
|
||||
'mailbox_verification': 'unknown',
|
||||
}, ensure_ascii=True)
|
||||
}
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
self.assertTrue(self.partner.email_bounced)
|
||||
@ -402,9 +401,7 @@ class TestMailgun(TransactionCase):
|
||||
|
||||
@mock.patch(_packagepath + '.models.mail_tracking_email.requests')
|
||||
def test_manual_check(self, mock_request):
|
||||
mock_request.get.return_value.content = json.dumps(self.response,
|
||||
ensure_ascii=True)
|
||||
mock_request.get.return_value.apparent_encoding = 'ascii'
|
||||
mock_request.get.return_value.json.return_value = self.response
|
||||
mock_request.get.return_value.status_code = 200
|
||||
self.tracking_email.action_manual_check_mailgun()
|
||||
event = self.env['mail.tracking.event'].search(
|
||||
@ -417,8 +414,6 @@ class TestMailgun(TransactionCase):
|
||||
with self.assertRaises(ValidationError):
|
||||
self.tracking_email.action_manual_check_mailgun()
|
||||
mock_request.get.return_value.status_code = 200
|
||||
mock_request.get.return_value.content = json.dumps('{}',
|
||||
ensure_ascii=True)
|
||||
mock_request.get.return_value.apparent_encoding = 'ascii'
|
||||
mock_request.get.return_value.json.return_value = {}
|
||||
with self.assertRaises(ValidationError):
|
||||
self.tracking_email.action_manual_check_mailgun()
|
||||
|
@ -13,14 +13,14 @@
|
||||
<field name="email_bounced" position="after">
|
||||
<label for="check_email_bounced" string="Mailgun"
|
||||
attrs="{'invisible': [('email', '=', False)]}"/>
|
||||
<group col="3" name="mailgun_buttons" attrs="{'invisible': [('email', '=', False)]}">
|
||||
<div name="mailgun_buttons" attrs="{'invisible': [('email', '=', False)]}">
|
||||
<button name="check_email_bounced" type="object" string="Check Mailgun" class="oe_link"/>
|
||||
<button name="check_email_validity" type="object" string="Check email validity" class="oe_link"/>
|
||||
<button name="force_set_bounced" type="object" string="Set Bounced" class="oe_link"
|
||||
attrs="{'invisible': [('email_bounced', '=', True)]}"/>
|
||||
<button name="force_unset_bounced" type="object" string="Unset Bounced" class="oe_link"
|
||||
attrs="{'invisible': [('email_bounced', '=', False)]}"/>
|
||||
</group>
|
||||
</div>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
Loading…
Reference in New Issue
Block a user