Skip to content

Commit f0cf74d

Browse files
authored
Merge pull request #70 from ambitioninc/develop
2.0.0
2 parents f6ab14c + 4c4b79b commit f0cf74d

File tree

10 files changed

+122
-28
lines changed

10 files changed

+122
-28
lines changed

.travis.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,15 @@ python:
88

99
env:
1010
matrix:
11-
- DJANGO=2.0
12-
- DJANGO=2.1
1311
- DJANGO=2.2
12+
- DJANGO=3.0
13+
- DJANGO=3.1
1414
- DJANGO=master
1515

1616
addons:
1717
postgresql: '9.6'
1818

1919
matrix:
20-
exclude:
21-
- { python: "3.7", env: DJANGO=2.0 }
22-
2320
include:
2421
- { python: "3.6", env: TOXENV=flake8 }
2522

entity_emailer/interface.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,33 @@ def convert_events_to_emails():
120120

121121
# Create the emails
122122
Email.objects.create_email(event=event, from_address=from_address, recipients=targets)
123+
124+
@staticmethod
125+
def bulk_convert_events_to_emails():
126+
"""
127+
Converts unseen events to emails and marks them as seen. Uses the create_emails method to bulk create
128+
emails and recipient relationships
129+
"""
130+
131+
# Get the email medium
132+
email_medium = get_medium()
133+
134+
# Get the default from email
135+
default_from_email = get_from_email_address()
136+
137+
email_params_list = []
138+
139+
# Find any unseen events and create unsent email objects
140+
for event, targets in email_medium.events_targets(seen=False, mark_seen=True):
141+
142+
# Check the event's context for a from_address, otherwise fallback to default
143+
from_address = event.context.get('from_address') or default_from_email
144+
145+
email_params_list.append(dict(
146+
event=event,
147+
from_address=from_address,
148+
recipients=targets
149+
))
150+
151+
# Bulk create the emails
152+
Email.objects.create_emails(email_params_list)

entity_emailer/models.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
22

3-
from django.db import models
3+
from django.db import models, transaction
44
from entity.models import Entity
55
from entity_event.models import Event
66
import uuid
@@ -26,6 +26,41 @@ def create_email(self, recipients=None, **kwargs):
2626
email.save()
2727
return email
2828

29+
@transaction.atomic
30+
def create_emails(self, email_params_list):
31+
"""
32+
:param email_params_list: A list of dicts containing the keys for the create_email method
33+
:return: list of Email objects that were created
34+
"""
35+
emails_to_create = []
36+
recipient_entities_per_email = []
37+
38+
# Build the emails to create and keep track of recipients
39+
for kwargs in email_params_list:
40+
scheduled = kwargs.pop('scheduled', datetime.utcnow())
41+
recipients = kwargs.pop('recipients', [])
42+
emails_to_create.append(Email(scheduled=scheduled, **kwargs))
43+
recipient_entities_per_email.append(recipients)
44+
45+
# Bulk create the emails
46+
emails = Email.objects.bulk_create(emails_to_create)
47+
48+
# Build list of recipient through relationships to create
49+
recipients_to_create = []
50+
for i, recipient_entities in enumerate(recipient_entities_per_email):
51+
for recipient_entity in recipient_entities:
52+
recipients_to_create.append(
53+
Email.recipients.through(
54+
email_id=emails[i].id,
55+
entity_id=recipient_entity.id,
56+
)
57+
)
58+
59+
# Bulk create the recipient relationships
60+
Email.recipients.through.objects.bulk_create(recipients_to_create)
61+
62+
return emails
63+
2964

3065
class Email(models.Model):
3166
"""Save an Email object and it is sent automagically!

entity_emailer/tests/interface_tests.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,30 @@ def test_multiple_events_only_following_false(self):
294294
self.assertEquals(email.subject, '')
295295
self.assertEquals(email.scheduled, datetime(2013, 1, 2))
296296

297+
@freeze_time('2013-1-2')
298+
def test_bulk_multiple_events_only_following_false(self):
299+
source = G(Source)
300+
e = G(Entity)
301+
other_e = G(Entity)
302+
303+
G(Subscription, entity=e, source=source, medium=self.email_medium, only_following=False)
304+
G(Subscription, entity=other_e, source=source, medium=self.email_medium, only_following=False)
305+
email_context = {
306+
'entity_emailer_template': 'template',
307+
'entity_emailer_subject': 'hi',
308+
}
309+
G(Event, source=source, context=email_context)
310+
G(Event, source=source, context=email_context)
311+
312+
EntityEmailerInterface.bulk_convert_events_to_emails()
313+
314+
self.assertEquals(Email.objects.count(), 2)
315+
for email in Email.objects.all():
316+
self.assertEquals(set(email.recipients.all()), set([e, other_e]))
317+
self.assertEquals(email.event.context, email_context)
318+
self.assertEquals(email.subject, '')
319+
self.assertEquals(email.scheduled, datetime(2013, 1, 2))
320+
297321
@freeze_time('2013-1-2')
298322
def test_multiple_events_only_following_true(self):
299323
source = G(Source)

entity_emailer/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.1.2'
1+
__version__ = '2.0.0'

release_notes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Release Notes
22
=============
33

4+
v2.0.0
5+
------
6+
* Added bulk interface for converting to emails
7+
* Add support for django 3.0, 3.1
8+
49
v1.1.2
510
------
611
* Handle email render exceptions
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
coverage
2-
django-dynamic-fixture<=2.0.0
3-
django-nose
4-
flake8
5-
freezegun
6-
mock
7-
psycopg2
1+
coverage==4.5.1
2+
django-dynamic-fixture
3+
django-nose==1.4.5
4+
flake8==3.5.0
5+
freezegun==0.3.12
6+
mock==2.0.0
7+
psycopg2>=2.7.7

requirements/requirements.txt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
beautifulsoup4>=4.3.2
2-
Django>=2.0,<3.0
3-
django-db-mutex>=1.2.0
4-
django-entity>=4.2.0
5-
django-entity-event>=1.2.0
1+
Django>=2.2
2+
3+
django-db-mutex>=2.0.0
4+
django-entity>=5.0.0
5+
django-entity-event>=2.0.0
66
ambition-django-uuidfield>=0.5.0
7+
8+
beautifulsoup4>=4.3.2

setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ def get_requirements(requirements_file):
4848
'Programming Language :: Python',
4949
'Programming Language :: Python :: 3.6',
5050
'Programming Language :: Python :: 3.7',
51+
'Programming Language :: Python :: 3.8',
5152
'Intended Audience :: Developers',
5253
'License :: OSI Approved :: MIT License',
5354
'Operating System :: OS Independent',
5455
'Framework :: Django',
55-
'Framework :: Django :: 2.0',
56-
'Framework :: Django :: 2.1',
5756
'Framework :: Django :: 2.2',
57+
'Framework :: Django :: 3.0',
58+
'Framework :: Django :: 3.1',
5859
],
5960
license='MIT',
6061
install_requires=get_requirements('requirements.txt'),

tox.ini

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
[tox]
22
envlist =
33
flake8
4-
py{36}-django20
5-
py{36,37}-django21
64
py{36,37}-django22
5+
py{36,37}-django30
6+
py{36,37}-django31
77
py{36,37}-djangomaster
88

99
[testenv]
1010
setenv =
1111
DB = postgres
1212
deps =
13-
django20: Django>=2.0,<2.1
14-
django21: Django>=2.1,<2.2
15-
django22: Django>=2.2,<2.3
13+
django22: Django>=2.2,<3.0
14+
django30: Django>=3.0,<3.1
15+
django31: Django>=3.1,<3.2
1616
djangomaster: https://github.com/django/django/archive/master.tar.gz
1717
-rrequirements/requirements-testing.txt
1818
commands =
@@ -25,7 +25,7 @@ commands = flake8 entity_emailer
2525

2626
[travis:env]
2727
DJANGO =
28-
2.0: django20
29-
2.1: django21
3028
2.2: django22
29+
3.0: django30
30+
3.1: django31
3131
master: djangomaster

0 commit comments

Comments
 (0)