diff --git a/entity_emailer/models.py b/entity_emailer/models.py index c61a593..e46c4ba 100644 --- a/entity_emailer/models.py +++ b/entity_emailer/models.py @@ -47,14 +47,20 @@ def create_emails(self, email_params_list): # Build list of recipient through relationships to create recipients_to_create = [] + + # Keep track of unique pairs to avoid unique constraint on through relationship + email_entity_pairs = set() for i, recipient_entities in enumerate(recipient_entities_per_email): for recipient_entity in recipient_entities: - recipients_to_create.append( - Email.recipients.through( - email_id=emails[i].id, - entity_id=recipient_entity.id, + if (emails[i].id, recipient_entity.id) not in email_entity_pairs: + email_entity_pairs.add((emails[i].id, recipient_entity.id)) + + recipients_to_create.append( + Email.recipients.through( + email_id=emails[i].id, + entity_id=recipient_entity.id, + ) ) - ) # Bulk create the recipient relationships Email.recipients.through.objects.bulk_create(recipients_to_create) diff --git a/entity_emailer/tests/interface_tests.py b/entity_emailer/tests/interface_tests.py index 4429337..031b900 100644 --- a/entity_emailer/tests/interface_tests.py +++ b/entity_emailer/tests/interface_tests.py @@ -298,10 +298,15 @@ def test_multiple_events_only_following_false(self): @freeze_time('2013-1-2') def test_bulk_multiple_events_only_following_false(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=False) G(Subscription, entity=e, source=source, medium=self.email_medium, only_following=False) G(Subscription, entity=other_e, source=source, medium=self.email_medium, only_following=False) email_context = { @@ -344,6 +349,35 @@ def test_multiple_events_only_following_true(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('2014-01-05') class SendUnsentScheduledEmailsTest(TestCase): diff --git a/entity_emailer/version.py b/entity_emailer/version.py index 3f39079..668c344 100644 --- a/entity_emailer/version.py +++ b/entity_emailer/version.py @@ -1 +1 @@ -__version__ = '2.0.1' +__version__ = '2.0.2' diff --git a/release_notes.rst b/release_notes.rst index b1a2557..fd8c695 100644 --- a/release_notes.rst +++ b/release_notes.rst @@ -1,6 +1,10 @@ Release Notes ============= +v2.0.2 +------ +* Fix unique constraint when bulk creating emails + v2.0.1 ------ * Fix for handling single failures in a batch of outgoing emails