Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
include README.md
include LICENSE
recursive-include requirements *
19 changes: 18 additions & 1 deletion entity_emailer/interface.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import sys

from datetime import datetime

from django.core import mail
from entity_event import context_loader

from entity_emailer.models import Email
from entity_emailer.signals import pre_send

from entity_emailer.utils import get_medium, get_from_email_address, get_subscribed_email_addresses, \
create_email_message, extract_email_subject_from_html_content
Expand All @@ -26,7 +29,7 @@ def send_unsent_scheduled_emails():
scheduled__lte=current_time,
sent__isnull=True
).select_related(
'event'
'event__source'
).prefetch_related(
'recipients'
)
Expand All @@ -38,14 +41,28 @@ def send_unsent_scheduled_emails():
for email in to_send:
to_email_addresses = get_subscribed_email_addresses(email)
if to_email_addresses:
# Render the email
text_message, html_message = email.render(email_medium)

# Create the email
message = create_email_message(
to_emails=to_email_addresses,
from_email=email.from_address or get_from_email_address(),
subject=email.subject or extract_email_subject_from_html_content(html_message),
text=text_message,
html=html_message,
)

# Fire the pre send signal
pre_send.send(
sender=sys.intern(email.event.source.name),
email=email,
event=email.event,
context=email.event.context,
message=message,
)

# Add the email to the list of emails that need to be sent
emails.append(message)

connection = mail.get_connection()
Expand Down
5 changes: 5 additions & 0 deletions entity_emailer/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.dispatch import Signal


# An event that will be fired prior to an email being sent
pre_send = Signal(providing_args=['email', 'event', 'context', 'message'])
31 changes: 31 additions & 0 deletions entity_emailer/tests/interface_tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime

from django.core import mail
from django.core.mail import EmailMultiAlternatives
from django.core.management import call_command
from django.test import TestCase, SimpleTestCase
from django.test.utils import override_settings
Expand Down Expand Up @@ -343,6 +344,36 @@ def test_sends_all_scheduled_emails(self, render_mock, address_mock):
EntityEmailerInterface.send_unsent_scheduled_emails()
self.assertEqual(len(mail.outbox), 2)

@patch('entity_emailer.interface.pre_send')
@patch('entity_emailer.interface.get_subscribed_email_addresses')
@patch.object(Event, 'render', spec_set=True)
def test_send_signals(self, render_mock, address_mock, mock_pre_send):
"""
Test that we properly fire signals during the send process
"""

# Setup the email
render_mock.return_value = ['<p>This is a test html email.</p>', 'This is a test text email.']
address_mock.return_value = ['test1@example.com', 'test2@example.com']
email = g_email(context={
'test': 'test'
}, scheduled=datetime.min)
EntityEmailerInterface.send_unsent_scheduled_emails()

# Assert that we sent the email
self.assertEqual(len(mail.outbox), 1)

# Assert that we called the pre send signal with the proper values
name, args, kwargs = mock_pre_send.send.mock_calls[0]
self.assertEqual(kwargs['sender'], email.event.source.name)
self.assertEqual(kwargs['email'], email)
self.assertEqual(kwargs['event'], email.event)
self.assertEqual(kwargs['context'], {
'test': 'test',
'entity_emailer_id': str(email.view_uid)
})
self.assertIsInstance(kwargs['message'], EmailMultiAlternatives)

@patch('entity_emailer.interface.get_subscribed_email_addresses')
@patch.object(Event, 'render', spec_set=True)
def test_sends_email_with_specified_from_address(self, render_mock, address_mock):
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__ = '1.1.0'
__version__ = '1.1.1'
4 changes: 4 additions & 0 deletions release_notes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Release Notes
=============

v1.1.1
------
* Add `pre_send` signal

v1.1.0
------
* Python 3.7
Expand Down
6 changes: 6 additions & 0 deletions requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
beautifulsoup4>=4.3.2
Django>=2.0
django-db-mutex>=1.2.0
django-entity>=4.2.0
django-entity-event>=1.2.0
ambition-django-uuidfield>=0.5.0
4 changes: 2 additions & 2 deletions run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from django_nose import NoseTestSuiteRunner


def run_tests(*test_args, **kwargs):
def run(*test_args, **kwargs):
if not test_args:
test_args = ['entity_emailer']

Expand All @@ -30,4 +30,4 @@ def run_tests(*test_args, **kwargs):
parser.add_option('--verbosity', dest='verbosity', action='store', default=1, type=int)
(options, args) = parser.parse_args()

run_tests(*args, **options.__dict__)
run(*args, **options.__dict__)
34 changes: 19 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from os import path

import re
from setuptools import setup, find_packages

Expand All @@ -18,6 +20,20 @@ def get_version():
raise RuntimeError('Unable to find version string in {0}.'.format(VERSION_FILE))


def get_requirements(requirements_file):
"""
Gets a list of requirements from requirements.txt.
"""
with open(path.join(path.dirname(__file__), 'requirements', requirements_file)) as requirements_file:
requirements = requirements_file.readlines()

requirements = [r.strip() for r in requirements if r.strip()]

return [
r for r in requirements
if not r.startswith('#') and not r.startswith('-')
]

setup(
name='django-entity-emailer',
version=get_version(),
Expand All @@ -41,20 +57,8 @@ def get_version():
'Framework :: Django :: 2.2',
],
license='MIT',
install_requires=[
'beautifulsoup4>=4.3.2',
'Django>=2.0',
'django-db-mutex>=1.2.0',
'django-entity>=4.2.0',
'django-entity-event>=1.2.0',
'ambition-django-uuidfield>=0.5.0',
],
tests_require=[
'django-dynamic-fixture',
'django-nose>=1.4',
'freezegun',
'mock',
],
test_suite='run_tests.run_tests',
install_requires=get_requirements('requirements.txt'),
tests_require=get_requirements('requirements-testing.txt'),
test_suite='run_tests.run',
include_package_data=True,
)