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,19 @@
|
|
|
1
|
+
from .mailing_lists import (
|
|
2
|
+
MailingListEmailContactThroughModelModelSerializer,
|
|
3
|
+
MailingListEntryRepresentationSerializer,
|
|
4
|
+
MailingListListSerializer,
|
|
5
|
+
MailingListModelSerializer,
|
|
6
|
+
MailingListRepresentationSerializer,
|
|
7
|
+
MailingListSubscriberChangeRequestModelSerializer,
|
|
8
|
+
)
|
|
9
|
+
from .mails import (
|
|
10
|
+
MailEventModelSerializer,
|
|
11
|
+
MailModelSerializer,
|
|
12
|
+
MailRepresentationSerializer,
|
|
13
|
+
MailStatusMassMailModelSerializer,
|
|
14
|
+
MailTemplateModelSerializer,
|
|
15
|
+
MailTemplateRepresentationSerializer,
|
|
16
|
+
MassMailListSerializer,
|
|
17
|
+
MassMailModelSerializer,
|
|
18
|
+
MassMailRepresentationSerializer,
|
|
19
|
+
)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from django.dispatch import receiver
|
|
2
|
+
from django.utils.translation import gettext
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
4
|
+
from rest_framework import serializers
|
|
5
|
+
from rest_framework.reverse import reverse
|
|
6
|
+
from wbcore import serializers as wb_serializers
|
|
7
|
+
from wbcore.contrib.directory.serializers import (
|
|
8
|
+
CompanyModelSerializer,
|
|
9
|
+
EmailContactRepresentationSerializer,
|
|
10
|
+
EntryModelSerializer,
|
|
11
|
+
PersonModelSerializer,
|
|
12
|
+
PersonRepresentationSerializer,
|
|
13
|
+
)
|
|
14
|
+
from wbcore.signals.serializers import add_instance_additional_resource
|
|
15
|
+
from wbmailing import models
|
|
16
|
+
from wbmailing.models import MailingListEmailContactThroughModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MailingListRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
20
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbmailing:mailinglist-detail")
|
|
21
|
+
|
|
22
|
+
class Meta:
|
|
23
|
+
model = models.MailingList
|
|
24
|
+
fields = ("id", "title", "_detail")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MailingListEntryRepresentationSerializer(MailingListRepresentationSerializer):
|
|
28
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbmailing:mailinglist-detail")
|
|
29
|
+
|
|
30
|
+
def get_filter_params(self, request):
|
|
31
|
+
entry_id = request.parser_context["view"].kwargs.get("entry_id", None)
|
|
32
|
+
return {"negative_entry": entry_id}
|
|
33
|
+
|
|
34
|
+
class Meta:
|
|
35
|
+
model = models.MailingList
|
|
36
|
+
fields = ("id", "title", "_detail")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class MailingListListSerializer(wb_serializers.ModelSerializer):
|
|
40
|
+
nb_subscribers = wb_serializers.IntegerField(read_only=True, label=_("Number of Subscribers"), default=0)
|
|
41
|
+
|
|
42
|
+
class Meta:
|
|
43
|
+
model = models.MailingList
|
|
44
|
+
fields = (
|
|
45
|
+
"id",
|
|
46
|
+
"title",
|
|
47
|
+
"is_public",
|
|
48
|
+
"nb_subscribers",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class MailingListModelSerializer(wb_serializers.ModelSerializer):
|
|
53
|
+
nb_subscribers = wb_serializers.IntegerField(read_only=True, label=_("Number of Subscribers"), default=0)
|
|
54
|
+
|
|
55
|
+
@wb_serializers.register_resource()
|
|
56
|
+
def email_contacts(self, instance, request, user):
|
|
57
|
+
# Do some something (checks, etc.)
|
|
58
|
+
return {
|
|
59
|
+
"mailevent_chart": reverse(
|
|
60
|
+
"wbmailing:mailing_list-maileventchart-list", args=[instance.id], request=request
|
|
61
|
+
),
|
|
62
|
+
"email_contacts": reverse(
|
|
63
|
+
"wbmailing:mailing_list-email_contacts-list", args=[instance.id], request=request
|
|
64
|
+
),
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
class Meta:
|
|
68
|
+
model = models.MailingList
|
|
69
|
+
fields = ("id", "title", "is_public", "nb_subscribers", "_additional_resources")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class MailingListEmailContactThroughModelModelSerializer(wb_serializers.ModelSerializer):
|
|
73
|
+
_email_contact = EmailContactRepresentationSerializer(source="email_contact")
|
|
74
|
+
_mailing_list = MailingListRepresentationSerializer(source="mailing_list")
|
|
75
|
+
|
|
76
|
+
in_charge = wb_serializers.CharField(read_only=True, label=_("Relationship Managers"))
|
|
77
|
+
expiration_date = wb_serializers.DateField(read_only=True, label=_("Expiration Date"))
|
|
78
|
+
is_public = wb_serializers.BooleanField(read_only=True, label=_("Public Mailing list"))
|
|
79
|
+
is_pending_request_change = wb_serializers.BooleanField(
|
|
80
|
+
read_only=True,
|
|
81
|
+
default=False,
|
|
82
|
+
label=_("Pending change request exists"),
|
|
83
|
+
help_text=_("If true, a pending change request exists for this email and mailing list"),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
@wb_serializers.register_resource()
|
|
87
|
+
def delete_from_mailinglist(self, instance, request, user):
|
|
88
|
+
res = {
|
|
89
|
+
"requests": f'{reverse("wbmailing:mailinglistsubscriberchangerequest-list", args=[], request=request)}?email_contact={instance.email_contact.id}&mailing_list={instance.mailing_list.id}'
|
|
90
|
+
}
|
|
91
|
+
if getattr(instance, "expiration_date", None):
|
|
92
|
+
res["remove_expiration_date"] = reverse(
|
|
93
|
+
"wbmailing:mailinglistemailcontact-removeexpirationdate",
|
|
94
|
+
args=[instance.id],
|
|
95
|
+
request=request,
|
|
96
|
+
)
|
|
97
|
+
if instance.status != MailingListEmailContactThroughModel.Status.SUBSCRIBED:
|
|
98
|
+
res["delete_from_mailinglist"] = reverse(
|
|
99
|
+
"wbmailing:mailinglistemailcontact-delete",
|
|
100
|
+
args=[instance.id],
|
|
101
|
+
request=request,
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
res["unsubscribe"] = reverse(
|
|
105
|
+
"wbmailing:mailinglistemailcontact-unsubscribe",
|
|
106
|
+
args=[instance.id],
|
|
107
|
+
request=request,
|
|
108
|
+
)
|
|
109
|
+
return res
|
|
110
|
+
|
|
111
|
+
class Meta:
|
|
112
|
+
model = MailingListEmailContactThroughModel
|
|
113
|
+
fields = (
|
|
114
|
+
"id",
|
|
115
|
+
"status",
|
|
116
|
+
"email_contact",
|
|
117
|
+
"mailing_list",
|
|
118
|
+
"_email_contact",
|
|
119
|
+
"_mailing_list",
|
|
120
|
+
"in_charge",
|
|
121
|
+
"expiration_date",
|
|
122
|
+
"is_public",
|
|
123
|
+
"is_pending_request_change",
|
|
124
|
+
"_additional_resources",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class MailingListSubscriberChangeRequestModelSerializer(wb_serializers.ModelSerializer):
|
|
129
|
+
_email_contact = EmailContactRepresentationSerializer(many=False, source="email_contact")
|
|
130
|
+
_mailing_list = MailingListRepresentationSerializer(many=False, source="mailing_list")
|
|
131
|
+
_requester = PersonRepresentationSerializer(source="requester", many=False)
|
|
132
|
+
_approver = PersonRepresentationSerializer(source="approver", many=False)
|
|
133
|
+
|
|
134
|
+
approver = wb_serializers.PrimaryKeyRelatedField(read_only=True, label=_("Approver"))
|
|
135
|
+
requester = wb_serializers.PrimaryKeyRelatedField(read_only=True, label=_("Requester"))
|
|
136
|
+
created = wb_serializers.DateTimeField(read_only=True, label=_("Created"))
|
|
137
|
+
updated = wb_serializers.DateTimeField(read_only=True, label=_("Updated"))
|
|
138
|
+
entry_repr = wb_serializers.CharField(read_only=True)
|
|
139
|
+
type = wb_serializers.ChoiceField(choices=models.MailingListSubscriberChangeRequest.Type.choices, required=False)
|
|
140
|
+
|
|
141
|
+
def validate(self, attrs):
|
|
142
|
+
instance_id = self.instance.id if self.instance else None
|
|
143
|
+
email_contact = attrs.get("email_contact", self.instance.email_contact if self.instance else None)
|
|
144
|
+
mailing_list = attrs.get("mailing_list", self.instance.mailing_list if self.instance else None)
|
|
145
|
+
if email_contact and mailing_list:
|
|
146
|
+
if (
|
|
147
|
+
models.MailingListSubscriberChangeRequest.objects.exclude(id=instance_id)
|
|
148
|
+
.filter(
|
|
149
|
+
email_contact=email_contact,
|
|
150
|
+
mailing_list=mailing_list,
|
|
151
|
+
status=models.MailingListSubscriberChangeRequest.Status.PENDING.name,
|
|
152
|
+
)
|
|
153
|
+
.count()
|
|
154
|
+
> 0
|
|
155
|
+
):
|
|
156
|
+
raise serializers.ValidationError(
|
|
157
|
+
{
|
|
158
|
+
"non_field_errors": gettext("There is already a pending request to subscribe {} to {}").format(
|
|
159
|
+
email_contact.address, mailing_list.title
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
if not email_contact:
|
|
164
|
+
raise serializers.ValidationError(
|
|
165
|
+
{"email_contact": gettext("Email contact is missing for this request to be valid")}
|
|
166
|
+
)
|
|
167
|
+
return super().validate(attrs)
|
|
168
|
+
|
|
169
|
+
def create(self, validated_data):
|
|
170
|
+
if request := self.context.get("request"):
|
|
171
|
+
validated_data["requester"] = request.user.profile
|
|
172
|
+
return super().create(validated_data)
|
|
173
|
+
|
|
174
|
+
class Meta:
|
|
175
|
+
model = models.MailingListSubscriberChangeRequest
|
|
176
|
+
fields = (
|
|
177
|
+
"id",
|
|
178
|
+
"status",
|
|
179
|
+
"email_contact",
|
|
180
|
+
"_email_contact",
|
|
181
|
+
"email_contact",
|
|
182
|
+
"mailing_list",
|
|
183
|
+
"_mailing_list",
|
|
184
|
+
"expiration_date",
|
|
185
|
+
"type",
|
|
186
|
+
"created",
|
|
187
|
+
"updated",
|
|
188
|
+
"requester",
|
|
189
|
+
"_requester",
|
|
190
|
+
"approver",
|
|
191
|
+
"_approver",
|
|
192
|
+
"reason",
|
|
193
|
+
"entry_repr",
|
|
194
|
+
"_additional_resources",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@receiver(add_instance_additional_resource, sender=CompanyModelSerializer)
|
|
199
|
+
@receiver(add_instance_additional_resource, sender=PersonModelSerializer)
|
|
200
|
+
@receiver(add_instance_additional_resource, sender=EntryModelSerializer)
|
|
201
|
+
def crm_adding_additional_resource(sender, serializer, instance, request, user, **kwargs):
|
|
202
|
+
return {
|
|
203
|
+
"mailinglist": reverse("wbmailing:entry-mailinglist-list", args=[instance.id], request=request),
|
|
204
|
+
"mailinglistsubscriptionrequests": reverse(
|
|
205
|
+
"wbmailing:entry-mailinglistsubscriberchangerequest-list",
|
|
206
|
+
args=[instance.id],
|
|
207
|
+
request=request,
|
|
208
|
+
),
|
|
209
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
from datetime import timedelta
|
|
2
|
+
|
|
3
|
+
from django.utils import timezone
|
|
4
|
+
from django.utils.translation import gettext
|
|
5
|
+
from django.utils.translation import gettext_lazy as _
|
|
6
|
+
from dynamic_preferences.registries import global_preferences_registry
|
|
7
|
+
from rest_framework import serializers
|
|
8
|
+
from rest_framework.reverse import reverse
|
|
9
|
+
from wbcore import serializers as wb_serializers
|
|
10
|
+
from wbcore.contrib.directory.models import EmailContact
|
|
11
|
+
from wbcore.contrib.directory.serializers import (
|
|
12
|
+
EmailContactRepresentationSerializer,
|
|
13
|
+
EntryRepresentationSerializer,
|
|
14
|
+
PersonRepresentationSerializer,
|
|
15
|
+
)
|
|
16
|
+
from wbmailing import models
|
|
17
|
+
|
|
18
|
+
from .mailing_lists import MailingListRepresentationSerializer
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MailRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
22
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbmailing:mail-detail")
|
|
23
|
+
|
|
24
|
+
class Meta:
|
|
25
|
+
model = models.Mail
|
|
26
|
+
fields = ("id", "subject", "_detail")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MassMailRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
30
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbmailing:massmail-detail")
|
|
31
|
+
|
|
32
|
+
class Meta:
|
|
33
|
+
model = models.MassMail
|
|
34
|
+
fields = ("id", "subject", "_detail")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class MailTemplateRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
38
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbmailing:mailtemplate-detail")
|
|
39
|
+
|
|
40
|
+
class Meta:
|
|
41
|
+
model = models.MailTemplate
|
|
42
|
+
fields = ("id", "title", "_detail")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MassMailListSerializer(wb_serializers.ModelSerializer):
|
|
46
|
+
_creator = PersonRepresentationSerializer(source="creator")
|
|
47
|
+
_mailing_lists = MailingListRepresentationSerializer(label=_("Mailing List"), source="mailing_lists", many=True)
|
|
48
|
+
_excluded_mailing_lists = MailingListRepresentationSerializer(
|
|
49
|
+
label=_("Excluded Mailing List"), source="excluded_mailing_lists", many=True
|
|
50
|
+
)
|
|
51
|
+
_template = MailTemplateRepresentationSerializer(source="template")
|
|
52
|
+
subject = wb_serializers.CharField(required=True, label=_("Subject"))
|
|
53
|
+
|
|
54
|
+
class Meta:
|
|
55
|
+
model = models.MassMail
|
|
56
|
+
fields = (
|
|
57
|
+
"id",
|
|
58
|
+
"status",
|
|
59
|
+
"mailing_lists",
|
|
60
|
+
"_mailing_lists",
|
|
61
|
+
"excluded_mailing_lists",
|
|
62
|
+
"_excluded_mailing_lists",
|
|
63
|
+
"from_email",
|
|
64
|
+
"template",
|
|
65
|
+
"_template",
|
|
66
|
+
"subject",
|
|
67
|
+
"created",
|
|
68
|
+
"creator",
|
|
69
|
+
"_creator",
|
|
70
|
+
"send_at",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class MassMailModelSerializer(MassMailListSerializer):
|
|
75
|
+
from_email = wb_serializers.CharField(
|
|
76
|
+
default=lambda: global_preferences_registry.manager()["wbmailing__default_source_mail"], label=_("From")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
@wb_serializers.register_resource()
|
|
80
|
+
def send_test_mail(self, instance, request, user):
|
|
81
|
+
return {
|
|
82
|
+
"send_test_mail": reverse(
|
|
83
|
+
"wbmailing:massmail-sendtestmail",
|
|
84
|
+
args=[instance.id],
|
|
85
|
+
request=request,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@wb_serializers.register_resource()
|
|
90
|
+
def mails(self, instance, request, user):
|
|
91
|
+
return {
|
|
92
|
+
"mails": reverse(
|
|
93
|
+
"wbmailing:massmail-mailstatus-list",
|
|
94
|
+
args=[instance.id],
|
|
95
|
+
request=request,
|
|
96
|
+
),
|
|
97
|
+
"events": reverse(
|
|
98
|
+
"wbmailing:massmail-mailevent-list",
|
|
99
|
+
args=[instance.id],
|
|
100
|
+
request=request,
|
|
101
|
+
),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@wb_serializers.register_resource()
|
|
105
|
+
def analytics(self, instance, request, user):
|
|
106
|
+
return {
|
|
107
|
+
"mailstatus_barchart": reverse(
|
|
108
|
+
"wbmailing:massmail-mailstatusbarchart-list", args=[instance.id], request=request
|
|
109
|
+
),
|
|
110
|
+
"mailclick_barchart": reverse(
|
|
111
|
+
"wbmailing:massmail-mailclickbarchart-list", args=[instance.id], request=request
|
|
112
|
+
),
|
|
113
|
+
"clients_barchart": reverse(
|
|
114
|
+
"wbmailing:massmail-clientsbarchart-list", args=[instance.id], request=request
|
|
115
|
+
),
|
|
116
|
+
"country_barchart": reverse(
|
|
117
|
+
"wbmailing:massmail-countrybarchart-list", args=[instance.id], request=request
|
|
118
|
+
),
|
|
119
|
+
"region_barchart": reverse("wbmailing:massmail-regionbarchart-list", args=[instance.id], request=request),
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def create(self, validated_data, *args, **kwargs):
|
|
123
|
+
if request := self.context.get("request"):
|
|
124
|
+
validated_data["creator"] = request.user.profile
|
|
125
|
+
return super().create(validated_data, *args, **kwargs)
|
|
126
|
+
|
|
127
|
+
class Meta:
|
|
128
|
+
model = models.MassMail
|
|
129
|
+
fields = (
|
|
130
|
+
"id",
|
|
131
|
+
"status",
|
|
132
|
+
"mailing_lists",
|
|
133
|
+
"_mailing_lists",
|
|
134
|
+
"excluded_mailing_lists",
|
|
135
|
+
"_excluded_mailing_lists",
|
|
136
|
+
"from_email",
|
|
137
|
+
"template",
|
|
138
|
+
"_template",
|
|
139
|
+
"subject",
|
|
140
|
+
"created",
|
|
141
|
+
"body",
|
|
142
|
+
"creator",
|
|
143
|
+
"_creator",
|
|
144
|
+
"send_at",
|
|
145
|
+
"attachment_url",
|
|
146
|
+
"_additional_resources",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def validate(self, data):
|
|
150
|
+
send_at = data.get("send_at", None)
|
|
151
|
+
if send_at:
|
|
152
|
+
if send_at < timezone.now() - timedelta(minutes=1):
|
|
153
|
+
raise serializers.ValidationError(
|
|
154
|
+
{"non_field_errors": gettext("Send time shouldn't be earlier than now.")}
|
|
155
|
+
)
|
|
156
|
+
return super().validate(data)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class MailModelSerializer(wb_serializers.ModelSerializer):
|
|
160
|
+
from_email = wb_serializers.CharField(
|
|
161
|
+
default=wb_serializers.CurrentUserDefault(user_attr="email"), label=_("From")
|
|
162
|
+
)
|
|
163
|
+
created = wb_serializers.DateTimeField(default=lambda: timezone.now(), label=_("Created"))
|
|
164
|
+
_mass_mail = MassMailRepresentationSerializer(many=False, source="mass_mail")
|
|
165
|
+
_template = MailTemplateRepresentationSerializer(many=False, source="template")
|
|
166
|
+
_to_email = EmailContactRepresentationSerializer(many=True, source="to_email")
|
|
167
|
+
_cc_email = EmailContactRepresentationSerializer(many=True, source="cc_email")
|
|
168
|
+
_bcc_email = EmailContactRepresentationSerializer(many=True, source="bcc_email")
|
|
169
|
+
|
|
170
|
+
status = wb_serializers.ChoiceField(
|
|
171
|
+
choices=models.MailEvent.EventType.choices, default=models.MailEvent.EventType.UNKNOWN, read_only=True
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
@wb_serializers.register_resource()
|
|
175
|
+
def mail_event(self, instance, request, user):
|
|
176
|
+
return {
|
|
177
|
+
"mailevent": reverse(
|
|
178
|
+
"wbmailing:mail-mailevent-list",
|
|
179
|
+
args=[instance.id],
|
|
180
|
+
request=request,
|
|
181
|
+
),
|
|
182
|
+
"resend_mail": reverse(
|
|
183
|
+
"wbmailing:mail-resend",
|
|
184
|
+
args=[instance.id],
|
|
185
|
+
request=request,
|
|
186
|
+
),
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
class Meta:
|
|
190
|
+
model = models.Mail
|
|
191
|
+
fields = (
|
|
192
|
+
"id",
|
|
193
|
+
"created",
|
|
194
|
+
"last_send",
|
|
195
|
+
"template",
|
|
196
|
+
"_template",
|
|
197
|
+
"message_ids",
|
|
198
|
+
"mass_mail",
|
|
199
|
+
"_mass_mail",
|
|
200
|
+
"from_email",
|
|
201
|
+
"to_email",
|
|
202
|
+
"_to_email",
|
|
203
|
+
"cc_email",
|
|
204
|
+
"_cc_email",
|
|
205
|
+
"bcc_email",
|
|
206
|
+
"_bcc_email",
|
|
207
|
+
"subject",
|
|
208
|
+
"body",
|
|
209
|
+
"status",
|
|
210
|
+
"_additional_resources",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class MailStatusMassMailModelSerializer(wb_serializers.ModelSerializer):
|
|
215
|
+
mail_id = wb_serializers.CharField(read_only=True)
|
|
216
|
+
_entry = EntryRepresentationSerializer(source="entry")
|
|
217
|
+
status = wb_serializers.ChoiceField(
|
|
218
|
+
choices=(*models.MailEvent.EventType.choices, ("NOT_SENT", gettext("Not Sent"))),
|
|
219
|
+
default="NOT_SENT",
|
|
220
|
+
read_only=True,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
class Meta:
|
|
224
|
+
model = EmailContact
|
|
225
|
+
fields = ("id", "entry", "_entry", "address", "status", "mail_id")
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class MailTemplateModelSerializer(wb_serializers.ModelSerializer):
|
|
229
|
+
class Meta:
|
|
230
|
+
model = models.MailTemplate
|
|
231
|
+
fields = ("id", "title", "template")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class MailEventModelSerializer(wb_serializers.ModelSerializer):
|
|
235
|
+
_mail = MailRepresentationSerializer(source="mail")
|
|
236
|
+
|
|
237
|
+
class Meta:
|
|
238
|
+
model = models.MailEvent
|
|
239
|
+
fields = (
|
|
240
|
+
"id",
|
|
241
|
+
"mail",
|
|
242
|
+
"_mail",
|
|
243
|
+
"timestamp",
|
|
244
|
+
"event_type",
|
|
245
|
+
"reject_reason",
|
|
246
|
+
"description",
|
|
247
|
+
"recipient",
|
|
248
|
+
"click_url",
|
|
249
|
+
"ip",
|
|
250
|
+
"user_agent",
|
|
251
|
+
)
|
wbmailing/tasks.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import absolute_import, unicode_literals
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from celery import shared_task
|
|
6
|
+
from django.db.models import Q
|
|
7
|
+
from django.utils import timezone
|
|
8
|
+
from wbmailing.models import (
|
|
9
|
+
MailingListEmailContactThroughModel,
|
|
10
|
+
MailingListSubscriberChangeRequest,
|
|
11
|
+
MassMail,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@shared_task
|
|
16
|
+
def check_and_remove_expired_mailinglist_subscription(date=None):
|
|
17
|
+
"""
|
|
18
|
+
Shared tasks to expire contact in MailingList.
|
|
19
|
+
"""
|
|
20
|
+
if not date:
|
|
21
|
+
date = timezone.now().date()
|
|
22
|
+
for request in MailingListSubscriberChangeRequest.objects.filter(
|
|
23
|
+
relationship__status=MailingListEmailContactThroughModel.Status.SUBSCRIBED,
|
|
24
|
+
expiration_date__isnull=False,
|
|
25
|
+
expiration_date__lte=date,
|
|
26
|
+
).all():
|
|
27
|
+
request.relationship.change_state(automatically_approve=True, reason="Expired mailing list subscription")
|
|
28
|
+
request.expiration_date = None
|
|
29
|
+
request.save()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@shared_task
|
|
33
|
+
def periodic_send_mass_mail_as_tasks():
|
|
34
|
+
mass_mails = MassMail.objects.filter(Q(status=MassMail.Status.SEND_LATER) & Q(send_at__lte=datetime.now()))
|
|
35
|
+
for mass_mail in mass_mails:
|
|
36
|
+
mass_mail.send()
|
|
37
|
+
mass_mail.save()
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from django import template
|
|
2
|
+
from django.utils.html import strip_tags
|
|
3
|
+
|
|
4
|
+
register = template.Library()
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@register.filter
|
|
8
|
+
def stripAndsplit(string, sep):
|
|
9
|
+
"""Return the string split by sep.
|
|
10
|
+
|
|
11
|
+
Example usage: {{ value|split:"/" }}
|
|
12
|
+
"""
|
|
13
|
+
return strip_tags(string).split(sep)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@register.filter
|
|
17
|
+
def strip(string):
|
|
18
|
+
"""Return the string split by sep.
|
|
19
|
+
|
|
20
|
+
Example usage: {{ value|split:"/" }}
|
|
21
|
+
"""
|
|
22
|
+
return strip_tags(string)
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from django.apps import apps
|
|
2
|
+
from django.db.models.signals import pre_migrate
|
|
3
|
+
from pytest_factoryboy import register
|
|
4
|
+
from wbcore.contrib.authentication.factories import UserFactory
|
|
5
|
+
from wbcore.contrib.directory.factories import EmailContactFactory, PersonFactory
|
|
6
|
+
from wbcore.contrib.geography.tests.signals import app_pre_migration
|
|
7
|
+
from wbmailing.factories import (
|
|
8
|
+
MailEventFactory,
|
|
9
|
+
MailFactory,
|
|
10
|
+
MailingListEmailContactThroughModelFactory,
|
|
11
|
+
MailingListFactory,
|
|
12
|
+
MailingListSubscriberChangeRequestFactory,
|
|
13
|
+
MailTemplateFactory,
|
|
14
|
+
MassMailFactory,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
register(EmailContactFactory)
|
|
18
|
+
register(PersonFactory)
|
|
19
|
+
register(UserFactory)
|
|
20
|
+
register(MailingListSubscriberChangeRequestFactory)
|
|
21
|
+
register(MailingListEmailContactThroughModelFactory)
|
|
22
|
+
register(MailingListFactory)
|
|
23
|
+
register(MassMailFactory)
|
|
24
|
+
register(MailFactory)
|
|
25
|
+
register(MailEventFactory)
|
|
26
|
+
register(MailTemplateFactory)
|
|
27
|
+
|
|
28
|
+
from .signals import *
|
|
29
|
+
|
|
30
|
+
pre_migrate.connect(app_pre_migration, sender=apps.get_app_config("wbmailing"))
|
|
File without changes
|