Coverage for website/newsletters/forms.py: 30.11%
65 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1"""The forms defined by the newsletters package."""
3from django import forms
4from django.contrib.admin.widgets import AdminDateWidget
5from django.db.models import Q
6from django.utils import timezone
7from django.utils.translation import gettext_lazy as _
9from events.models import Event
10from thaliawebsite import settings
12from .models import Newsletter, NewsletterEvent
15class NewsletterEventForm(forms.ModelForm):
16 """Custom ModelForm for the NewsletterEvent model to add the order field and javascript for automatic field filling."""
18 event = forms.ChoiceField(label=_("Event"))
20 def __init__(self, *args, **kwargs):
21 super().__init__(*args, **kwargs)
23 self.fields["event"].choices = [(None, "-----")] + [
24 (e.pk, e.title)
25 for e in Event.objects.filter(published=True, start__gt=timezone.now())
26 ]
27 self.fields["event"].required = False
29 class Meta:
30 fields = (
31 "order",
32 "event",
33 "title",
34 "url",
35 "description",
36 "where",
37 "start_datetime",
38 "end_datetime",
39 "show_costs_warning",
40 "price",
41 "penalty_costs",
42 )
43 model = NewsletterEvent
45 class Media:
46 js = (
47 "js/js.cookie.min.js",
48 "admin/newsletters/js/forms.js",
49 )
52class NewsletterImportEventForm(forms.Form):
53 event_start = forms.DateField(required=False, widget=AdminDateWidget())
54 event_end = forms.DateField(required=False, widget=AdminDateWidget())
56 registration_start = forms.DateField(required=False, widget=AdminDateWidget())
57 registration_end = forms.DateField(required=False, widget=AdminDateWidget())
59 remove_existing = forms.BooleanField(required=False, initial=False)
61 sort_by = forms.ChoiceField(
62 choices=(
63 ("start", _("Event start date")),
64 ("registration", _("Registrations open date")),
65 ),
66 required=True,
67 )
69 def import_events(self, newsletter: Newsletter):
70 """Import events from the database into the newsletter."""
71 if self.cleaned_data["remove_existing"]:
72 NewsletterEvent.objects.filter(newsletter=newsletter).delete()
74 (event_start, event_end, registration_start, registration_end) = (
75 self.cleaned_data["event_start"],
76 self.cleaned_data["event_end"],
77 self.cleaned_data["registration_start"],
78 self.cleaned_data["registration_end"],
79 )
81 events = Event.objects.filter(published=True)
83 if event_start and registration_start:
84 events = events.filter(
85 Q(
86 registration_start__date__gte=registration_start,
87 registration_start__date__lte=registration_end,
88 )
89 | Q(
90 start__date__lte=event_end,
91 start__date__gte=event_start,
92 )
93 )
94 elif event_start:
95 events = events.filter(
96 start__date__gte=event_start,
97 start__date__lte=event_end,
98 )
99 elif registration_start:
100 events = events.filter(
101 registration_start__date__gte=registration_start,
102 registration_start__date__lte=registration_end,
103 )
104 else:
105 raise forms.ValidationError(
106 _("Please specify which events you want to add to the newsletter.")
107 )
109 if self.cleaned_data["sort_by"] == "start":
110 events = events.order_by("start")
111 elif self.cleaned_data["sort_by"] == "registration":
112 events = events.order_by("registration_start")
114 max_order = (
115 NewsletterEvent.objects.filter(newsletter=newsletter)
116 .order_by("-order")
117 .first()
118 )
119 max_order = max_order.order if max_order else 0
121 for i, event in enumerate(events, start=max_order + 1):
122 NewsletterEvent.objects.create(
123 newsletter=newsletter,
124 order=i,
125 title=event.title,
126 url=settings.BASE_URL + event.get_absolute_url(),
127 description=event.description,
128 where=event.location,
129 start_datetime=event.start,
130 end_datetime=event.end,
131 show_costs_warning=event.fine > 0,
132 price=event.price,
133 penalty_costs=event.fine,
134 )
136 def clean(self):
137 data = super().clean()
138 (event_start, event_end, registration_start, registration_end) = (
139 data.get("event_start"),
140 data.get("event_end"),
141 data.get("registration_start"),
142 data.get("registration_end"),
143 )
144 if event_start is not None and event_end is None:
145 self.add_error(
146 "event_end", _("This field is required if you specify a start date.")
147 )
148 if event_end is not None and event_start is None:
149 self.add_error(
150 "event_start", _("This field is required if you specify an end date.")
151 )
152 if registration_start is not None and registration_end is None:
153 self.add_error(
154 "registration_end",
155 _("This field is required if you specify a start date."),
156 )
157 if registration_end is not None and registration_start is None:
158 self.add_error(
159 "registration_start",
160 _("This field is required if you specify an end date."),
161 )
163 if (
164 event_start is not None
165 and event_end is not None
166 and (event_start > event_end)
167 ):
168 self.add_error("event_end", _("Range must end after it starts."))
169 if (
170 registration_start is not None
171 and registration_end is not None
172 and (registration_start > registration_end)
173 ):
174 self.add_error("registration_end", _("Range must end after it starts."))
176 if event_start is None and registration_start is None:
177 self.add_error(
178 "event_start",
179 _("Please specify which events you want to add to the newsletter."),
180 )
181 self.add_error(
182 "registration_start",
183 _("Please specify which events you want to add to the newsletter."),
184 )
186 return data