mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-10 11:59:23 +00:00
rework news form
This commit is contained in:
186
com/forms.py
186
com/forms.py
@ -1,12 +1,17 @@
|
||||
from datetime import timedelta
|
||||
from datetime import date
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Exists, OuterRef
|
||||
from django.forms import CheckboxInput
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from club.models import Club
|
||||
from club.widgets.select import AutoCompleteSelectClub
|
||||
from com.models import News, NewsDate, Poster
|
||||
from core.models import User
|
||||
from core.utils import get_end_of_semester
|
||||
from core.views.forms import SelectDateTime
|
||||
from core.views.widgets.markdown import MarkdownInput
|
||||
|
||||
@ -46,66 +51,143 @@ class PosterForm(forms.ModelForm):
|
||||
self.fields.pop("display_time")
|
||||
|
||||
|
||||
class NewsDateForm(forms.ModelForm):
|
||||
"""Form to select the dates of an event."""
|
||||
|
||||
required_css_class = "required"
|
||||
|
||||
class Meta:
|
||||
model = NewsDate
|
||||
fields = ["start_date", "end_date"]
|
||||
widgets = {"start_date": SelectDateTime, "end_date": SelectDateTime}
|
||||
|
||||
is_weekly = forms.BooleanField(
|
||||
label=_("Weekly event"),
|
||||
help_text=_("Weekly events will occur each week for a specified timespan."),
|
||||
widget=CheckboxInput(attrs={"class": "switch"}),
|
||||
initial=False,
|
||||
required=False,
|
||||
)
|
||||
occurrence_choices = [
|
||||
*[(str(i), _("%d times") % i) for i in range(2, 7)],
|
||||
("SEMESTER_END", _("Until the end of the semester")),
|
||||
]
|
||||
occurrences = forms.ChoiceField(
|
||||
label=_("Occurrences"),
|
||||
help_text=_("How much times should the event occur (including the first one)"),
|
||||
choices=occurrence_choices,
|
||||
initial="SEMESTER_END",
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.label_suffix = ""
|
||||
|
||||
@classmethod
|
||||
def get_occurrences(cls, number: int) -> tuple[str, str] | None:
|
||||
"""Find the occurrence choice corresponding to numeric number of occurrences."""
|
||||
if number < 2:
|
||||
# If only 0 or 1 date, there cannot be weekly events
|
||||
return None
|
||||
# occurrences have all a numeric value, except "SEMESTER_END"
|
||||
str_num = str(number)
|
||||
occurrences = next((c for c in cls.occurrence_choices if c[0] == str_num), None)
|
||||
if occurrences:
|
||||
return occurrences
|
||||
return next((c for c in cls.occurrence_choices if c[0] == "SEMESTER_END"), None)
|
||||
|
||||
def save(self, commit: bool = True, *, news: News): # noqa FBT001
|
||||
# the base save method contains some checks we want to run
|
||||
# before doing our own logic
|
||||
super().save(commit=False)
|
||||
# delete existing dates before creating new ones
|
||||
news.dates.all().delete()
|
||||
if not self.cleaned_data.get("is_weekly"):
|
||||
self.instance.news = news
|
||||
return super().save(commit=commit)
|
||||
|
||||
dates: list[NewsDate] = [self.instance]
|
||||
occurrences = self.cleaned_data.get("occurrences")
|
||||
start = self.instance.start_date
|
||||
end = self.instance.end_date
|
||||
if occurrences[0].isdigit():
|
||||
nb_occurrences = int(occurrences[0])
|
||||
else: # to the end of the semester
|
||||
start_date = date(start.year, start.month, start.day)
|
||||
nb_occurrences = (get_end_of_semester(start_date) - start_date).days // 7
|
||||
dates.extend(
|
||||
[
|
||||
NewsDate(
|
||||
start_date=start + relativedelta(weeks=i),
|
||||
end_date=end + relativedelta(weeks=i),
|
||||
)
|
||||
for i in range(1, nb_occurrences)
|
||||
]
|
||||
)
|
||||
for d in dates:
|
||||
d.news = news
|
||||
if not commit:
|
||||
return dates
|
||||
return NewsDate.objects.bulk_create(dates)
|
||||
|
||||
|
||||
class NewsForm(forms.ModelForm):
|
||||
"""Form to create or edit news."""
|
||||
|
||||
error_css_class = "error"
|
||||
required_css_class = "required"
|
||||
|
||||
class Meta:
|
||||
model = News
|
||||
fields = ["type", "title", "club", "summary", "content", "author"]
|
||||
fields = ["title", "club", "summary", "content"]
|
||||
widgets = {
|
||||
"author": forms.HiddenInput,
|
||||
"summary": MarkdownInput,
|
||||
"content": MarkdownInput,
|
||||
}
|
||||
|
||||
start_date = forms.DateTimeField(
|
||||
label=_("Start date"), widget=SelectDateTime, required=False
|
||||
auto_moderate = forms.BooleanField(
|
||||
label=_("Automoderation"),
|
||||
widget=CheckboxInput(attrs={"class": "switch"}),
|
||||
required=False,
|
||||
)
|
||||
end_date = forms.DateTimeField(
|
||||
label=_("End date"), widget=SelectDateTime, required=False
|
||||
)
|
||||
until = forms.DateTimeField(label=_("Until"), widget=SelectDateTime, required=False)
|
||||
|
||||
automoderation = forms.BooleanField(label=_("Automoderation"), required=False)
|
||||
def __init__(self, *args, author: User, date_form: NewsDateForm, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.author = author
|
||||
self.date_form = date_form
|
||||
self.label_suffix = ""
|
||||
# if the author is an admin, he/she can choose any club,
|
||||
# otherwise, only clubs for which he/she is a board member can be selected
|
||||
if author.is_root or author.is_com_admin:
|
||||
self.fields["club"] = forms.ModelChoiceField(
|
||||
queryset=Club.objects.all(), widget=AutoCompleteSelectClub
|
||||
)
|
||||
else:
|
||||
active_memberships = author.memberships.board().ongoing()
|
||||
self.fields["club"] = forms.ModelChoiceField(
|
||||
queryset=Club.objects.filter(
|
||||
Exists(active_memberships.filter(club=OuterRef("pk")))
|
||||
)
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
self.cleaned_data = super().clean()
|
||||
if self.cleaned_data["type"] != "NOTICE":
|
||||
if not self.cleaned_data["start_date"]:
|
||||
self.add_error(
|
||||
"start_date", ValidationError(_("This field is required."))
|
||||
)
|
||||
if not self.cleaned_data["end_date"]:
|
||||
self.add_error(
|
||||
"end_date", ValidationError(_("This field is required."))
|
||||
)
|
||||
if (
|
||||
not self.has_error("start_date")
|
||||
and not self.has_error("end_date")
|
||||
and self.cleaned_data["start_date"] > self.cleaned_data["end_date"]
|
||||
):
|
||||
self.add_error(
|
||||
"end_date",
|
||||
ValidationError(_("An event cannot end before its beginning.")),
|
||||
)
|
||||
if self.cleaned_data["type"] == "WEEKLY" and not self.cleaned_data["until"]:
|
||||
self.add_error("until", ValidationError(_("This field is required.")))
|
||||
return self.cleaned_data
|
||||
def is_valid(self):
|
||||
return super().is_valid() and self.date_form.is_valid()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
ret = super().save()
|
||||
self.instance.dates.all().delete()
|
||||
if self.instance.type == "EVENT" or self.instance.type == "CALL":
|
||||
NewsDate(
|
||||
start_date=self.cleaned_data["start_date"],
|
||||
end_date=self.cleaned_data["end_date"],
|
||||
news=self.instance,
|
||||
).save()
|
||||
elif self.instance.type == "WEEKLY":
|
||||
start_date = self.cleaned_data["start_date"]
|
||||
end_date = self.cleaned_data["end_date"]
|
||||
while start_date <= self.cleaned_data["until"]:
|
||||
NewsDate(
|
||||
start_date=start_date, end_date=end_date, news=self.instance
|
||||
).save()
|
||||
start_date += timedelta(days=7)
|
||||
end_date += timedelta(days=7)
|
||||
return ret
|
||||
def full_clean(self):
|
||||
super().full_clean()
|
||||
self.date_form.full_clean()
|
||||
|
||||
def save(self, commit: bool = True): # noqa FBT001
|
||||
self.instance.author = self.author
|
||||
if (self.author.is_com_admin or self.author.is_root) and (
|
||||
self.cleaned_data.get("auto_moderate") is True
|
||||
):
|
||||
self.instance.is_moderated = True
|
||||
self.instance.moderator = self.author
|
||||
else:
|
||||
self.instance.is_moderated = False
|
||||
created_news = super().save(commit=commit)
|
||||
self.date_form.save(commit=commit, news=created_news)
|
||||
return created_news
|
||||
|
Reference in New Issue
Block a user