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.
- wbmailing/__init__.py +1 -0
- wbmailing/admin.py +74 -0
- wbmailing/apps.py +14 -0
- wbmailing/backend.py +131 -0
- wbmailing/celery.py +0 -0
- wbmailing/dynamic_preferences_registry.py +35 -0
- wbmailing/factories.py +211 -0
- wbmailing/filters/__init__.py +8 -0
- wbmailing/filters/mailing_lists.py +84 -0
- wbmailing/filters/mails.py +74 -0
- wbmailing/management/__init__.py +22 -0
- wbmailing/migrations/0001_initial_squashed_squashed_0008_alter_mail_bcc_email_alter_mail_cc_email_and_more.py +649 -0
- wbmailing/migrations/0002_delete_mailingsettings.py +16 -0
- wbmailing/migrations/0003_alter_mailinglistsubscriberchangerequest_options.py +25 -0
- wbmailing/migrations/__init__.py +0 -0
- wbmailing/models/__init__.py +6 -0
- wbmailing/models/mailing_lists.py +386 -0
- wbmailing/models/mails.py +895 -0
- wbmailing/serializers/__init__.py +19 -0
- wbmailing/serializers/mailing_lists.py +209 -0
- wbmailing/serializers/mails.py +251 -0
- wbmailing/tasks.py +37 -0
- wbmailing/templatetags/__init__.py +0 -0
- wbmailing/templatetags/mailing_tags.py +22 -0
- wbmailing/tests/__init__.py +0 -0
- wbmailing/tests/conftest.py +30 -0
- wbmailing/tests/models/__init__.py +0 -0
- wbmailing/tests/models/test_mailing_lists.py +297 -0
- wbmailing/tests/models/test_mails.py +205 -0
- wbmailing/tests/signals.py +124 -0
- wbmailing/tests/test_serializers.py +28 -0
- wbmailing/tests/test_tasks.py +49 -0
- wbmailing/tests/test_viewsets.py +216 -0
- wbmailing/tests/tests.py +142 -0
- wbmailing/urls.py +90 -0
- wbmailing/viewsets/__init__.py +32 -0
- wbmailing/viewsets/analytics.py +110 -0
- wbmailing/viewsets/buttons/__init__.py +10 -0
- wbmailing/viewsets/buttons/mailing_lists.py +91 -0
- wbmailing/viewsets/buttons/mails.py +98 -0
- wbmailing/viewsets/display/__init__.py +16 -0
- wbmailing/viewsets/display/mailing_lists.py +175 -0
- wbmailing/viewsets/display/mails.py +318 -0
- wbmailing/viewsets/endpoints/__init__.py +8 -0
- wbmailing/viewsets/endpoints/mailing_lists.py +86 -0
- wbmailing/viewsets/endpoints/mails.py +51 -0
- wbmailing/viewsets/mailing_lists.py +320 -0
- wbmailing/viewsets/mails.py +425 -0
- wbmailing/viewsets/menu/__init__.py +5 -0
- wbmailing/viewsets/menu/mailing_lists.py +37 -0
- wbmailing/viewsets/menu/mails.py +25 -0
- wbmailing/viewsets/titles/__init__.py +17 -0
- wbmailing/viewsets/titles/mailing_lists.py +63 -0
- wbmailing/viewsets/titles/mails.py +55 -0
- wbmailing-2.2.1.dist-info/METADATA +5 -0
- wbmailing-2.2.1.dist-info/RECORD +57 -0
- wbmailing-2.2.1.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
from django.contrib.auth import get_user_model
|
|
2
|
+
from django.db import models
|
|
3
|
+
from django.db.models import Exists, OuterRef, Subquery
|
|
4
|
+
from django.db.models.signals import post_delete, post_save
|
|
5
|
+
from django.dispatch import receiver
|
|
6
|
+
from django.utils.translation import gettext
|
|
7
|
+
from django.utils.translation import gettext_lazy as _
|
|
8
|
+
from django_fsm import FSMField, transition
|
|
9
|
+
from wbcore.contrib.directory.models import EmailContact
|
|
10
|
+
from wbcore.contrib.directory.signals import deactivate_profile
|
|
11
|
+
from wbcore.contrib.icons import WBIcon
|
|
12
|
+
from wbcore.contrib.notifications.dispatch import send_notification
|
|
13
|
+
from wbcore.contrib.notifications.utils import create_notification_type
|
|
14
|
+
from wbcore.enums import RequestType
|
|
15
|
+
from wbcore.metadata.configs.buttons import ActionButton, ButtonDefaultColor
|
|
16
|
+
from wbcore.models import WBModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def can_administrate_change_request(mail, user):
|
|
20
|
+
return user.has_perm("wbmailing.administrate_mailinglistsubscriberchangerequest") or user.is_superuser
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MailingListSubscriberChangeRequest(models.Model):
|
|
24
|
+
class Type(models.TextChoices):
|
|
25
|
+
SUBSCRIBING = "SUBSCRIBING", _("Subscribing")
|
|
26
|
+
UNSUBSCRIBING = "UNSUBSCRIBING", _("Unsubscribing")
|
|
27
|
+
|
|
28
|
+
class Status(models.TextChoices):
|
|
29
|
+
PENDING = "PENDING", _("Pending")
|
|
30
|
+
APPROVED = "APPROVED", _("Approved")
|
|
31
|
+
DENIED = "DENIED", _("Denied")
|
|
32
|
+
|
|
33
|
+
status = FSMField(default=Status.PENDING, choices=Status.choices, verbose_name=_("Status"))
|
|
34
|
+
type = models.CharField(max_length=32, choices=Type.choices, verbose_name=_("Type"))
|
|
35
|
+
|
|
36
|
+
@transition(
|
|
37
|
+
field=status,
|
|
38
|
+
source=[Status.PENDING],
|
|
39
|
+
target=Status.APPROVED,
|
|
40
|
+
permission=can_administrate_change_request,
|
|
41
|
+
custom={
|
|
42
|
+
"_transition_button": ActionButton(
|
|
43
|
+
method=RequestType.PATCH,
|
|
44
|
+
identifiers=("wbmailing:mailinglistsubscriberchangerequest",),
|
|
45
|
+
color=ButtonDefaultColor.SUCCESS,
|
|
46
|
+
icon=WBIcon.APPROVE.icon,
|
|
47
|
+
key="approve",
|
|
48
|
+
label=_("Approve"),
|
|
49
|
+
action_label=_("Approving"),
|
|
50
|
+
description_fields=_(
|
|
51
|
+
"<p>Address: {{_email_contact.address}}</p><p>Mailing list: {{_mailing_list.title}}</p>"
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
def approve(self, by=None, description=None, **kwargs):
|
|
57
|
+
if profile := getattr(by, "profile", None):
|
|
58
|
+
self.approver = profile
|
|
59
|
+
if self.subscribing:
|
|
60
|
+
self.relationship.status = MailingListEmailContactThroughModel.Status.SUBSCRIBED
|
|
61
|
+
else:
|
|
62
|
+
self.relationship.status = MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
|
|
63
|
+
self.relationship.save()
|
|
64
|
+
if description:
|
|
65
|
+
self.reason = description
|
|
66
|
+
if self.requester != self.approver and (user := getattr(self.requester, "user_account", None)):
|
|
67
|
+
approver_repr = self.approver.full_name if self.approver else "Unknown"
|
|
68
|
+
send_notification(
|
|
69
|
+
code="wbmailing.mailinglistsubscriberchangerequest.notify",
|
|
70
|
+
title=f"{self.type} change request for {self.email_contact.address} to {self.mailing_list.title} approved by {approver_repr}",
|
|
71
|
+
body=self.reason,
|
|
72
|
+
user=user,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@transition(
|
|
76
|
+
field=status,
|
|
77
|
+
source=[Status.PENDING],
|
|
78
|
+
target=Status.DENIED,
|
|
79
|
+
permission=can_administrate_change_request,
|
|
80
|
+
custom={
|
|
81
|
+
"_transition_button": ActionButton(
|
|
82
|
+
method=RequestType.PATCH,
|
|
83
|
+
color=ButtonDefaultColor.ERROR,
|
|
84
|
+
identifiers=("wbmailing:mailinglistsubscriberchangerequest",),
|
|
85
|
+
icon=WBIcon.DENY.icon,
|
|
86
|
+
key="deny",
|
|
87
|
+
label=_("Deny"),
|
|
88
|
+
action_label=_("Denial"),
|
|
89
|
+
description_fields=_(
|
|
90
|
+
"<p>Mail: {{_email_contact.address}}</p><p>Mailing list: {{_mailing_list.title}}</p>"
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
def deny(self, by=None, description=None, **kwargs):
|
|
96
|
+
if profile := getattr(by, "profile", None):
|
|
97
|
+
self.approver = profile
|
|
98
|
+
if description:
|
|
99
|
+
self.reason = description
|
|
100
|
+
|
|
101
|
+
email_contact = models.ForeignKey(
|
|
102
|
+
"directory.EmailContact",
|
|
103
|
+
related_name="change_requests",
|
|
104
|
+
on_delete=models.CASCADE,
|
|
105
|
+
verbose_name=_("Subscriber"),
|
|
106
|
+
)
|
|
107
|
+
mailing_list = models.ForeignKey(
|
|
108
|
+
"MailingList", related_name="change_requests", on_delete=models.CASCADE, verbose_name=_("Mailing List")
|
|
109
|
+
)
|
|
110
|
+
relationship = models.ForeignKey(
|
|
111
|
+
"wbmailing.MailingListEmailContactThroughModel", on_delete=models.CASCADE, related_name="requests"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
requester = models.ForeignKey(
|
|
115
|
+
"directory.Person", null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_("Requester")
|
|
116
|
+
)
|
|
117
|
+
approver = models.ForeignKey(
|
|
118
|
+
"directory.Person",
|
|
119
|
+
null=True,
|
|
120
|
+
blank=True,
|
|
121
|
+
on_delete=models.SET_NULL,
|
|
122
|
+
related_name="approved_requests",
|
|
123
|
+
verbose_name=_("Approver"),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
expiration_date = models.DateField(
|
|
127
|
+
null=True,
|
|
128
|
+
blank=True,
|
|
129
|
+
verbose_name=_("Expiration Date"),
|
|
130
|
+
help_text=_(
|
|
131
|
+
"If set, this email will be removed automatically from the mailing list after the set expiration time"
|
|
132
|
+
),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
reason = models.TextField(blank=True, null=True, verbose_name=_("Reason"))
|
|
136
|
+
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
|
|
137
|
+
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
|
|
138
|
+
|
|
139
|
+
class Meta:
|
|
140
|
+
verbose_name = _("Mailing List Subscriber Change Request")
|
|
141
|
+
verbose_name_plural = _("Mailing List Subscriber Change Requests")
|
|
142
|
+
permissions = (
|
|
143
|
+
(
|
|
144
|
+
"administrate_mailinglistsubscriberchangerequest",
|
|
145
|
+
"Can Administrate Mailing List Subscriber Change Requests",
|
|
146
|
+
),
|
|
147
|
+
)
|
|
148
|
+
constraints = [
|
|
149
|
+
models.UniqueConstraint(
|
|
150
|
+
fields=["mailing_list", "email_contact"],
|
|
151
|
+
condition=models.Q(status="PENDING"),
|
|
152
|
+
name="unique_pending_request",
|
|
153
|
+
)
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
notification_types = [
|
|
157
|
+
create_notification_type(
|
|
158
|
+
code="wbmailing.mailinglistsubscriberchangerequest.notify",
|
|
159
|
+
title="Subscriber Notification",
|
|
160
|
+
help_text="Sends out a notification when a recipient subscribes or unsubscribes",
|
|
161
|
+
)
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
def save(self, **kwargs):
|
|
165
|
+
if not hasattr(self, "relationship"):
|
|
166
|
+
self.relationship = MailingListEmailContactThroughModel.objects.get_or_create(
|
|
167
|
+
mailing_list=self.mailing_list, email_contact=self.email_contact
|
|
168
|
+
)[0]
|
|
169
|
+
if not self.type:
|
|
170
|
+
self.type = (
|
|
171
|
+
self.Type.SUBSCRIBING
|
|
172
|
+
if self.relationship.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
|
|
173
|
+
else self.Type.UNSUBSCRIBING
|
|
174
|
+
)
|
|
175
|
+
if self.status == MailingListSubscriberChangeRequest.Status.PENDING:
|
|
176
|
+
if self.mailing_list.is_public or (
|
|
177
|
+
(user := getattr(self.requester, "user_account", None)) and can_administrate_change_request(self, user)
|
|
178
|
+
):
|
|
179
|
+
if self.approver is None:
|
|
180
|
+
self.approver = self.requester
|
|
181
|
+
self.approve(description=gettext("Automatically approved.") if not self.reason else self.reason)
|
|
182
|
+
|
|
183
|
+
super().save(**kwargs)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def subscribing(self) -> bool:
|
|
187
|
+
"""
|
|
188
|
+
True if the state is unsubscribed and the change will subscribe it
|
|
189
|
+
"""
|
|
190
|
+
return (
|
|
191
|
+
self.relationship.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED
|
|
192
|
+
and self.type == self.Type.SUBSCRIBING
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def __str__(self) -> str:
|
|
196
|
+
return f"{self.type} {self.email_contact.address} {self.mailing_list.title}"
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def get_endpoint_basename(cls) -> str:
|
|
200
|
+
return "wbmailing:mailinglistsubscriberchangerequest"
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def get_representation_value_key(cls) -> str:
|
|
204
|
+
return "id"
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def get_representation_label_key(cls) -> str:
|
|
208
|
+
return "{{email_contact__address}} to {{mailing_list__title}}"
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def get_approvers(cls):
|
|
212
|
+
return (
|
|
213
|
+
get_user_model()
|
|
214
|
+
.objects.filter(
|
|
215
|
+
models.Q(groups__permissions__codename="administrate_mailinglistsubscriberchangerequest")
|
|
216
|
+
| models.Q(user_permissions__codename="administrate_mailinglistsubscriberchangerequest")
|
|
217
|
+
)
|
|
218
|
+
.distinct()
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class MailingListEmailContactThroughModel(models.Model):
|
|
223
|
+
class Status(models.TextChoices):
|
|
224
|
+
SUBSCRIBED = "SUBSCRIBED", _("Subscribed")
|
|
225
|
+
UNSUBSCRIBED = "UNSUBSCRIBED", _("Unsubscribed")
|
|
226
|
+
|
|
227
|
+
mailing_list = models.ForeignKey(
|
|
228
|
+
"wbmailing.MailingList", on_delete=models.CASCADE, related_name="through_mailinglists"
|
|
229
|
+
)
|
|
230
|
+
email_contact = models.ForeignKey(
|
|
231
|
+
"directory.EmailContact", on_delete=models.CASCADE, related_name="through_mailinglists"
|
|
232
|
+
)
|
|
233
|
+
status = models.CharField(
|
|
234
|
+
max_length=32, default=Status.UNSUBSCRIBED, choices=Status.choices, verbose_name=_("Status")
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
class Meta:
|
|
238
|
+
unique_together = ("mailing_list", "email_contact")
|
|
239
|
+
|
|
240
|
+
def change_state(self, automatically_approve: bool = False, **kwargs):
|
|
241
|
+
"""
|
|
242
|
+
When called, change the state of the relationship from subscribe to unsubscribe or unsubscribe to subscribe
|
|
243
|
+
Args:
|
|
244
|
+
reason: Text field explaining the reason
|
|
245
|
+
requester: The subscription change state requester
|
|
246
|
+
automatically_approve: True if the change request needs to be automatically approved.
|
|
247
|
+
"""
|
|
248
|
+
request = MailingListSubscriberChangeRequest.objects.get_or_create(
|
|
249
|
+
email_contact=self.email_contact,
|
|
250
|
+
mailing_list=self.mailing_list,
|
|
251
|
+
status=MailingListSubscriberChangeRequest.Status.PENDING,
|
|
252
|
+
defaults={
|
|
253
|
+
"relationship": self,
|
|
254
|
+
"type": MailingListSubscriberChangeRequest.Type.SUBSCRIBING
|
|
255
|
+
if self.status == self.Status.UNSUBSCRIBED
|
|
256
|
+
else MailingListSubscriberChangeRequest.Type.UNSUBSCRIBING,
|
|
257
|
+
**kwargs,
|
|
258
|
+
},
|
|
259
|
+
)[0]
|
|
260
|
+
if automatically_approve and request.status == MailingListSubscriberChangeRequest.Status.PENDING:
|
|
261
|
+
request.approve()
|
|
262
|
+
request.save()
|
|
263
|
+
|
|
264
|
+
@classmethod
|
|
265
|
+
def get_expired_date_subquery(
|
|
266
|
+
cls, mailing_list_label_field: str = "mailing_list", email_contact_label_field: str = "email_contact"
|
|
267
|
+
) -> Subquery:
|
|
268
|
+
return Subquery(
|
|
269
|
+
MailingListSubscriberChangeRequest.objects.filter(
|
|
270
|
+
mailing_list=OuterRef(mailing_list_label_field),
|
|
271
|
+
email_contact=OuterRef(email_contact_label_field),
|
|
272
|
+
status=MailingListSubscriberChangeRequest.Status.APPROVED,
|
|
273
|
+
type=MailingListSubscriberChangeRequest.Type.SUBSCRIBING,
|
|
274
|
+
)
|
|
275
|
+
.order_by("-created")
|
|
276
|
+
.values("expiration_date")[:1],
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
@classmethod
|
|
280
|
+
def get_endpoint_basename(cls) -> str:
|
|
281
|
+
return "wbmailing:mailinglistemailcontact"
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class MailingList(WBModel):
|
|
285
|
+
class Meta:
|
|
286
|
+
verbose_name = _("Mailing List")
|
|
287
|
+
verbose_name_plural = _("Mailing Lists")
|
|
288
|
+
|
|
289
|
+
title = models.CharField(max_length=255, verbose_name=_("Title"))
|
|
290
|
+
is_public = models.BooleanField(
|
|
291
|
+
default=False, verbose_name=_("Public"), help_text=_("If true, the factsheet is automatically subscribable")
|
|
292
|
+
)
|
|
293
|
+
email_contacts = models.ManyToManyField(
|
|
294
|
+
"directory.EmailContact",
|
|
295
|
+
through=MailingListEmailContactThroughModel,
|
|
296
|
+
related_name="mailing_lists",
|
|
297
|
+
blank=True,
|
|
298
|
+
verbose_name=_("Subcribers"),
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
def __str__(self) -> str:
|
|
302
|
+
return self.title
|
|
303
|
+
|
|
304
|
+
def unsubscribe(self, email_contact: EmailContact, **kwargs):
|
|
305
|
+
"""
|
|
306
|
+
Wrapper around the corresponding method in MailingListEmailContactThroughModel. Keyword argument matches the underlying signature
|
|
307
|
+
"""
|
|
308
|
+
rel = MailingListEmailContactThroughModel.objects.get_or_create(
|
|
309
|
+
email_contact=email_contact, mailing_list=self
|
|
310
|
+
)[0]
|
|
311
|
+
if rel.status == MailingListEmailContactThroughModel.Status.SUBSCRIBED:
|
|
312
|
+
rel.change_state(**kwargs)
|
|
313
|
+
|
|
314
|
+
def subscribe(self, email_contact: EmailContact, **kwargs):
|
|
315
|
+
"""
|
|
316
|
+
Wrapper around the corresponding method in MailingListEmailContactThroughModel. Keyword argument matches the underlying signature
|
|
317
|
+
"""
|
|
318
|
+
rel = MailingListEmailContactThroughModel.objects.get_or_create(
|
|
319
|
+
email_contact=email_contact, mailing_list=self
|
|
320
|
+
)[0]
|
|
321
|
+
if rel.status == MailingListEmailContactThroughModel.Status.UNSUBSCRIBED:
|
|
322
|
+
rel.change_state(**kwargs)
|
|
323
|
+
|
|
324
|
+
@classmethod
|
|
325
|
+
def get_subscribed_mailing_lists(cls, email_contact):
|
|
326
|
+
return cls.objects.annotate(
|
|
327
|
+
is_subscribe=Exists(
|
|
328
|
+
MailingListEmailContactThroughModel.objects.filter(
|
|
329
|
+
mailing_list=OuterRef("id"),
|
|
330
|
+
email_contact=email_contact,
|
|
331
|
+
status=MailingListEmailContactThroughModel.Status.SUBSCRIBED,
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
).filter(is_subscribe=True)
|
|
335
|
+
|
|
336
|
+
@classmethod
|
|
337
|
+
def get_endpoint_basename(cls) -> str:
|
|
338
|
+
return "wbmailing:mailinglist"
|
|
339
|
+
|
|
340
|
+
@classmethod
|
|
341
|
+
def get_representation_endpoint(cls) -> str:
|
|
342
|
+
return "wbmailing:mailinglistrepresentation-list"
|
|
343
|
+
|
|
344
|
+
@classmethod
|
|
345
|
+
def get_representation_value_key(cls) -> str:
|
|
346
|
+
return "id"
|
|
347
|
+
|
|
348
|
+
@classmethod
|
|
349
|
+
def get_representation_label_key(cls) -> str:
|
|
350
|
+
return "{{title}}"
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
@receiver(post_save, sender=MailingListSubscriberChangeRequest)
|
|
354
|
+
def post_save_mailing_request(sender, instance, created, **kwargs):
|
|
355
|
+
"""
|
|
356
|
+
MailingListSubscriberChangeRequest post_save signal: Send the notification email if needed
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
if created and instance.status == MailingListSubscriberChangeRequest.Status.PENDING.name:
|
|
360
|
+
for user in MailingListSubscriberChangeRequest.get_approvers():
|
|
361
|
+
entry_name = instance.email_contact.address
|
|
362
|
+
if instance.email_contact.entry:
|
|
363
|
+
entry_name += f" ({instance.email_contact.entry.computed_str})"
|
|
364
|
+
|
|
365
|
+
send_notification(
|
|
366
|
+
code="wbmailing.mailinglistsubscriberchangerequest.notify",
|
|
367
|
+
title=_("New in Mailing Subscription Request Change for {}").format(entry_name),
|
|
368
|
+
body=_("User requested to {} {} to the mailing list {}").format(
|
|
369
|
+
instance.type, entry_name, instance.mailing_list.title
|
|
370
|
+
),
|
|
371
|
+
user=user,
|
|
372
|
+
reverse_name="wbmailing:mailinglistsubscriberchangerequest-detail",
|
|
373
|
+
reverse_args=[instance.id],
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@receiver(deactivate_profile)
|
|
378
|
+
@receiver(post_delete, sender="directory.Entry")
|
|
379
|
+
@receiver(post_delete, sender="directory.Person")
|
|
380
|
+
@receiver(post_delete, sender="directory.Company")
|
|
381
|
+
def handle_user_deactivation(sender, instance, substitute_profile=None, **kwargs):
|
|
382
|
+
for email_contact in EmailContact.objects.filter(entry_id=instance.id):
|
|
383
|
+
for rel in MailingListEmailContactThroughModel.objects.filter(
|
|
384
|
+
email_contact=email_contact, status=MailingListEmailContactThroughModel.Status.SUBSCRIBED
|
|
385
|
+
):
|
|
386
|
+
rel.change_state(reason=gettext("User's deactivation"), automatically_approve=True)
|