Skip to content
5 changes: 3 additions & 2 deletions entity_emailer/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import traceback

from datetime import datetime

from django.db import transaction
from django.core import mail
from entity_event import context_loader

Expand Down Expand Up @@ -94,7 +94,7 @@ def send_unsent_scheduled_emails(cls):
for email in emails_to_send:
try:
# Send mail
connection.send_message(email.get('message'))
connection.send_messages([email.get('message')])
except Exception as e:
cls.save_email_exception(email.get('model'), e)

Expand Down Expand Up @@ -123,6 +123,7 @@ def convert_events_to_emails():
Email.objects.create_email(event=event, from_address=from_address, recipients=targets)

@staticmethod
@transaction.atomic
def bulk_convert_events_to_emails():
"""
Converts unseen events to emails and marks them as seen. Uses the create_emails method to bulk create
Expand Down
39 changes: 34 additions & 5 deletions entity_emailer/tests/interface_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,35 @@ def test_bulk_multiple_events_only_following_false(self):
self.assertEquals(email.subject, '')
self.assertEquals(email.scheduled, datetime(2013, 1, 2))

@freeze_time('2013-1-2')
def test_bulk_multiple_events_only_following_true(self):
"""
Handles bulk creating events and tests the unique constraint of the duplicated subscription which would cause
a bulk create error if it wasn't handled
"""
source = G(Source)
e = G(Entity)
other_e = G(Entity)

G(Subscription, entity=e, source=source, medium=self.email_medium, only_following=True)
G(Subscription, entity=e, source=source, medium=self.email_medium, only_following=True)
G(Subscription, entity=other_e, source=source, medium=self.email_medium, only_following=True)
email_context = {
'entity_emailer_template': 'template',
'entity_emailer_subject': 'hi',
}
G(Event, source=source, context=email_context)
event = G(Event, source=source, context=email_context)
G(EventActor, event=event, entity=e)

EntityEmailerInterface.bulk_convert_events_to_emails()

email = Email.objects.get()
self.assertEquals(set(email.recipients.all()), set([e]))
self.assertEquals(email.event.context, email_context)
self.assertEquals(email.subject, '')
self.assertEquals(email.scheduled, datetime(2013, 1, 2))

@freeze_time('2013-1-2')
def test_multiple_events_only_following_true(self):
source = G(Source)
Expand Down Expand Up @@ -405,7 +434,7 @@ def test_sends_all_scheduled_emails(self, render_mock, address_mock):
with patch(settings.EMAIL_BACKEND) as mock_connection:
EntityEmailerInterface.send_unsent_scheduled_emails()

self.assertEqual(2, mock_connection.return_value.__enter__.return_value.send_message.call_count)
self.assertEqual(2, mock_connection.return_value.__enter__.return_value.send_messages.call_count)

@patch('entity_emailer.interface.pre_send')
@patch('entity_emailer.interface.get_subscribed_email_addresses')
Expand All @@ -426,7 +455,7 @@ def test_send_signals(self, render_mock, address_mock, mock_pre_send):
EntityEmailerInterface.send_unsent_scheduled_emails()

# Assert that we sent the email
self.assertEqual(1, mock_connection.return_value.__enter__.return_value.send_message.call_count)
self.assertEqual(1, mock_connection.return_value.__enter__.return_value.send_messages.call_count)

# Assert that we called the pre send signal with the proper values
name, args, kwargs = mock_pre_send.send.mock_calls[0]
Expand All @@ -450,8 +479,8 @@ def test_sends_email_with_specified_from_address(self, render_mock, address_mock
with patch(settings.EMAIL_BACKEND) as mock_connection:
EntityEmailerInterface.send_unsent_scheduled_emails()

args = mock_connection.return_value.__enter__.return_value.send_message.call_args
self.assertEqual(args[0][0].from_email, from_address)
args = mock_connection.return_value.__enter__.return_value.send_messages.call_args
self.assertEqual(args[0][0][0].from_email, from_address)

@patch('entity_emailer.interface.get_subscribed_email_addresses')
@patch.object(Event, 'render', spec_set=True)
Expand Down Expand Up @@ -538,7 +567,7 @@ def to_dict(self):

with patch(settings.EMAIL_BACKEND) as mock_connection:
# Mock side effects for sending emails
mock_connection.return_value.__enter__.return_value.send_message.side_effect = [
mock_connection.return_value.__enter__.return_value.send_messages.side_effect = [
None,
TestEmailSendMessageException('test'),
]
Expand Down
2 changes: 1 addition & 1 deletion entity_emailer/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '2.0.2'
__version__ = '2.0.4'
12 changes: 12 additions & 0 deletions release_notes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Release Notes
=============

v2.0.4
------
* Bugfix for updated interface

v2.0.2
------
* Fix unique constraint when bulk creating emails
Expand All @@ -9,6 +13,14 @@ v2.0.1
------
* Fix for handling single failures in a batch of outgoing emails

v2.0.0.2
------
* Atomic decorator on event fetching

v2.0.0.1
------
* Fix unique constraint when bulk creating emails

v2.0.0
------
* Added bulk interface for converting to emails
Expand Down