diff --git a/mail_tracking_mailgun/README.rst b/mail_tracking_mailgun/README.rst index eb0ec7e..3b83516 100644 --- a/mail_tracking_mailgun/README.rst +++ b/mail_tracking_mailgun/README.rst @@ -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 ====================== diff --git a/mail_tracking_mailgun/__init__.py b/mail_tracking_mailgun/__init__.py index ec50cfc..69f7bab 100644 --- a/mail_tracking_mailgun/__init__.py +++ b/mail_tracking_mailgun/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import models diff --git a/mail_tracking_mailgun/__manifest__.py b/mail_tracking_mailgun/__manifest__.py index 419b1ea..8eba373 100644 --- a/mail_tracking_mailgun/__manifest__.py +++ b/mail_tracking_mailgun/__manifest__.py @@ -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", diff --git a/mail_tracking_mailgun/models/__init__.py b/mail_tracking_mailgun/models/__init__.py index b0449e5..a0efd36 100644 --- a/mail_tracking_mailgun/models/__init__.py +++ b/mail_tracking_mailgun/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import ir_mail_server diff --git a/mail_tracking_mailgun/models/mail_tracking_email.py b/mail_tracking_mailgun/models/mail_tracking_email.py index fa431dd..6486396 100644 --- a/mail_tracking_mailgun/models/mail_tracking_email.py +++ b/mail_tracking_mailgun/models/mail_tracking_email.py @@ -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"]: diff --git a/mail_tracking_mailgun/models/res_partner.py b/mail_tracking_mailgun/models/res_partner.py index c5f531b..7d13bae 100644 --- a/mail_tracking_mailgun/models/res_partner.py +++ b/mail_tracking_mailgun/models/res_partner.py @@ -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( diff --git a/mail_tracking_mailgun/tests/__init__.py b/mail_tracking_mailgun/tests/__init__.py index bfbcec7..c9fdfe6 100644 --- a/mail_tracking_mailgun/tests/__init__.py +++ b/mail_tracking_mailgun/tests/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import test_mailgun diff --git a/mail_tracking_mailgun/tests/test_mailgun.py b/mail_tracking_mailgun/tests/test_mailgun.py index 45cecd6..db4a98b 100644 --- a/mail_tracking_mailgun/tests/test_mailgun.py +++ b/mail_tracking_mailgun/tests/test_mailgun.py @@ -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'', - 'X-Mailgun-Sid': u'WyIwNjgxZSIsICJ0b0BleGFtcGxlLmNvbSIsICI3MG' + 'Message-Id': '', + '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() diff --git a/mail_tracking_mailgun/views/res_partner.xml b/mail_tracking_mailgun/views/res_partner.xml index 9ad12fe..82ffd3e 100644 --- a/mail_tracking_mailgun/views/res_partner.xml +++ b/mail_tracking_mailgun/views/res_partner.xml @@ -13,14 +13,14 @@