edx-ace 1.11.0__tar.gz → 1.11.2__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.0/edx_ace.egg-info → edx-ace-1.11.2}/PKG-INFO +1 -1
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/__init__.py +1 -1
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/delivery.py +2 -3
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_delivery.py +20 -2
- edx-ace-1.11.2/edx_ace/tests/utils/test_signals.py +47 -0
- edx-ace-1.11.2/edx_ace/utils/signals.py +46 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2/edx_ace.egg-info}/PKG-INFO +1 -1
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace.egg-info/SOURCES.txt +2 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/CHANGELOG.rst +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/LICENSE.txt +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/MANIFEST.in +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/README.rst +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/ace.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/apps.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/__init__.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/braze.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/django_email.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/file.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/mixins.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/push_notification.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/channel/sailthru.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/errors.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/message.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/monitoring.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/policy.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/presentation.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/push_notifications/views/__init__.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/recipient.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/recipient_resolver.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/renderers.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/serialization.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/signals.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/templatetags/acetags.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/test_utils/__init__.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/channel/test_braze.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/channel/test_channel_helpers.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/channel/test_django_email.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/channel/test_file_email.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/channel/test_push_notification.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/channel/test_sailthru.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_ace.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_date.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_message.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_policy.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_presentation.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_templates/testapp/edx_ace/testmessage/email/body.html +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/tests/test_templates/testapp/edx_ace/testmessage/email/head.html +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/utils/__init__.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/utils/date.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/utils/once.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace/utils/plugins.py +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace.egg-info/dependency_links.txt +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace.egg-info/entry_points.txt +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace.egg-info/not-zip-safe +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace.egg-info/requires.txt +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/edx_ace.egg-info/top_level.txt +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/requirements/base.in +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/requirements/constraints.txt +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/setup.cfg +0 -0
- {edx-ace-1.11.0 → edx-ace-1.11.2}/setup.py +0 -0
@@ -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,10 +61,9 @@ 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'
|
68
68
|
logger.debug(delivery_expired_report)
|
69
69
|
message.report(delivery_expired_report, get_current_time() - start_time)
|
70
|
-
ACE_MESSAGE_SENT.send(sender=channel, message=message)
|
@@ -34,21 +34,26 @@ class TestDelivery(TestCase): # pylint: disable=missing-class-docstring
|
|
34
34
|
)
|
35
35
|
self.current_time = datetime.datetime.utcnow().replace(tzinfo=tzutc())
|
36
36
|
|
37
|
-
|
37
|
+
@patch('edx_ace.delivery.send_ace_message_sent_signal')
|
38
|
+
def test_happy_path(self, mock_ace_message_sent):
|
38
39
|
deliver(self.mock_channel, sentinel.rendered_email, self.message)
|
39
40
|
self.mock_channel.deliver.assert_called_once_with(self.message, sentinel.rendered_email)
|
41
|
+
# check if ACE_MESSAGE_SENT is raised
|
42
|
+
mock_ace_message_sent.assert_called_once_with(self.mock_channel, self.message)
|
40
43
|
|
41
44
|
def test_fatal_error(self):
|
42
45
|
self.mock_channel.deliver.side_effect = FatalChannelDeliveryError('testing')
|
43
46
|
with self.assertRaises(FatalChannelDeliveryError):
|
44
47
|
deliver(self.mock_channel, sentinel.rendered_email, self.message)
|
45
48
|
|
49
|
+
@patch('edx_ace.delivery.send_ace_message_sent_signal')
|
46
50
|
@patch('edx_ace.delivery.get_current_time')
|
47
|
-
def test_custom_message_expiration(self, mock_get_current_time):
|
51
|
+
def test_custom_message_expiration(self, mock_get_current_time, mock_ace_message_sent):
|
48
52
|
self.message.expiration_time = self.current_time - datetime.timedelta(seconds=10)
|
49
53
|
mock_get_current_time.return_value = self.current_time
|
50
54
|
deliver(self.mock_channel, sentinel.rendered_email, self.message)
|
51
55
|
assert not self.mock_channel.deliver.called
|
56
|
+
mock_ace_message_sent.assert_not_called()
|
52
57
|
|
53
58
|
@patch('edx_ace.delivery.time')
|
54
59
|
@patch('edx_ace.delivery.get_current_time')
|
@@ -100,3 +105,16 @@ class TestDelivery(TestCase): # pylint: disable=missing-class-docstring
|
|
100
105
|
deliver(self.mock_channel, sentinel.rendered_email, self.message)
|
101
106
|
assert mock_time.sleep.call_args_list == [call(1), call(1)]
|
102
107
|
assert self.mock_channel.deliver.call_count == 3
|
108
|
+
|
109
|
+
@patch('edx_ace.delivery.send_ace_message_sent_signal')
|
110
|
+
def test_message_sent_signal_for_push_channel(self, mock_ace_message_sent):
|
111
|
+
"""
|
112
|
+
Test that ACE_MESSAGE_SENT signal is sent when a message is delivered to a push channel.
|
113
|
+
"""
|
114
|
+
mock_push_channel = Mock(
|
115
|
+
name='push_channel',
|
116
|
+
channel_type=ChannelType.PUSH
|
117
|
+
)
|
118
|
+
deliver(mock_push_channel, sentinel.rendered_email, self.message)
|
119
|
+
# check if ACE_MESSAGE_SENT is raised
|
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
|
File without changes
|