2018-03-19 16:41:26 +01:00
|
|
|
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
2016-06-14 17:22:17 +02:00
|
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
|
|
|
2019-07-24 12:39:27 +02:00
|
|
|
import base64
|
2019-11-18 11:46:59 +01:00
|
|
|
import time
|
|
|
|
|
|
|
|
import mock
|
2019-10-17 03:28:42 +02:00
|
|
|
import psycopg2
|
|
|
|
import psycopg2.errorcodes
|
2019-07-05 14:20:27 +02:00
|
|
|
from lxml import etree
|
2016-06-14 17:22:17 +02:00
|
|
|
|
2020-03-19 20:30:34 +01:00
|
|
|
from odoo import http
|
2019-11-18 11:46:59 +01:00
|
|
|
from odoo.tests.common import TransactionCase
|
|
|
|
from odoo.tools import mute_logger
|
|
|
|
|
|
|
|
from ..controllers.main import BLANK, MailTrackingController
|
|
|
|
|
|
|
|
mock_send_email = "odoo.addons.base.models.ir_mail_server." "IrMailServer.send_email"
|
2016-06-14 17:22:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
class FakeUserAgent(object):
|
2019-11-18 11:46:59 +01:00
|
|
|
browser = "Test browser"
|
|
|
|
platform = "Test platform"
|
2016-06-14 17:22:17 +02:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
"""Return name"""
|
2019-11-18 11:46:59 +01:00
|
|
|
return "Test suite"
|
2016-06-14 17:22:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestMailTracking(TransactionCase):
|
2016-10-14 15:42:29 +02:00
|
|
|
def setUp(self, *args, **kwargs):
|
|
|
|
super(TestMailTracking, self).setUp(*args, **kwargs)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.sender = self.env["res.partner"].create(
|
|
|
|
{"name": "Test sender", "email": "sender@example.com"}
|
|
|
|
)
|
|
|
|
self.recipient = self.env["res.partner"].create(
|
|
|
|
{"name": "Test recipient", "email": "recipient@example.com"}
|
|
|
|
)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.last_request = http.request
|
2019-11-18 11:46:59 +01:00
|
|
|
http.request = type(
|
|
|
|
"obj",
|
|
|
|
(object,),
|
|
|
|
{
|
|
|
|
"env": self.env,
|
|
|
|
"cr": self.env.cr,
|
|
|
|
"db": self.env.cr.dbname,
|
|
|
|
"endpoint": type("obj", (object,), {"routing": []}),
|
|
|
|
"httprequest": type(
|
|
|
|
"obj",
|
|
|
|
(object,),
|
|
|
|
{"remote_addr": "123.123.123.123", "user_agent": FakeUserAgent()},
|
|
|
|
),
|
|
|
|
},
|
|
|
|
)
|
2016-10-14 15:42:29 +02:00
|
|
|
|
|
|
|
def tearDown(self, *args, **kwargs):
|
|
|
|
http.request = self.last_request
|
|
|
|
return super(TestMailTracking, self).tearDown(*args, **kwargs)
|
2016-06-14 17:22:17 +02:00
|
|
|
|
2016-10-24 13:35:45 +02:00
|
|
|
def test_empty_email(self):
|
2019-11-18 11:46:59 +01:00
|
|
|
self.recipient.write({"email_bounced": True})
|
|
|
|
self.recipient.write({"email": False})
|
2016-10-24 13:35:45 +02:00
|
|
|
self.assertEqual(False, self.recipient.email)
|
|
|
|
self.assertEqual(False, self.recipient.email_bounced)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.recipient.write({"email_bounced": True})
|
|
|
|
self.recipient.write({"email": ""})
|
2016-10-24 13:35:45 +02:00
|
|
|
self.assertEqual(False, self.recipient.email_bounced)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(False, self.env["mail.tracking.email"].email_is_bounced(False))
|
2016-10-24 13:35:45 +02:00
|
|
|
self.assertEqual(
|
2019-11-18 11:46:59 +01:00
|
|
|
0.0, self.env["mail.tracking.email"].email_score_from_email(False)
|
|
|
|
)
|
2016-10-24 13:35:45 +02:00
|
|
|
|
|
|
|
def test_recipient_address_compute(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.write({"recipient": False})
|
2016-10-24 13:35:45 +02:00
|
|
|
self.assertEqual(False, tracking.recipient_address)
|
|
|
|
|
2016-06-14 17:22:17 +02:00
|
|
|
def test_message_post(self):
|
|
|
|
# This message will generate a notification for recipient
|
2019-11-18 11:34:02 +01:00
|
|
|
message = self.env["mail.message"].create(
|
|
|
|
{
|
|
|
|
"subject": "Message test",
|
|
|
|
"author_id": self.sender.id,
|
|
|
|
"email_from": self.sender.email,
|
|
|
|
"message_type": "comment",
|
|
|
|
"model": "res.partner",
|
|
|
|
"res_id": self.recipient.id,
|
|
|
|
"partner_ids": [(4, self.recipient.id)],
|
|
|
|
"body": "<p>This is a test message</p>",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
message._moderate_accept()
|
2016-06-14 17:22:17 +02:00
|
|
|
# Search tracking created
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking_email = self.env["mail.tracking.email"].search(
|
|
|
|
[
|
|
|
|
("mail_message_id", "=", message.id),
|
|
|
|
("partner_id", "=", self.recipient.id),
|
|
|
|
]
|
|
|
|
)
|
2016-06-14 17:22:17 +02:00
|
|
|
# The tracking email must be sent
|
|
|
|
self.assertTrue(tracking_email)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(tracking_email.state, "sent")
|
2016-06-14 17:22:17 +02:00
|
|
|
# message_dict read by web interface
|
2016-10-14 21:53:04 +02:00
|
|
|
message_dict = message.message_format()[0]
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertTrue(len(message_dict["partner_ids"]) > 0)
|
2016-06-14 17:22:17 +02:00
|
|
|
# First partner is recipient
|
2019-11-18 11:34:02 +01:00
|
|
|
partner_id = message_dict["partner_ids"][0]
|
2016-06-14 17:22:17 +02:00
|
|
|
self.assertEqual(partner_id, self.recipient.id)
|
2019-11-18 11:46:59 +01:00
|
|
|
status = message_dict["partner_trackings"][0]
|
2016-06-14 17:22:17 +02:00
|
|
|
# Tracking status must be sent and
|
|
|
|
# mail tracking must be the one search before
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(status["status"], "sent")
|
|
|
|
self.assertEqual(status["tracking_id"], tracking_email.id)
|
|
|
|
self.assertEqual(status["recipient"], self.recipient.display_name)
|
|
|
|
self.assertEqual(status["partner_id"], self.recipient.id)
|
|
|
|
self.assertEqual(status["isCc"], False)
|
2016-06-14 17:22:17 +02:00
|
|
|
# And now open the email
|
|
|
|
metadata = {
|
2019-11-18 11:46:59 +01:00
|
|
|
"ip": "127.0.0.1",
|
|
|
|
"user_agent": "Odoo Test/1.0",
|
|
|
|
"os_family": "linux",
|
|
|
|
"ua_family": "odoo",
|
2016-06-14 17:22:17 +02:00
|
|
|
}
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking_email.event_create("open", metadata)
|
|
|
|
self.assertEqual(tracking_email.state, "opened")
|
2016-06-14 17:22:17 +02:00
|
|
|
|
2019-10-17 03:28:42 +02:00
|
|
|
def test_message_post_partner_no_email(self):
|
|
|
|
# Create message with recipient without defined email
|
2019-11-18 11:46:59 +01:00
|
|
|
self.recipient.write({"email": False})
|
|
|
|
message = self.env["mail.message"].create(
|
|
|
|
{
|
|
|
|
"subject": "Message test",
|
|
|
|
"author_id": self.sender.id,
|
|
|
|
"email_from": self.sender.email,
|
|
|
|
"message_type": "comment",
|
|
|
|
"model": "res.partner",
|
|
|
|
"res_id": self.recipient.id,
|
|
|
|
"partner_ids": [(4, self.recipient.id)],
|
|
|
|
"body": "<p>This is a test message</p>",
|
|
|
|
}
|
|
|
|
)
|
2019-11-18 11:34:02 +01:00
|
|
|
message._moderate_accept()
|
2019-10-17 03:28:42 +02:00
|
|
|
# Search tracking created
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking_email = self.env["mail.tracking.email"].search(
|
|
|
|
[
|
|
|
|
("mail_message_id", "=", message.id),
|
|
|
|
("partner_id", "=", self.recipient.id),
|
|
|
|
]
|
|
|
|
)
|
2019-10-17 03:28:42 +02:00
|
|
|
# No email should generate a error state: no_recipient
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(tracking_email.state, "error")
|
|
|
|
self.assertEqual(tracking_email.error_type, "no_recipient")
|
2019-10-17 03:28:42 +02:00
|
|
|
self.assertFalse(self.recipient.email_bounced)
|
|
|
|
|
2020-03-26 20:43:45 +01:00
|
|
|
def _check_partner_trackings_cc(self, message):
|
2019-07-23 17:50:45 +02:00
|
|
|
message_dict = message.message_format()[0]
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(len(message_dict["partner_trackings"]), 3)
|
2019-07-23 17:50:45 +02:00
|
|
|
# mail cc
|
|
|
|
foundPartner = False
|
|
|
|
foundNoPartner = False
|
2019-11-18 11:46:59 +01:00
|
|
|
for tracking in message_dict["partner_trackings"]:
|
|
|
|
if tracking["partner_id"] == self.sender.id:
|
2019-07-23 17:50:45 +02:00
|
|
|
foundPartner = True
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertTrue(tracking["isCc"])
|
|
|
|
elif tracking["recipient"] == "unnamed@test.com":
|
2019-07-23 17:50:45 +02:00
|
|
|
foundNoPartner = True
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertFalse(tracking["partner_id"])
|
|
|
|
self.assertTrue(tracking["isCc"])
|
|
|
|
elif tracking["partner_id"] == self.recipient.id:
|
|
|
|
self.assertFalse(tracking["isCc"])
|
2019-07-23 17:50:45 +02:00
|
|
|
self.assertTrue(foundPartner)
|
|
|
|
self.assertTrue(foundNoPartner)
|
|
|
|
|
2019-07-03 11:12:11 +02:00
|
|
|
def test_email_cc(self):
|
2019-11-18 11:46:59 +01:00
|
|
|
sender_user = self.env["res.users"].create(
|
|
|
|
{
|
|
|
|
"name": "Sender User Test",
|
|
|
|
"partner_id": self.sender.id,
|
|
|
|
"login": "sender-test",
|
|
|
|
}
|
|
|
|
)
|
2020-03-19 20:30:34 +01:00
|
|
|
# pylint: disable=C8107
|
2019-11-18 11:46:59 +01:00
|
|
|
message = self.recipient.with_user(sender_user).message_post(
|
2020-03-19 20:30:34 +01:00
|
|
|
body="<p>This is a test message</p>",
|
2020-03-26 20:43:45 +01:00
|
|
|
cc="Dominique Pinon <unnamed@test.com>, sender@example.com",
|
2019-10-17 03:28:42 +02:00
|
|
|
)
|
2019-07-03 11:12:11 +02:00
|
|
|
# suggested recipients
|
2019-11-18 11:46:59 +01:00
|
|
|
recipients = self.recipient._message_get_suggested_recipients()
|
|
|
|
suggested_mails = {email[1] for email in recipients[self.recipient.id]}
|
2020-03-26 20:43:45 +01:00
|
|
|
self.assertIn("unnamed@test.com", suggested_mails)
|
|
|
|
self.assertEqual(len(recipients[self.recipient.id]), 3)
|
2019-07-22 17:07:50 +02:00
|
|
|
# Repeated Cc recipients
|
2019-11-18 11:46:59 +01:00
|
|
|
message = self.env["mail.message"].create(
|
|
|
|
{
|
|
|
|
"subject": "Message test",
|
|
|
|
"author_id": self.sender.id,
|
|
|
|
"email_from": self.sender.email,
|
|
|
|
"message_type": "comment",
|
|
|
|
"model": "res.partner",
|
|
|
|
"res_id": self.recipient.id,
|
|
|
|
"partner_ids": [(4, self.recipient.id)],
|
2020-03-26 20:43:45 +01:00
|
|
|
"email_cc": "Dominique Pinon <unnamed@test.com>, sender@example.com"
|
2019-11-18 11:46:59 +01:00
|
|
|
", recipient@example.com",
|
|
|
|
"body": "<p>This is another test message</p>",
|
|
|
|
}
|
|
|
|
)
|
2019-11-18 11:34:02 +01:00
|
|
|
message._moderate_accept()
|
2019-11-18 11:46:59 +01:00
|
|
|
recipients = self.recipient._message_get_suggested_recipients()
|
2020-03-26 20:43:45 +01:00
|
|
|
self.assertEqual(len(recipients[self.recipient.id]), 3)
|
|
|
|
self._check_partner_trackings_cc(message)
|
|
|
|
|
|
|
|
def _check_partner_trackings_to(self, message):
|
|
|
|
message_dict = message.message_format()[0]
|
|
|
|
self.assertEqual(len(message_dict["partner_trackings"]), 3)
|
|
|
|
# mail cc
|
|
|
|
foundPartner = False
|
|
|
|
foundNoPartner = False
|
|
|
|
for tracking in message_dict["partner_trackings"]:
|
|
|
|
if tracking["partner_id"] == self.sender.id:
|
|
|
|
foundPartner = True
|
|
|
|
elif tracking["recipient"] == "support+unnamed@test.com":
|
|
|
|
foundNoPartner = True
|
|
|
|
self.assertFalse(tracking["partner_id"])
|
|
|
|
self.assertTrue(foundPartner)
|
|
|
|
self.assertTrue(foundNoPartner)
|
|
|
|
|
|
|
|
def test_email_to(self):
|
|
|
|
sender_user = self.env["res.users"].create(
|
|
|
|
{
|
|
|
|
"name": "Sender User Test",
|
|
|
|
"partner_id": self.sender.id,
|
|
|
|
"login": "sender-test",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
# pylint: disable=C8107
|
|
|
|
message = self.recipient.with_user(sender_user).message_post(
|
|
|
|
body="<p>This is a test message</p>",
|
|
|
|
to="Dominique Pinon <support+unnamed@test.com>, sender@example.com",
|
|
|
|
)
|
|
|
|
# suggested recipients
|
|
|
|
recipients = self.recipient._message_get_suggested_recipients()
|
|
|
|
suggested_mails = {email[1] for email in recipients[self.recipient.id]}
|
|
|
|
self.assertIn("support+unnamed@test.com", suggested_mails)
|
|
|
|
self.assertEqual(len(recipients[self.recipient.id]), 3)
|
|
|
|
# Repeated To recipients
|
|
|
|
message = self.env["mail.message"].create(
|
|
|
|
{
|
|
|
|
"subject": "Message test",
|
|
|
|
"author_id": self.sender.id,
|
|
|
|
"email_from": self.sender.email,
|
|
|
|
"message_type": "comment",
|
|
|
|
"model": "res.partner",
|
|
|
|
"res_id": self.recipient.id,
|
|
|
|
"partner_ids": [(4, self.recipient.id)],
|
|
|
|
"email_to": "Dominique Pinon <support+unnamed@test.com>"
|
|
|
|
", sender@example.com, recipient@example.com",
|
|
|
|
"body": "<p>This is another test message</p>",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
message._moderate_accept()
|
|
|
|
recipients = self.recipient._message_get_suggested_recipients()
|
|
|
|
self.assertEqual(len(recipients[self.recipient.id]), 3)
|
|
|
|
self._check_partner_trackings_to(message)
|
|
|
|
# Catchall + Alias
|
|
|
|
self.env["ir.config_parameter"].set_param("mail.catchall.domain", "test.com")
|
|
|
|
self.env["mail.alias"].create(
|
|
|
|
{
|
|
|
|
"alias_model_id": self.env["ir.model"]._get("res.partner").id,
|
|
|
|
"alias_name": "support+unnamed",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
recipients = self.recipient._message_get_suggested_recipients()
|
|
|
|
self.assertEqual(len(recipients[self.recipient.id]), 2)
|
|
|
|
suggested_mails = {email[1] for email in recipients[self.recipient.id]}
|
|
|
|
self.assertNotIn("support+unnamed@test.com", suggested_mails)
|
2019-07-03 11:12:11 +02:00
|
|
|
|
2019-07-05 14:20:27 +02:00
|
|
|
def test_failed_message(self):
|
2019-11-18 11:46:59 +01:00
|
|
|
MailMessageObj = self.env["mail.message"]
|
2019-07-05 14:20:27 +02:00
|
|
|
# Create message
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
|
|
|
self.assertFalse(tracking.mail_message_id.mail_tracking_needs_action)
|
|
|
|
# Force error state
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.state = "error"
|
2019-07-05 14:20:27 +02:00
|
|
|
self.assertTrue(tracking.mail_message_id.mail_tracking_needs_action)
|
2019-10-17 03:28:42 +02:00
|
|
|
failed_count = MailMessageObj.get_failed_count()
|
2019-07-05 14:20:27 +02:00
|
|
|
self.assertTrue(failed_count > 0)
|
|
|
|
values = tracking.mail_message_id.get_failed_messages()
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(values[0]["id"], tracking.mail_message_id.id)
|
2019-10-17 03:28:42 +02:00
|
|
|
messages = MailMessageObj.search([])
|
|
|
|
messages_failed = MailMessageObj.search(
|
2019-11-18 11:46:59 +01:00
|
|
|
MailMessageObj._get_failed_message_domain()
|
|
|
|
)
|
2019-07-05 14:20:27 +02:00
|
|
|
self.assertTrue(messages)
|
|
|
|
self.assertTrue(messages_failed)
|
|
|
|
self.assertTrue(len(messages) > len(messages_failed))
|
2019-11-14 18:41:24 +01:00
|
|
|
tracking.mail_message_id.set_need_action_done()
|
2019-07-05 14:20:27 +02:00
|
|
|
self.assertFalse(tracking.mail_message_id.mail_tracking_needs_action)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertTrue(MailMessageObj.get_failed_count() < failed_count)
|
2019-10-17 03:28:42 +02:00
|
|
|
# No author_id
|
|
|
|
tracking.mail_message_id.author_id = False
|
|
|
|
values = tracking.mail_message_id.get_failed_messages()[0]
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(values["author"][0], -1)
|
2019-07-05 14:20:27 +02:00
|
|
|
|
2019-11-18 11:34:02 +01:00
|
|
|
def test_resend_failed_message(self):
|
|
|
|
# This message will generate a notification for recipient
|
|
|
|
message = self.env["mail.message"].create(
|
|
|
|
{
|
|
|
|
"subject": "Message test",
|
|
|
|
"author_id": self.sender.id,
|
|
|
|
"email_from": self.sender.email,
|
|
|
|
"message_type": "comment",
|
|
|
|
"model": "res.partner",
|
|
|
|
"res_id": self.recipient.id,
|
|
|
|
"partner_ids": [(4, self.recipient.id)],
|
|
|
|
"body": "<p>This is a test message</p>",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
message._moderate_accept()
|
|
|
|
# Search tracking created
|
|
|
|
tracking_email = self.env["mail.tracking.email"].search(
|
|
|
|
[
|
|
|
|
("mail_message_id", "=", message.id),
|
|
|
|
("partner_id", "=", self.recipient.id),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
# Force error state
|
|
|
|
tracking_email.state = "error"
|
|
|
|
# Create resend mail wizard
|
|
|
|
wizard = (
|
|
|
|
self.env["mail.resend.message"]
|
|
|
|
.sudo()
|
|
|
|
.with_context({"mail_message_to_resend": message.id})
|
|
|
|
.create({})
|
|
|
|
)
|
|
|
|
# Check failed recipient)s
|
|
|
|
self.assertTrue(any(wizard.partner_ids))
|
|
|
|
self.assertEqual(self.recipient.email, wizard.partner_ids[0].email)
|
|
|
|
# Resend message
|
|
|
|
wizard.resend_mail_action()
|
|
|
|
# Check tracking reset
|
|
|
|
self.assertFalse(tracking_email.state)
|
|
|
|
|
2016-09-09 18:33:21 +02:00
|
|
|
def mail_send(self, recipient):
|
2019-11-18 11:46:59 +01:00
|
|
|
mail = self.env["mail.mail"].create(
|
|
|
|
{
|
|
|
|
"subject": "Test subject",
|
|
|
|
"email_from": "from@domain.com",
|
|
|
|
"email_to": recipient,
|
|
|
|
"body_html": "<p>This is a test message</p>",
|
|
|
|
}
|
|
|
|
)
|
2016-06-14 17:22:17 +02:00
|
|
|
mail.send()
|
|
|
|
# Search tracking created
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking_email = self.env["mail.tracking.email"].search(
|
|
|
|
[("mail_id", "=", mail.id)]
|
|
|
|
)
|
2016-06-14 17:22:17 +02:00
|
|
|
return mail, tracking_email
|
|
|
|
|
|
|
|
def test_mail_send(self):
|
|
|
|
controller = MailTrackingController()
|
|
|
|
db = self.env.cr.dbname
|
2019-07-24 12:39:27 +02:00
|
|
|
image = base64.b64decode(BLANK)
|
2016-09-09 18:33:21 +02:00
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2016-06-14 17:22:17 +02:00
|
|
|
self.assertEqual(mail.email_to, tracking.recipient)
|
|
|
|
self.assertEqual(mail.email_from, tracking.sender)
|
2019-11-18 11:46:59 +01:00
|
|
|
with mock.patch("odoo.http.db_filter") as mock_client:
|
2019-10-17 03:28:42 +02:00
|
|
|
mock_client.return_value = True
|
2019-11-18 11:46:59 +01:00
|
|
|
res = controller.mail_tracking_open(db, tracking.id, tracking.token)
|
2019-10-17 03:28:42 +02:00
|
|
|
self.assertEqual(image, res.response[0])
|
|
|
|
# Two events: sent and open
|
|
|
|
self.assertEqual(2, len(tracking.tracking_event_ids))
|
|
|
|
# Fake event: tracking_email_id = False
|
|
|
|
res = controller.mail_tracking_open(db, False, False)
|
|
|
|
self.assertEqual(image, res.response[0])
|
|
|
|
# Two events again because no tracking_email_id found for False
|
|
|
|
self.assertEqual(2, len(tracking.tracking_event_ids))
|
|
|
|
|
|
|
|
def test_mail_tracking_open(self):
|
|
|
|
controller = MailTrackingController()
|
|
|
|
db = self.env.cr.dbname
|
2019-11-18 11:46:59 +01:00
|
|
|
with mock.patch("odoo.http.db_filter") as mock_client:
|
2019-10-17 03:28:42 +02:00
|
|
|
mock_client.return_value = True
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
|
|
|
# Tracking is in sent or delivered state. But no token give.
|
|
|
|
# Don't generates tracking event
|
|
|
|
controller.mail_tracking_open(db, tracking.id)
|
|
|
|
self.assertEqual(1, len(tracking.tracking_event_ids))
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.write({"state": "opened"})
|
2019-10-17 03:28:42 +02:00
|
|
|
# Tracking isn't in sent or delivered state.
|
|
|
|
# Don't generates tracking event
|
|
|
|
controller.mail_tracking_open(db, tracking.id, tracking.token)
|
|
|
|
self.assertEqual(1, len(tracking.tracking_event_ids))
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.write({"state": "sent"})
|
2019-10-17 03:28:42 +02:00
|
|
|
# Tracking is in sent or delivered state and a token is given.
|
|
|
|
# Generates tracking event
|
|
|
|
controller.mail_tracking_open(db, tracking.id, tracking.token)
|
|
|
|
self.assertEqual(2, len(tracking.tracking_event_ids))
|
|
|
|
# Generate new email due concurrent event filter
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.write({"token": False})
|
2019-10-17 03:28:42 +02:00
|
|
|
# Tracking is in sent or delivered state but a token is given for a
|
|
|
|
# record that doesn't have a token.
|
|
|
|
# Don't generates tracking event
|
2019-11-18 11:46:59 +01:00
|
|
|
controller.mail_tracking_open(db, tracking.id, "tokentest")
|
2019-10-17 03:28:42 +02:00
|
|
|
self.assertEqual(1, len(tracking.tracking_event_ids))
|
|
|
|
# Tracking is in sent or delivered state and not token is given for
|
|
|
|
# a record that doesn't have a token.
|
|
|
|
# Generates tracking event
|
|
|
|
controller.mail_tracking_open(db, tracking.id, False)
|
|
|
|
self.assertEqual(2, len(tracking.tracking_event_ids))
|
2016-06-14 17:22:17 +02:00
|
|
|
|
2016-09-09 13:29:58 +02:00
|
|
|
def test_concurrent_open(self):
|
2016-09-09 18:33:21 +02:00
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2016-09-09 13:29:58 +02:00
|
|
|
ts = time.time()
|
|
|
|
metadata = {
|
2019-11-18 11:46:59 +01:00
|
|
|
"ip": "127.0.0.1",
|
|
|
|
"user_agent": "Odoo Test/1.0",
|
|
|
|
"os_family": "linux",
|
|
|
|
"ua_family": "odoo",
|
|
|
|
"timestamp": ts,
|
2016-09-09 13:29:58 +02:00
|
|
|
}
|
|
|
|
# First open event
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("open", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "open")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 1)
|
|
|
|
# Concurrent open event
|
2019-11-18 11:46:59 +01:00
|
|
|
metadata["timestamp"] = ts + 2
|
|
|
|
tracking.event_create("open", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "open")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 1)
|
|
|
|
# Second open event
|
2019-11-18 11:46:59 +01:00
|
|
|
metadata["timestamp"] = ts + 350
|
|
|
|
tracking.event_create("open", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "open")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 2)
|
|
|
|
|
|
|
|
def test_concurrent_click(self):
|
2016-09-09 18:33:21 +02:00
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2016-09-09 13:29:58 +02:00
|
|
|
ts = time.time()
|
|
|
|
metadata = {
|
2019-11-18 11:46:59 +01:00
|
|
|
"ip": "127.0.0.1",
|
|
|
|
"user_agent": "Odoo Test/1.0",
|
|
|
|
"os_family": "linux",
|
|
|
|
"ua_family": "odoo",
|
|
|
|
"timestamp": ts,
|
|
|
|
"url": "https://www.example.com/route/1",
|
2016-09-09 13:29:58 +02:00
|
|
|
}
|
|
|
|
# First click event (URL 1)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("click", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "click")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 1)
|
|
|
|
# Concurrent click event (URL 1)
|
2019-11-18 11:46:59 +01:00
|
|
|
metadata["timestamp"] = ts + 2
|
|
|
|
tracking.event_create("click", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "click")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 1)
|
|
|
|
# Second click event (URL 1)
|
2019-11-18 11:46:59 +01:00
|
|
|
metadata["timestamp"] = ts + 350
|
|
|
|
tracking.event_create("click", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "click")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 2)
|
|
|
|
# Concurrent click event (URL 2)
|
2019-11-18 11:46:59 +01:00
|
|
|
metadata["timestamp"] = ts + 2
|
|
|
|
metadata["url"] = "https://www.example.com/route/2"
|
|
|
|
tracking.event_create("click", metadata)
|
|
|
|
opens = tracking.tracking_event_ids.filtered(lambda r: r.event_type == "click")
|
2016-09-09 13:29:58 +02:00
|
|
|
self.assertEqual(len(opens), 3)
|
|
|
|
|
2019-11-18 11:46:59 +01:00
|
|
|
@mute_logger("odoo.addons.mail.models.mail_mail")
|
2016-06-14 17:22:17 +02:00
|
|
|
def test_smtp_error(self):
|
|
|
|
with mock.patch(mock_send_email) as mock_func:
|
2019-11-18 11:46:59 +01:00
|
|
|
mock_func.side_effect = Warning("Test error")
|
2016-09-09 18:33:21 +02:00
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual("error", tracking.state)
|
|
|
|
self.assertEqual("Warning", tracking.error_type)
|
|
|
|
self.assertEqual("Test error", tracking.error_description)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_bounced)
|
2016-06-14 17:22:17 +02:00
|
|
|
|
2016-09-09 18:33:21 +02:00
|
|
|
def test_partner_email_change(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("open", {})
|
2016-09-09 18:33:21 +02:00
|
|
|
orig_score = self.recipient.email_score
|
2016-10-14 15:42:29 +02:00
|
|
|
orig_count = self.recipient.tracking_emails_count
|
2016-09-09 18:33:21 +02:00
|
|
|
orig_email = self.recipient.email
|
2019-11-18 11:46:59 +01:00
|
|
|
self.recipient.email = orig_email + "2"
|
2016-09-09 18:33:21 +02:00
|
|
|
self.assertEqual(50.0, self.recipient.email_score)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertEqual(0, self.recipient.tracking_emails_count)
|
2016-09-09 18:33:21 +02:00
|
|
|
self.recipient.email = orig_email
|
|
|
|
self.assertEqual(orig_score, self.recipient.email_score)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertEqual(orig_count, self.recipient.tracking_emails_count)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_hard_bounce(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("hard_bounce", {})
|
|
|
|
self.assertEqual("bounced", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score < 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_soft_bounce(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("soft_bounce", {})
|
|
|
|
self.assertEqual("soft-bounced", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score < 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_delivered(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("delivered", {})
|
|
|
|
self.assertEqual("delivered", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score > 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_deferral(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("deferral", {})
|
|
|
|
self.assertEqual("deferred", tracking.state)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_spam(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("spam", {})
|
|
|
|
self.assertEqual("spam", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score < 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_unsub(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("unsub", {})
|
|
|
|
self.assertEqual("unsub", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score < 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_reject(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("reject", {})
|
|
|
|
self.assertEqual("rejected", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score < 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_open(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("open", {})
|
|
|
|
self.assertEqual("opened", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score > 50.0)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
|
|
|
def test_process_click(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("click", {})
|
|
|
|
self.assertEqual("opened", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertTrue(self.recipient.email_score > 50.0)
|
|
|
|
|
|
|
|
def test_process_several_bounce(self):
|
2019-11-18 11:46:59 +01:00
|
|
|
for _i in range(1, 10):
|
2016-10-14 15:42:29 +02:00
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("hard_bounce", {})
|
|
|
|
self.assertEqual("bounced", tracking.state)
|
2016-10-14 15:42:29 +02:00
|
|
|
self.assertEqual(0.0, self.recipient.email_score)
|
2016-09-09 18:33:21 +02:00
|
|
|
|
2018-11-05 17:26:01 +01:00
|
|
|
def test_bounce_new_partner(self):
|
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("hard_bounce", {})
|
|
|
|
new_partner = self.env["res.partner"].create({"name": "Test New Partner"})
|
2018-11-05 17:26:01 +01:00
|
|
|
new_partner.email = self.recipient.email
|
|
|
|
self.assertTrue(new_partner.email_bounced)
|
|
|
|
|
2018-09-06 11:24:20 +02:00
|
|
|
def test_recordset_email_score(self):
|
|
|
|
"""For backwords compatibility sake"""
|
2019-11-18 11:46:59 +01:00
|
|
|
trackings = self.env["mail.tracking.email"]
|
|
|
|
for _i in range(11):
|
2018-09-06 11:24:20 +02:00
|
|
|
mail, tracking = self.mail_send(self.recipient.email)
|
2019-11-18 11:46:59 +01:00
|
|
|
tracking.event_create("click", {})
|
2018-09-06 11:24:20 +02:00
|
|
|
trackings |= tracking
|
|
|
|
self.assertEqual(100.0, trackings.email_score())
|
|
|
|
|
2016-06-14 17:22:17 +02:00
|
|
|
def test_db(self):
|
|
|
|
db = self.env.cr.dbname
|
|
|
|
controller = MailTrackingController()
|
2019-11-18 11:46:59 +01:00
|
|
|
with mock.patch("odoo.http.db_filter") as mock_client:
|
2019-10-17 03:28:42 +02:00
|
|
|
mock_client.return_value = True
|
|
|
|
with self.assertRaises(psycopg2.OperationalError):
|
2019-11-18 11:46:59 +01:00
|
|
|
controller.mail_tracking_event("not_found_db")
|
2019-10-17 03:28:42 +02:00
|
|
|
none = controller.mail_tracking_event(db)
|
2019-11-18 11:46:59 +01:00
|
|
|
self.assertEqual(b"NONE", none.response[0])
|
|
|
|
none = controller.mail_tracking_event(db, "open")
|
|
|
|
self.assertEqual(b"NONE", none.response[0])
|
2019-07-05 14:20:27 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestMailTrackingViews(TransactionCase):
|
|
|
|
def test_fields_view_get(self):
|
2019-11-18 11:46:59 +01:00
|
|
|
result = self.env["res.partner"].fields_view_get(
|
|
|
|
view_id=self.env.ref("base.view_partner_form").id, view_type="form"
|
|
|
|
)
|
|
|
|
doc = etree.XML(result["arch"])
|
2019-07-05 14:20:27 +02:00
|
|
|
nodes = doc.xpath(
|
2019-11-18 11:46:59 +01:00
|
|
|
"//field[@name='failed_message_ids'" " and @widget='mail_failed_message']"
|
|
|
|
)
|
2019-07-05 14:20:27 +02:00
|
|
|
self.assertTrue(nodes)
|
2019-11-18 11:46:59 +01:00
|
|
|
result = self.env["res.partner"].fields_view_get(
|
|
|
|
view_id=self.env.ref("base.view_res_partner_filter").id, view_type="search"
|
|
|
|
)
|
|
|
|
doc = etree.XML(result["arch"])
|
2019-07-05 14:20:27 +02:00
|
|
|
nodes = doc.xpath("//filter[@name='failed_message_ids']")
|
|
|
|
self.assertTrue(nodes)
|