wbmailing 2.2.1__py2.py3-none-any.whl

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.

Potentially problematic release.


This version of wbmailing might be problematic. Click here for more details.

Files changed (57) hide show
  1. wbmailing/__init__.py +1 -0
  2. wbmailing/admin.py +74 -0
  3. wbmailing/apps.py +14 -0
  4. wbmailing/backend.py +131 -0
  5. wbmailing/celery.py +0 -0
  6. wbmailing/dynamic_preferences_registry.py +35 -0
  7. wbmailing/factories.py +211 -0
  8. wbmailing/filters/__init__.py +8 -0
  9. wbmailing/filters/mailing_lists.py +84 -0
  10. wbmailing/filters/mails.py +74 -0
  11. wbmailing/management/__init__.py +22 -0
  12. wbmailing/migrations/0001_initial_squashed_squashed_0008_alter_mail_bcc_email_alter_mail_cc_email_and_more.py +649 -0
  13. wbmailing/migrations/0002_delete_mailingsettings.py +16 -0
  14. wbmailing/migrations/0003_alter_mailinglistsubscriberchangerequest_options.py +25 -0
  15. wbmailing/migrations/__init__.py +0 -0
  16. wbmailing/models/__init__.py +6 -0
  17. wbmailing/models/mailing_lists.py +386 -0
  18. wbmailing/models/mails.py +895 -0
  19. wbmailing/serializers/__init__.py +19 -0
  20. wbmailing/serializers/mailing_lists.py +209 -0
  21. wbmailing/serializers/mails.py +251 -0
  22. wbmailing/tasks.py +37 -0
  23. wbmailing/templatetags/__init__.py +0 -0
  24. wbmailing/templatetags/mailing_tags.py +22 -0
  25. wbmailing/tests/__init__.py +0 -0
  26. wbmailing/tests/conftest.py +30 -0
  27. wbmailing/tests/models/__init__.py +0 -0
  28. wbmailing/tests/models/test_mailing_lists.py +297 -0
  29. wbmailing/tests/models/test_mails.py +205 -0
  30. wbmailing/tests/signals.py +124 -0
  31. wbmailing/tests/test_serializers.py +28 -0
  32. wbmailing/tests/test_tasks.py +49 -0
  33. wbmailing/tests/test_viewsets.py +216 -0
  34. wbmailing/tests/tests.py +142 -0
  35. wbmailing/urls.py +90 -0
  36. wbmailing/viewsets/__init__.py +32 -0
  37. wbmailing/viewsets/analytics.py +110 -0
  38. wbmailing/viewsets/buttons/__init__.py +10 -0
  39. wbmailing/viewsets/buttons/mailing_lists.py +91 -0
  40. wbmailing/viewsets/buttons/mails.py +98 -0
  41. wbmailing/viewsets/display/__init__.py +16 -0
  42. wbmailing/viewsets/display/mailing_lists.py +175 -0
  43. wbmailing/viewsets/display/mails.py +318 -0
  44. wbmailing/viewsets/endpoints/__init__.py +8 -0
  45. wbmailing/viewsets/endpoints/mailing_lists.py +86 -0
  46. wbmailing/viewsets/endpoints/mails.py +51 -0
  47. wbmailing/viewsets/mailing_lists.py +320 -0
  48. wbmailing/viewsets/mails.py +425 -0
  49. wbmailing/viewsets/menu/__init__.py +5 -0
  50. wbmailing/viewsets/menu/mailing_lists.py +37 -0
  51. wbmailing/viewsets/menu/mails.py +25 -0
  52. wbmailing/viewsets/titles/__init__.py +17 -0
  53. wbmailing/viewsets/titles/mailing_lists.py +63 -0
  54. wbmailing/viewsets/titles/mails.py +55 -0
  55. wbmailing-2.2.1.dist-info/METADATA +5 -0
  56. wbmailing-2.2.1.dist-info/RECORD +57 -0
  57. wbmailing-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,297 @@
1
+ import pytest
2
+ from django.contrib.auth.models import Permission
3
+ from faker import Faker
4
+ from wbcore.contrib.authentication.factories import UserFactory
5
+ from wbmailing.models.mailing_lists import (
6
+ MailingList,
7
+ MailingListEmailContactThroughModel,
8
+ MailingListSubscriberChangeRequest,
9
+ )
10
+
11
+ fake = Faker()
12
+
13
+
14
+ @pytest.mark.django_db
15
+ class TestMailingListSubscriberChangeRequest:
16
+ @pytest.fixture
17
+ def user_admin(self):
18
+ user = UserFactory.create()
19
+ perm = Permission.objects.get(codename="administrate_mailinglistsubscriberchangerequest")
20
+ user.user_permissions.add(perm)
21
+ return user
22
+
23
+ def test_init(self, mailing_list_subscriber_change_request):
24
+ """
25
+ Test basics creation logic:
26
+ - relationship creation from email contact and mailing list
27
+ """
28
+ assert mailing_list_subscriber_change_request
29
+ assert mailing_list_subscriber_change_request.status == MailingListSubscriberChangeRequest.Status.PENDING
30
+ rel = mailing_list_subscriber_change_request.relationship
31
+ assert rel.email_contact == mailing_list_subscriber_change_request.email_contact
32
+ assert rel.mailing_list == mailing_list_subscriber_change_request.mailing_list
33
+ assert rel.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
34
+
35
+ @pytest.mark.parametrize("mailing_list__is_public", [True, False])
36
+ def test_init_public_mailing_list(self, mailing_list_subscriber_change_request_factory, mailing_list):
37
+ """
38
+ Test if a request subscription creation to a public mailing list is automatically approved
39
+ """
40
+ request = mailing_list_subscriber_change_request_factory.create(mailing_list=mailing_list)
41
+ assert request.type == MailingListSubscriberChangeRequest.Type.SUBSCRIBING
42
+ if mailing_list.is_public:
43
+ assert request.status == MailingListSubscriberChangeRequest.Status.APPROVED
44
+ else:
45
+ assert request.status == MailingListSubscriberChangeRequest.Status.PENDING
46
+
47
+ @pytest.mark.parametrize(
48
+ "mailing_list_subscriber_change_request__type, description",
49
+ [
50
+ (MailingListSubscriberChangeRequest.Type.SUBSCRIBING, fake.sentence()),
51
+ (MailingListSubscriberChangeRequest.Type.UNSUBSCRIBING, fake.sentence()),
52
+ ],
53
+ )
54
+ def test_approve(self, mailing_list_subscriber_change_request, user, description):
55
+ mailing_list_subscriber_change_request.approve(by=user, description=description)
56
+ if mailing_list_subscriber_change_request.type == MailingListSubscriberChangeRequest.Type.SUBSCRIBING:
57
+ assert (
58
+ mailing_list_subscriber_change_request.relationship.status
59
+ == MailingListEmailContactThroughModel.Status.SUBSCRIBED
60
+ )
61
+ else:
62
+ assert (
63
+ mailing_list_subscriber_change_request.relationship.status
64
+ == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
65
+ )
66
+ assert mailing_list_subscriber_change_request.approver == user.profile
67
+ assert mailing_list_subscriber_change_request.reason == description
68
+
69
+ @pytest.mark.parametrize("description", [fake.sentence()])
70
+ def test_deny(self, mailing_list_subscriber_change_request, user, description):
71
+ """
72
+ Coverage test and unit test on description and approver from action trigerer
73
+ """
74
+ mailing_list_subscriber_change_request.deny(by=user, description=description)
75
+ mailing_list_subscriber_change_request.save()
76
+ assert mailing_list_subscriber_change_request.approver == user.profile
77
+ assert mailing_list_subscriber_change_request.reason == description
78
+
79
+ @pytest.mark.parametrize(
80
+ "mailing_list_email_contact_through_model__status, type, res",
81
+ [
82
+ (
83
+ MailingListEmailContactThroughModel.Status.SUBSCRIBED,
84
+ MailingListSubscriberChangeRequest.Type.UNSUBSCRIBING,
85
+ False,
86
+ ),
87
+ (
88
+ MailingListEmailContactThroughModel.Status.SUBSCRIBED,
89
+ MailingListSubscriberChangeRequest.Type.SUBSCRIBING,
90
+ False,
91
+ ),
92
+ (
93
+ MailingListEmailContactThroughModel.Status.UNSUBSCRIBED,
94
+ MailingListSubscriberChangeRequest.Type.UNSUBSCRIBING,
95
+ False,
96
+ ),
97
+ (
98
+ MailingListEmailContactThroughModel.Status.UNSUBSCRIBED,
99
+ MailingListSubscriberChangeRequest.Type.SUBSCRIBING,
100
+ True,
101
+ ),
102
+ ],
103
+ )
104
+ def test_subscribing(
105
+ self, mailing_list_email_contact_through_model, mailing_list_subscriber_change_request_factory, type, res
106
+ ):
107
+ """
108
+ Basic property result check
109
+ """
110
+ request = mailing_list_subscriber_change_request_factory.create(
111
+ type=type,
112
+ relationship=mailing_list_email_contact_through_model,
113
+ email_contact=mailing_list_email_contact_through_model.email_contact,
114
+ mailing_list=mailing_list_email_contact_through_model.mailing_list,
115
+ )
116
+ assert request.subscribing == res
117
+
118
+ def test_get_expired_date_subquery(
119
+ self, email_contact, mailing_list, mailing_list_subscriber_change_request_factory
120
+ ):
121
+ """
122
+ Check that expired date is the last approved and subscribing mailing change request
123
+ """
124
+ mailing_list_subscriber_change_request_factory.create(
125
+ type=MailingListSubscriberChangeRequest.Type.SUBSCRIBING,
126
+ status=MailingListSubscriberChangeRequest.Status.APPROVED,
127
+ mailing_list=mailing_list,
128
+ email_contact=email_contact,
129
+ expiration_date=fake.date_object(),
130
+ ) # oldest valid request
131
+ req = mailing_list_subscriber_change_request_factory.create(
132
+ type=MailingListSubscriberChangeRequest.Type.SUBSCRIBING,
133
+ status=MailingListSubscriberChangeRequest.Status.APPROVED,
134
+ mailing_list=mailing_list,
135
+ email_contact=email_contact,
136
+ expiration_date=fake.date_object(),
137
+ ) # expected expiration time request
138
+ mailing_list_subscriber_change_request_factory.create(
139
+ type=MailingListSubscriberChangeRequest.Type.UNSUBSCRIBING,
140
+ status=MailingListSubscriberChangeRequest.Status.APPROVED,
141
+ mailing_list=mailing_list,
142
+ email_contact=email_contact,
143
+ expiration_date=fake.date_object(),
144
+ ) # Unvalid request because not subscribing
145
+ mailing_list_subscriber_change_request_factory.create(
146
+ type=MailingListSubscriberChangeRequest.Type.SUBSCRIBING,
147
+ status=MailingListSubscriberChangeRequest.Status.PENDING,
148
+ mailing_list=mailing_list,
149
+ email_contact=email_contact,
150
+ expiration_date=fake.date_object(),
151
+ ) # Unvalid request because pending
152
+ assert (
153
+ MailingListEmailContactThroughModel.objects.annotate(
154
+ expiration_date=MailingListEmailContactThroughModel.get_expired_date_subquery()
155
+ )
156
+ .filter(mailing_list=mailing_list, email_contact=email_contact)
157
+ .values_list("expiration_date", flat=True)[0]
158
+ == req.expiration_date
159
+ )
160
+
161
+ def test_get_approvers(self, user, user_admin):
162
+ """
163
+ Test that approvers are the proper user with admin rights
164
+ """
165
+ assert set(MailingListSubscriberChangeRequest.get_approvers()) == {user_admin}
166
+ assert not MailingListSubscriberChangeRequest.get_approvers().filter(id=user.id).exists()
167
+
168
+
169
+ @pytest.mark.django_db
170
+ class TestMailingListEmailContactThroughModel:
171
+ def test_init(self, mailing_list_email_contact_through_model):
172
+ assert mailing_list_email_contact_through_model
173
+
174
+ def test_change_state(self, mailing_list_email_contact_through_model):
175
+ initial_status = mailing_list_email_contact_through_model.status
176
+ mailing_list_email_contact_through_model.change_state()
177
+ assert mailing_list_email_contact_through_model.status == initial_status
178
+ assert (
179
+ mailing_list_email_contact_through_model.requests.filter(
180
+ status=MailingListSubscriberChangeRequest.Status.PENDING
181
+ ).count()
182
+ == 1
183
+ )
184
+ mailing_list_email_contact_through_model.change_state(automatically_approve=True)
185
+ mailing_list_email_contact_through_model.refresh_from_db()
186
+ assert not mailing_list_email_contact_through_model.requests.filter(
187
+ status=MailingListSubscriberChangeRequest.Status.PENDING
188
+ ).exists()
189
+ assert mailing_list_email_contact_through_model.status != initial_status
190
+
191
+
192
+ @pytest.mark.django_db
193
+ class TestMailingList:
194
+ def test_init(self, mailing_list):
195
+ assert mailing_list
196
+
197
+ @pytest.mark.parametrize(
198
+ "mailing_list_email_contact_through_model__status", [MailingListEmailContactThroughModel.Status.SUBSCRIBED]
199
+ )
200
+ def test_unsubscription(self, mailing_list_email_contact_through_model):
201
+ """
202
+ Test unsubscription
203
+ """
204
+ email_contact = mailing_list_email_contact_through_model.email_contact
205
+ mailing_list = mailing_list_email_contact_through_model.mailing_list
206
+
207
+ mailing_list.unsubscribe(email_contact)
208
+ req = mailing_list_email_contact_through_model.requests.get(
209
+ status=MailingListSubscriberChangeRequest.Status.PENDING
210
+ )
211
+ assert (
212
+ mailing_list_email_contact_through_model.status == MailingListEmailContactThroughModel.Status.SUBSCRIBED
213
+ ) # We expect the contact to still be subscribed because the unsubscription request is still pending
214
+ req.approve()
215
+ mailing_list_email_contact_through_model.refresh_from_db()
216
+ assert (
217
+ mailing_list_email_contact_through_model.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
218
+ )
219
+
220
+ @pytest.mark.parametrize(
221
+ "mailing_list_email_contact_through_model__status", [MailingListEmailContactThroughModel.Status.SUBSCRIBED]
222
+ )
223
+ def test_unsubscription_automatically_approve(self, mailing_list_email_contact_through_model):
224
+ """
225
+ Test automatically approved unsubscription change request
226
+ """
227
+ email_contact = mailing_list_email_contact_through_model.email_contact
228
+ mailing_list = mailing_list_email_contact_through_model.mailing_list
229
+
230
+ mailing_list.unsubscribe(email_contact, automatically_approve=True)
231
+ mailing_list_email_contact_through_model.refresh_from_db()
232
+ assert (
233
+ mailing_list_email_contact_through_model.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
234
+ )
235
+
236
+ @pytest.mark.parametrize(
237
+ "mailing_list_email_contact_through_model__status", [MailingListEmailContactThroughModel.Status.UNSUBSCRIBED]
238
+ )
239
+ def test_subscription(self, mailing_list_email_contact_through_model):
240
+ """
241
+ Test subscription change request
242
+ """
243
+ email_contact = mailing_list_email_contact_through_model.email_contact
244
+ mailing_list = mailing_list_email_contact_through_model.mailing_list
245
+
246
+ mailing_list.subscribe(email_contact)
247
+ req = mailing_list_email_contact_through_model.requests.get(
248
+ status=MailingListSubscriberChangeRequest.Status.PENDING
249
+ )
250
+ assert (
251
+ mailing_list_email_contact_through_model.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
252
+ ) # We expect the contact to still be subscribed because the unsubscription request is still pending
253
+ req.approve()
254
+ mailing_list_email_contact_through_model.refresh_from_db()
255
+ assert mailing_list_email_contact_through_model.status == MailingListEmailContactThroughModel.Status.SUBSCRIBED
256
+
257
+ @pytest.mark.parametrize(
258
+ "mailing_list_email_contact_through_model__status", [MailingListEmailContactThroughModel.Status.UNSUBSCRIBED]
259
+ )
260
+ def test_subscription_automatically_approve(self, mailing_list_email_contact_through_model):
261
+ """
262
+ Test automatically approved subscription change request
263
+ """
264
+ email_contact = mailing_list_email_contact_through_model.email_contact
265
+ mailing_list = mailing_list_email_contact_through_model.mailing_list
266
+
267
+ mailing_list.subscribe(email_contact, automatically_approve=True)
268
+ mailing_list_email_contact_through_model.refresh_from_db()
269
+ assert mailing_list_email_contact_through_model.status == MailingListEmailContactThroughModel.Status.SUBSCRIBED
270
+
271
+ def test_get_subscribed_mailing_lists(self, mailing_list_email_contact_through_model_factory):
272
+ """
273
+ Test subscribed mailing list for a email contact.
274
+ """
275
+ rel_e1_ml1_subscribed = mailing_list_email_contact_through_model_factory.create(
276
+ status=MailingListEmailContactThroughModel.Status.SUBSCRIBED
277
+ )
278
+ e1 = rel_e1_ml1_subscribed.email_contact
279
+ m1 = rel_e1_ml1_subscribed.mailing_list
280
+
281
+ rel_e1_rel_ml2_unsubscribed = mailing_list_email_contact_through_model_factory.create(
282
+ email_contact=e1, status=MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
283
+ ) # We expect e1 to not show up in the valid emails queryset
284
+ m2 = rel_e1_rel_ml2_unsubscribed.mailing_list
285
+
286
+ rel_e2_ml1_subscribed = mailing_list_email_contact_through_model_factory.create(
287
+ mailing_list=m1, status=MailingListEmailContactThroughModel.Status.SUBSCRIBED
288
+ )
289
+ e2 = rel_e2_ml1_subscribed.email_contact
290
+ mailing_list_email_contact_through_model_factory.create(
291
+ email_contact=e2, mailing_list=m2, status=MailingListEmailContactThroughModel.Status.SUBSCRIBED
292
+ )
293
+
294
+ assert set(MailingList.get_subscribed_mailing_lists(e1)) == {
295
+ m1,
296
+ }
297
+ assert set(MailingList.get_subscribed_mailing_lists(e2)) == {m1, m2}
@@ -0,0 +1,205 @@
1
+ from unittest.mock import patch
2
+
3
+ import pytest
4
+ from anymail.signals import AnymailTrackingEvent, tracking
5
+ from django.core import mail
6
+ from django.test import override_settings
7
+ from rest_framework.test import APIRequestFactory
8
+ from wbcore.contrib.directory.factories import EmailContactFactory
9
+ from wbcore.contrib.documents.factories import DocumentFactory
10
+ from wbcore.test.utils import get_or_create_superuser
11
+ from wbmailing.backend import SendgridEmailBackend
12
+ from wbmailing.factories import ToEmailMailFactory
13
+ from wbmailing.models import MailEvent, MassMail
14
+ from wbmailing.models.mails import (
15
+ can_administrate_mail,
16
+ send_mail_task,
17
+ send_mass_mail_as_task,
18
+ )
19
+
20
+
21
+ @pytest.mark.django_db
22
+ class TestSpecificModels:
23
+ @patch("wbmailing.models.mails.send_mass_mail_as_task.delay")
24
+ def test_send_mail_task(self, send_mass_mail_as_task, mass_mail_factory, mailing_list_factory):
25
+ ec = EmailContactFactory()
26
+ ml = mailing_list_factory(email_contacts=(ec,))
27
+ mm = mass_mail_factory(mailing_lists=(ml,))
28
+
29
+ send_mail_task(mm.id)
30
+ send_mass_mail_as_task.assert_called()
31
+ assert send_mass_mail_as_task.call_count == 1
32
+
33
+ def test_send_mass_mail_as_task(self, mass_mail_factory, mailing_list_factory):
34
+ ec = EmailContactFactory()
35
+ ml = mailing_list_factory(email_contacts=(ec,))
36
+ mass_mail = mass_mail_factory(mailing_lists=(ml,))
37
+ assert len(mail.outbox) == 0
38
+ for subscriber in mass_mail.get_mail_addresses():
39
+ send_mass_mail_as_task(mass_mail.id, subscriber["address"])
40
+ assert len(mail.outbox) == 1
41
+
42
+ @pytest.mark.parametrize("status, expected", [("PENDING", "DENIED")])
43
+ def test_deny(self, mailing_list_subscriber_change_request_factory, status, expected):
44
+ mlscr = mailing_list_subscriber_change_request_factory()
45
+ mlscr.deny(description="SPAM")
46
+ assert mlscr.status == expected
47
+
48
+ @pytest.mark.parametrize("status, expected", [("DRAFT", "PENDING")])
49
+ def test_submit(self, mass_mail_factory, status, expected):
50
+ ml = mass_mail_factory()
51
+ ml.submit()
52
+ assert ml.status == expected
53
+
54
+ @pytest.mark.parametrize("status, expected", [("PENDING", "DENIED")])
55
+ def test_deny2(self, mass_mail_factory, status, expected):
56
+ ml = mass_mail_factory(status=MassMail.Status.PENDING)
57
+ ml.deny()
58
+ assert ml.status == expected
59
+
60
+ @pytest.mark.parametrize("status, expected", [("PENDING", "DRAFT")])
61
+ def test_revise(self, mass_mail_factory, status, expected):
62
+ ml = mass_mail_factory(status=MassMail.Status.PENDING)
63
+ ml.revise()
64
+ assert ml.status == expected
65
+
66
+ @patch("wbmailing.models.mails.send_mail_task.delay")
67
+ def test_send(self, send_mail_task, mass_mail_factory):
68
+ mm = mass_mail_factory(status=MassMail.Status.PENDING)
69
+ mm.send()
70
+ send_mail_task.assert_called()
71
+ assert send_mail_task.call_count == 1
72
+
73
+ def test_create_email(self, mass_mail_factory):
74
+ request = APIRequestFactory().get("")
75
+ request.user = get_or_create_superuser()
76
+ mm = mass_mail_factory(attachments=(DocumentFactory(),))
77
+ EmailContactFactory(address=request.user.email)
78
+ mm.template = None
79
+ mm.save()
80
+ msg = mm.create_email(request.user.email)
81
+ assert msg
82
+
83
+ @patch("wbmailing.models.mails.send_mail_as_task.delay")
84
+ def test_resend_no_massmail(self, send_mail_as_task):
85
+ request = APIRequestFactory().get("")
86
+ request.user = get_or_create_superuser()
87
+ obj = ToEmailMailFactory(attachments=(DocumentFactory(),))
88
+ obj.mass_mail = None
89
+ obj.save()
90
+ obj.resend()
91
+ send_mail_as_task.assert_called()
92
+ assert send_mail_as_task.call_count == 1
93
+
94
+ @patch("wbmailing.models.mails.send_mail_as_task.delay")
95
+ def test_resend_no_template(self, send_mail_as_task):
96
+ request = APIRequestFactory().get("")
97
+ request.user = get_or_create_superuser()
98
+ obj = ToEmailMailFactory()
99
+ obj.mass_mail.template = None
100
+ obj.mass_mail.save()
101
+ obj.resend()
102
+ send_mail_as_task.assert_called()
103
+ assert send_mail_as_task.call_count == 1
104
+
105
+ @override_settings(EMAIL_BACKEND="anymail.backends.test.EmailBackend")
106
+ @pytest.mark.parametrize(
107
+ "exits_message_id, event_type, reject_reason",
108
+ [
109
+ ("YES", MailEvent.EventType.SENT, None),
110
+ ("YES", MailEvent.EventType.SENT, MailEvent.RejectReason.SPAM),
111
+ ("YES", "Other", "Unknow"),
112
+ ("NO", "Other", None),
113
+ ],
114
+ )
115
+ def test_handle_mail_tracking(self, exits_message_id, event_type, reject_reason, mail_factory, mail_event_factory):
116
+ request = APIRequestFactory().get("")
117
+ request.user = get_or_create_superuser()
118
+ ml = ToEmailMailFactory()
119
+ nb_mail_send = len(mail.outbox)
120
+ esp_event = {}
121
+ if reject_reason:
122
+ mailevent = mail_event_factory(mail=ml, description="", reject_reason=reject_reason)
123
+ if reject_reason == MailEvent.RejectReason.SPAM:
124
+ esp_event["reason"] = "SPAM"
125
+ else:
126
+ esp_event["response"] = "Unknow"
127
+ else:
128
+ mailevent = mail_event_factory(mail=ml)
129
+
130
+ to = list(ml.to_email.values_list("address", flat=True))
131
+ msg = ml.get_mailmessage(ml.subject, ml.body, request.user.email, to, attachments=ml.documents.all())
132
+ msg.send()
133
+ assert len(mail.outbox) == nb_mail_send + 1
134
+ assert msg.anymail_status.status == {"sent"}
135
+ if exits_message_id == "YES":
136
+ message_id = mailevent.mail.message_ids[0]
137
+ else:
138
+ message_id = msg.anymail_status.message_id
139
+
140
+ esp_event["ip"] = mailevent.ip
141
+ esp_event["useragent"] = mailevent.user_agent
142
+ mevent = AnymailTrackingEvent(
143
+ event_type=event_type,
144
+ message_id=message_id,
145
+ timestamp=mailevent.timestamp,
146
+ event_id=mailevent.id,
147
+ recipient=mailevent.recipient,
148
+ reject_reason=mailevent.reject_reason,
149
+ description=mailevent.description,
150
+ user_agent=mailevent.user_agent,
151
+ click_url=mailevent.click_url,
152
+ esp_event=esp_event,
153
+ )
154
+ # sender(class) – The source of the event. (One of theanymail.webhook.*Viewclasses, but you generally won’t examine this parameter; it’s required by Django’s signalmechanism.
155
+ tracking.send(sender=msg, event=mevent, esp_name="SendGrid")
156
+
157
+ if exits_message_id == "YES":
158
+ assert MailEvent.objects.filter(mail=ml, recipient=mailevent.recipient).count() == 2
159
+ else:
160
+ assert MailEvent.objects.filter(mail=ml, recipient=mailevent.recipient).count() == 1
161
+
162
+ @override_settings(EMAIL_BACKEND="anymail.backends.test.EmailBackend", ANYMAIL_SENDGRID_API_KEY="TEST")
163
+ @patch("wbmailing.backend.SendgridEmailBackend._send")
164
+ @pytest.mark.parametrize("resend, exit_document", [(False, False), (False, True), (True, False)])
165
+ def test_SendgridEmailBackend_send_messages(self, mock_send, resend, exit_document):
166
+ request = APIRequestFactory().get("")
167
+ request.user = get_or_create_superuser()
168
+ num_sent = SendgridEmailBackend().send_messages(None)
169
+ assert num_sent == 0
170
+ doc1 = DocumentFactory()
171
+ ml = ToEmailMailFactory(cc_email=(EmailContactFactory(),), attachments=(doc1,))
172
+ to = list(ml.to_email.values_list("address", flat=True))
173
+ cc = list(ml.cc_email.values_list("address", flat=True))
174
+ bcc = ["lemissan@atonra.ch"]
175
+ if resend:
176
+ msg = ml.get_mailmessage(
177
+ ml.subject, ml.body, request.user.email, to, attachments=ml.documents.all(), mail=ml
178
+ )
179
+ else:
180
+ msg = ml.get_mailmessage(
181
+ ml.subject, ml.body, request.user.email, to, bcc=bcc, cc=cc, attachments=ml.documents.all()
182
+ )
183
+ msg.send()
184
+
185
+ if exit_document:
186
+ for name, payload, mimetype in msg.attachments:
187
+ doc1.name = name
188
+ doc1.save()
189
+
190
+ email_messages = [msg]
191
+
192
+ mock_send.return_value.status_code = 200
193
+ mock_send.return_value.json.return_value = msg
194
+
195
+ num_sent = SendgridEmailBackend().send_messages(email_messages)
196
+ mock_send.assert_called()
197
+ assert mock_send.call_count == 1
198
+ assert num_sent == 1
199
+
200
+ def test_can_administrate_mail(self, mass_mail_factory):
201
+ request = APIRequestFactory().get("")
202
+ request.user = get_or_create_superuser()
203
+ obj = mass_mail_factory()
204
+ result = can_administrate_mail(obj, request.user)
205
+ assert result
@@ -0,0 +1,124 @@
1
+ from django.dispatch import receiver
2
+ from wbcore.contrib.directory.models import EmailContact
3
+ from wbcore.test.signals import (
4
+ custom_update_data_from_factory,
5
+ custom_update_kwargs,
6
+ get_custom_factory,
7
+ )
8
+ from wbmailing.factories import (
9
+ CustomMassMailFactory,
10
+ EmailContactFactory,
11
+ MailEventFactory,
12
+ MailFactory,
13
+ MailingListFactory,
14
+ MailingListSubscriberChangeRequestFactory,
15
+ MassMailFactory,
16
+ ToEmailMailFactory,
17
+ )
18
+ from wbmailing.models import MailingListSubscriberChangeRequest
19
+ from wbmailing.viewsets import (
20
+ EmailContactMailingListModelViewSet,
21
+ MailEventMassMailMailModelViewSet,
22
+ MailingListEntryModelViewSet,
23
+ MailingListSubscriberChangeRequestModelViewSet,
24
+ MailingListSubscriberRequestEntryModelViewSet,
25
+ MailingListSubscriberRequestMailingListModelViewSet,
26
+ MailMailingListChartViewSet,
27
+ MailModelViewSet,
28
+ MailStatusMassMailModelViewSet,
29
+ MassMailModelViewSet,
30
+ )
31
+
32
+ # =================================================================================================================
33
+ # CUSTOM FACTORY
34
+ # =================================================================================================================
35
+
36
+
37
+ @receiver(get_custom_factory, sender=MassMailModelViewSet)
38
+ def receive_factory_mass_mail(sender, *args, **kwargs):
39
+ return CustomMassMailFactory
40
+
41
+
42
+ @receiver(get_custom_factory, sender=MailModelViewSet)
43
+ def receive_factory_toemail(sender, *args, **kwargs):
44
+ return ToEmailMailFactory
45
+
46
+
47
+ @receiver(get_custom_factory, sender=MailStatusMassMailModelViewSet)
48
+ def receive_factory_email(sender, *args, **kwargs):
49
+ return EmailContactFactory
50
+
51
+
52
+ # =================================================================================================================
53
+ # UPDATE DATA
54
+ # =================================================================================================================
55
+
56
+
57
+ @receiver(custom_update_data_from_factory, sender=MailingListSubscriberRequestMailingListModelViewSet)
58
+ @receiver(custom_update_data_from_factory, sender=MailingListSubscriberRequestEntryModelViewSet)
59
+ @receiver(custom_update_data_from_factory, sender=MailingListSubscriberChangeRequestModelViewSet)
60
+ def receive_data_mailinglist_subscriber(sender, *args, **kwargs):
61
+ if obj := kwargs.get("obj_factory"):
62
+ obj.status = MailingListSubscriberChangeRequest.Status.APPROVED
63
+ obj.save()
64
+ # return {"mailing_list": obj.mailing_list.id }
65
+ return {}
66
+
67
+
68
+ @receiver(custom_update_data_from_factory, sender=EmailContactMailingListModelViewSet)
69
+ def receive_data_email_contact_mailinglist(sender, *args, **kwargs):
70
+ if obj := kwargs.get("obj_factory"):
71
+ mlscr = MailingListSubscriberChangeRequestFactory(
72
+ status=MailingListSubscriberChangeRequest.Status.APPROVED, mailing_list=obj.mailing_list
73
+ )
74
+ return {"email_contact": mlscr.email_contact.id}
75
+ return {}
76
+
77
+
78
+ # =================================================================================================================
79
+ # UPDATE KWARGS
80
+ # =================================================================================================================
81
+
82
+
83
+ @receiver(custom_update_kwargs, sender=MailStatusMassMailModelViewSet)
84
+ def receive_kwargs_mass_mail_mail(sender, *args, **kwargs):
85
+ if obj := kwargs.get("obj_factory"):
86
+ ml = MailingListFactory.create(email_contacts=[obj])
87
+ mass_mail = MassMailFactory.create(mailing_lists=[ml])
88
+ MailEventFactory.create(recipient=obj.address)
89
+ MailFactory.create(mass_mail=mass_mail, to_email=[obj])
90
+ return {"mass_mail_id": mass_mail.id}
91
+ return {}
92
+
93
+
94
+ @receiver(custom_update_kwargs, sender=MailEventMassMailMailModelViewSet)
95
+ def receive_kwargs_mail_event_massmail(sender, *args, **kwargs):
96
+ if obj := kwargs.get("obj_factory"):
97
+ return {"mass_mail_id": obj.mail.mass_mail.id}
98
+ return {}
99
+
100
+
101
+ @receiver(custom_update_kwargs, sender=MailingListEntryModelViewSet)
102
+ def receive_kwargs_mailing_list_entry(sender, *args, **kwargs):
103
+ if email_id := kwargs.get("email_contact_id", None):
104
+ ec = EmailContact.objects.get(id=email_id)
105
+ return {"entry_id": ec.entry.id}
106
+ return {}
107
+
108
+
109
+ @receiver(custom_update_kwargs, sender=MailingListSubscriberRequestEntryModelViewSet)
110
+ def receive_kwargs_mailing_list_subscriber_entry(sender, *args, **kwargs):
111
+ if kwargs.get("email_contact_id"):
112
+ sec = kwargs.get("email_contact_id")
113
+ ec = EmailContact.objects.filter(id=sec).first()
114
+ return {"entry_id": ec.entry.id}
115
+ return {}
116
+
117
+
118
+ @receiver(custom_update_kwargs, sender=MailMailingListChartViewSet)
119
+ def receive_kwargs_mail_mailing_list(sender, *args, **kwargs):
120
+ if obj := kwargs.get("obj_factory"):
121
+ ml = MailingListFactory()
122
+ obj.mass_mail.mailing_lists.add(ml)
123
+ return {"mailing_list_id": ml.id}
124
+ return {}
@@ -0,0 +1,28 @@
1
+ import pytest
2
+ from django.core import mail
3
+ from rest_framework import status
4
+ from rest_framework.test import APIRequestFactory
5
+ from wbcore.contrib.directory.factories import EmailContactFactory
6
+ from wbcore.test.utils import get_kwargs
7
+ from wbmailing.factories import CustomMassMailFactory
8
+ from wbmailing.models import MassMail
9
+ from wbmailing.viewsets.mails import MassMailModelViewSet
10
+
11
+
12
+ @pytest.mark.django_db
13
+ class TestSpecificSerializers:
14
+ @pytest.mark.parametrize("mvs, factory", [(MassMailModelViewSet, CustomMassMailFactory)])
15
+ def test_serializers_mail(self, mvs, factory, user):
16
+ request = APIRequestFactory().get("")
17
+ request.user = user
18
+ obj = factory(status=MassMail.Status.SENT)
19
+ EmailContactFactory(address=request.user.email)
20
+ nb_mail_send = len(mail.outbox)
21
+ request.query_params = {}
22
+ mvs.request = request
23
+ mvs.kwargs = get_kwargs(obj, mvs, request)
24
+ mvs.kwargs["pk"] = obj.pk
25
+ response = mvs().sendtestmail(request)
26
+ assert response.status_code == status.HTTP_200_OK
27
+ assert response.data
28
+ assert len(mail.outbox) == nb_mail_send + 1