edx-ace 1.11.1__tar.gz → 1.11.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {edx-ace-1.11.1/edx_ace.egg-info → edx-ace-1.11.3}/PKG-INFO +1 -1
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/__init__.py +1 -1
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/__init__.py +3 -1
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/delivery.py +2 -2
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_delivery.py +5 -5
- edx-ace-1.11.3/edx_ace/tests/utils/test_signals.py +47 -0
- edx-ace-1.11.3/edx_ace/utils/signals.py +46 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3/edx_ace.egg-info}/PKG-INFO +1 -1
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace.egg-info/SOURCES.txt +2 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/CHANGELOG.rst +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/LICENSE.txt +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/MANIFEST.in +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/README.rst +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/ace.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/apps.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/braze.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/django_email.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/file.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/mixins.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/push_notification.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/channel/sailthru.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/errors.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/message.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/monitoring.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/policy.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/presentation.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/push_notifications/views/__init__.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/recipient.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/recipient_resolver.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/renderers.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/serialization.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/signals.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/templatetags/acetags.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/test_utils/__init__.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/channel/test_braze.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/channel/test_channel_helpers.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/channel/test_django_email.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/channel/test_file_email.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/channel/test_push_notification.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/channel/test_sailthru.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_ace.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_date.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_message.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_policy.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_presentation.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_templates/testapp/edx_ace/testmessage/email/body.html +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/tests/test_templates/testapp/edx_ace/testmessage/email/head.html +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/utils/__init__.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/utils/date.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/utils/once.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace/utils/plugins.py +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace.egg-info/dependency_links.txt +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace.egg-info/entry_points.txt +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace.egg-info/not-zip-safe +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace.egg-info/requires.txt +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/edx_ace.egg-info/top_level.txt +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/requirements/base.in +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/requirements/constraints.txt +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/setup.cfg +0 -0
- {edx-ace-1.11.1 → edx-ace-1.11.3}/setup.py +0 -0
@@ -176,7 +176,9 @@ def get_channel_for_message(channel_type, message):
|
|
176
176
|
channel_names = []
|
177
177
|
|
178
178
|
if channel_type == ChannelType.EMAIL:
|
179
|
-
if message.options.get('
|
179
|
+
if message.options.get('override_default_channel'):
|
180
|
+
channel_names = [message.options.get('override_default_channel')]
|
181
|
+
elif message.options.get('transactional'):
|
180
182
|
channel_names = [settings.ACE_CHANNEL_TRANSACTIONAL_EMAIL, settings.ACE_CHANNEL_DEFAULT_EMAIL]
|
181
183
|
else:
|
182
184
|
channel_names = [settings.ACE_CHANNEL_DEFAULT_EMAIL]
|
@@ -10,8 +10,8 @@ import time
|
|
10
10
|
from django.conf import settings
|
11
11
|
|
12
12
|
from edx_ace.errors import RecoverableChannelDeliveryError
|
13
|
-
from edx_ace.signals import ACE_MESSAGE_SENT
|
14
13
|
from edx_ace.utils.date import get_current_time
|
14
|
+
from edx_ace.utils.signals import send_ace_message_sent_signal
|
15
15
|
|
16
16
|
LOG = logging.getLogger(__name__)
|
17
17
|
|
@@ -61,7 +61,7 @@ def deliver(channel, rendered_message, message):
|
|
61
61
|
message.report(f'{channel_type}_delivery_retried', num_seconds)
|
62
62
|
else:
|
63
63
|
message.report(f'{channel_type}_delivery_succeeded', True)
|
64
|
-
|
64
|
+
send_ace_message_sent_signal(channel, message)
|
65
65
|
return
|
66
66
|
|
67
67
|
delivery_expired_report = f'{channel_type}_delivery_expired'
|
@@ -34,19 +34,19 @@ class TestDelivery(TestCase): # pylint: disable=missing-class-docstring
|
|
34
34
|
)
|
35
35
|
self.current_time = datetime.datetime.utcnow().replace(tzinfo=tzutc())
|
36
36
|
|
37
|
-
@patch('edx_ace.delivery.
|
37
|
+
@patch('edx_ace.delivery.send_ace_message_sent_signal')
|
38
38
|
def test_happy_path(self, mock_ace_message_sent):
|
39
39
|
deliver(self.mock_channel, sentinel.rendered_email, self.message)
|
40
40
|
self.mock_channel.deliver.assert_called_once_with(self.message, sentinel.rendered_email)
|
41
41
|
# check if ACE_MESSAGE_SENT is raised
|
42
|
-
mock_ace_message_sent.assert_called_once_with(
|
42
|
+
mock_ace_message_sent.assert_called_once_with(self.mock_channel, self.message)
|
43
43
|
|
44
44
|
def test_fatal_error(self):
|
45
45
|
self.mock_channel.deliver.side_effect = FatalChannelDeliveryError('testing')
|
46
46
|
with self.assertRaises(FatalChannelDeliveryError):
|
47
47
|
deliver(self.mock_channel, sentinel.rendered_email, self.message)
|
48
48
|
|
49
|
-
@patch('edx_ace.delivery.
|
49
|
+
@patch('edx_ace.delivery.send_ace_message_sent_signal')
|
50
50
|
@patch('edx_ace.delivery.get_current_time')
|
51
51
|
def test_custom_message_expiration(self, mock_get_current_time, mock_ace_message_sent):
|
52
52
|
self.message.expiration_time = self.current_time - datetime.timedelta(seconds=10)
|
@@ -106,7 +106,7 @@ class TestDelivery(TestCase): # pylint: disable=missing-class-docstring
|
|
106
106
|
assert mock_time.sleep.call_args_list == [call(1), call(1)]
|
107
107
|
assert self.mock_channel.deliver.call_count == 3
|
108
108
|
|
109
|
-
@patch('edx_ace.delivery.
|
109
|
+
@patch('edx_ace.delivery.send_ace_message_sent_signal')
|
110
110
|
def test_message_sent_signal_for_push_channel(self, mock_ace_message_sent):
|
111
111
|
"""
|
112
112
|
Test that ACE_MESSAGE_SENT signal is sent when a message is delivered to a push channel.
|
@@ -117,4 +117,4 @@ class TestDelivery(TestCase): # pylint: disable=missing-class-docstring
|
|
117
117
|
)
|
118
118
|
deliver(mock_push_channel, sentinel.rendered_email, self.message)
|
119
119
|
# check if ACE_MESSAGE_SENT is raised
|
120
|
-
mock_ace_message_sent.assert_called_once_with(
|
120
|
+
mock_ace_message_sent.assert_called_once_with(mock_push_channel, self.message)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
"""
|
2
|
+
Tests for the utils/signals module.
|
3
|
+
"""
|
4
|
+
from django.test import TestCase
|
5
|
+
|
6
|
+
from edx_ace.utils.signals import make_serializable_object
|
7
|
+
|
8
|
+
|
9
|
+
class TestMakeSerializableObject(TestCase):
|
10
|
+
def test_primitive_types(self):
|
11
|
+
self.assertEqual(make_serializable_object(42), 42)
|
12
|
+
self.assertEqual(make_serializable_object(3.14), 3.14)
|
13
|
+
self.assertEqual(make_serializable_object("string"), "string")
|
14
|
+
self.assertEqual(make_serializable_object(True), True)
|
15
|
+
self.assertEqual(make_serializable_object(None), None)
|
16
|
+
|
17
|
+
def test_dict(self):
|
18
|
+
input_dict = {
|
19
|
+
"int": 1,
|
20
|
+
"float": 2.0,
|
21
|
+
"str": "test",
|
22
|
+
"bool": False,
|
23
|
+
"none": None,
|
24
|
+
"list": [1, 2, 3],
|
25
|
+
"nested_dict": {"key": "value"}
|
26
|
+
}
|
27
|
+
self.assertEqual(make_serializable_object(input_dict), input_dict)
|
28
|
+
|
29
|
+
def test_list(self):
|
30
|
+
input_list = [1, 2.0, "test", False, None, [1, 2, 3], {"key": "value"}]
|
31
|
+
self.assertEqual(make_serializable_object(input_list), input_list)
|
32
|
+
|
33
|
+
def test_non_serializable(self):
|
34
|
+
class NonSerializable:
|
35
|
+
pass
|
36
|
+
|
37
|
+
obj = NonSerializable()
|
38
|
+
self.assertEqual(make_serializable_object(obj), str(obj))
|
39
|
+
|
40
|
+
def test_non_serializable_list(self):
|
41
|
+
class NonSerializable:
|
42
|
+
pass
|
43
|
+
|
44
|
+
obj = NonSerializable()
|
45
|
+
obj2 = NonSerializable()
|
46
|
+
obj_list = [obj, obj2]
|
47
|
+
self.assertEqual(make_serializable_object(obj_list), [str(obj), str(obj2)])
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"""
|
2
|
+
Utils for signals.
|
3
|
+
"""
|
4
|
+
from edx_ace.signals import ACE_MESSAGE_SENT
|
5
|
+
|
6
|
+
|
7
|
+
def make_serializable_object(obj):
|
8
|
+
"""
|
9
|
+
Takes a dictionary/list and returns a dictionary/list with all the values converted
|
10
|
+
to JSON serializable objects.
|
11
|
+
"""
|
12
|
+
try:
|
13
|
+
if isinstance(obj, (int, float, str, bool)) or obj is None:
|
14
|
+
return obj
|
15
|
+
elif isinstance(obj, dict):
|
16
|
+
return {key: make_serializable_object(value) for key, value in obj.items()}
|
17
|
+
elif isinstance(obj, list):
|
18
|
+
return [make_serializable_object(element) for element in obj]
|
19
|
+
except Exception: # pylint: disable=broad-except
|
20
|
+
pass
|
21
|
+
return str(obj)
|
22
|
+
|
23
|
+
|
24
|
+
def send_ace_message_sent_signal(channel, message):
|
25
|
+
"""
|
26
|
+
Creates dictionary from message, makes it JSON serializable and
|
27
|
+
sends the ACE_MESSAGE_SENT signal.
|
28
|
+
"""
|
29
|
+
try:
|
30
|
+
channel_name = channel.__class__.__name__
|
31
|
+
except AttributeError:
|
32
|
+
channel_name = 'Other'
|
33
|
+
data = {
|
34
|
+
'name': message.name,
|
35
|
+
'app_label': message.app_label,
|
36
|
+
'recipient': {
|
37
|
+
'email': getattr(message.recipient, 'email_address', ''),
|
38
|
+
'user_id': getattr(message.recipient, 'lms_user_id', ''),
|
39
|
+
},
|
40
|
+
'channel': channel_name,
|
41
|
+
'context': message.context,
|
42
|
+
'options': message.options,
|
43
|
+
'uuid': str(message.uuid),
|
44
|
+
'send_uuid': str(message.send_uuid),
|
45
|
+
}
|
46
|
+
ACE_MESSAGE_SENT.send(sender=channel, message=make_serializable_object(data))
|
@@ -49,9 +49,11 @@ edx_ace/tests/channel/test_push_notification.py
|
|
49
49
|
edx_ace/tests/channel/test_sailthru.py
|
50
50
|
edx_ace/tests/test_templates/testapp/edx_ace/testmessage/email/body.html
|
51
51
|
edx_ace/tests/test_templates/testapp/edx_ace/testmessage/email/head.html
|
52
|
+
edx_ace/tests/utils/test_signals.py
|
52
53
|
edx_ace/utils/__init__.py
|
53
54
|
edx_ace/utils/date.py
|
54
55
|
edx_ace/utils/once.py
|
55
56
|
edx_ace/utils/plugins.py
|
57
|
+
edx_ace/utils/signals.py
|
56
58
|
requirements/base.in
|
57
59
|
requirements/constraints.txt
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|