Ajout d'une classe période remarquable

See #354
This commit is contained in:
Jean-Marie Favreau 2025-04-04 21:05:08 +02:00
parent 0581a46f98
commit 60b0255942
11 changed files with 715 additions and 360 deletions

View File

@ -20,6 +20,7 @@ from .models import (
Tag, Tag,
UserProfile, UserProfile,
SiteConfiguration, SiteConfiguration,
SpecialPeriod,
) )
admin.site.register(SiteConfiguration, SingletonModelAdmin) admin.site.register(SiteConfiguration, SingletonModelAdmin)
@ -35,6 +36,7 @@ admin.site.register(Message)
admin.site.register(ReferenceLocation) admin.site.register(ReferenceLocation)
admin.site.register(Organisation) admin.site.register(Organisation)
admin.site.register(UserProfile) admin.site.register(UserProfile)
admin.site.register(SpecialPeriod)
class URLWidget(DynamicArrayWidget): class URLWidget(DynamicArrayWidget):

View File

@ -36,6 +36,7 @@ from .models import (
RecurrentImport, RecurrentImport,
Tag, Tag,
UserProfile, UserProfile,
SpecialPeriod,
) )
from .templatetags.event_extra import event_field_verbose_name, field_to_html from .templatetags.event_extra import event_field_verbose_name, field_to_html
from .templatetags.utils_extra import int_to_abc from .templatetags.utils_extra import int_to_abc
@ -991,3 +992,14 @@ class UserProfileForm(ModelForm):
class Meta: class Meta:
model = UserProfile model = UserProfile
fields = "__all__" fields = "__all__"
class SpecialPeriodForm(ModelForm):
class Meta:
model = SpecialPeriod
fields = "__all__"
widgets = {
"start_date": TextInput(attrs={"type": "date"}),
"end_date": TextInput(attrs={"type": "date"}),
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
# Generated by Django 4.2.19 on 2025-04-04 20:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("agenda_culturel", "0164_alter_recurrentimport_processor"),
]
operations = [
migrations.CreateModel(
name="SpecialPeriod",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255, verbose_name="Period name")),
("start_date", models.DateField(verbose_name="Start day")),
("end_date", models.DateField(verbose_name="End day")),
(
"periodtype",
models.CharField(
choices=[
("public holidays", "public holidays"),
("school vacations", "school vacations"),
],
default="public holidays",
max_length=20,
verbose_name="Period type",
),
),
],
options={
"verbose_name": "Special period",
"verbose_name_plural": "Special periods",
},
),
]

View File

@ -3155,3 +3155,48 @@ class CategorisationRule(models.Model):
return False return False
return True return True
class SpecialPeriod(models.Model):
name = models.CharField(verbose_name=_("Period name"), max_length=255)
start_date = models.DateField(verbose_name=_("Start day"))
end_date = models.DateField(verbose_name=_("End day"))
class Meta:
verbose_name = _("Special period")
verbose_name_plural = _("Special periods")
class PERIODTYPE(models.TextChoices):
PUBLICHOLIDAYS = "public holidays", _("public holidays")
SCHOOLVACATIONS = "school vacations", _("school vacations")
periodtype = models.CharField(
_("Period type"),
max_length=20,
choices=PERIODTYPE.choices,
default=PERIODTYPE.PUBLICHOLIDAYS,
)
def clean(self):
# Call the parent class's clean() method
super().clean()
# Check that the end date is after or equal to the start date
if self.end_date < self.start_date:
raise ValidationError(
{
"end_date": _(
"The end date must be after or equal to the start date."
)
}
)
def __str__(self):
n = self.periodtype + ' "' + self.name + '" '
if self.start_date == self.end_date:
return n + _(" on ") + str(self.start_date)
else:
return (
n + _(" from ") + str(self.start_date) + _(" to ") + str(self.end_day)
)

View File

@ -101,6 +101,17 @@
</ul> </ul>
</nav> </nav>
{% endif %} {% endif %}
{% if perms.agenda_culturel.edit_specialperiod %}
<h3>Périodes remarquables</h3>
<nav>
<ul>
<li>
<a {% if current == "special_periods" %}class="selected"{% endif %}
href="{% url 'list_specialperiods' %}">Périodes remarquables</a>
</li>
</ul>
</nav>
{% endif %}
{% if user.is_staff %} {% if user.is_staff %}
<h3>Configuration interne</h3> <h3>Configuration interne</h3>
<nav> <nav>

View File

@ -0,0 +1,20 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}
{% block og_title %}Supprimer la période remarquable {{ object }}{% endblock %}
{% endblock %}
{% block fluid %}{% endblock %}
{% block configurer-bouton %}{% endblock %}
{% block content %}
<h1>Suppression de la période remarquable {{ object.pk }}</h1>
<form method="post">
{% csrf_token %}
<p>Êtes-vous sûr·e de vouloir supprimer la période remarquable «&nbsp;{{ object }} ({{ object.pk }})&nbsp;»&nbsp;?</p>
{{ form }}
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{{ object.get_absolute_url }}{% endif %}"
role="button"
class="secondary">Annuler</a>
<input type="submit" value="Confirmer">
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}
{% block og_title %}
{% if object %}
Modifier la période remarquable #{{ object.pk }}
{% else %}
Ajouter une période remarquable
{% endif %}
{% endblock %}
{% endblock %}
{% block fluid %}{% endblock %}
{% block content %}
<h1>
{% if object %}
Modifier la période remarquable #{{ object.pk }}
{% else %}
Ajouter une période remarquable
{% endif %}
</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% url 'list_specialperiods' %}{% endif %}"
role="button"
class="secondary">Annuler</a>
<input type="submit" value="Enregistrer">
</div>
</form>
{{ form.media }}
{% endblock %}

View File

@ -0,0 +1,56 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}
{% block og_title %}Administration des périodes remarquables{% endblock %}
{% endblock %}
{% load utils_extra %}
{% load cat_extra %}
{% block entete_header %}
{% css_categories %}
{% endblock %}
{% block sidemenu-bouton %}
<li>
<a href="#contenu-principal" aria-label="Aller au contenu">{% picto_from_name "chevron-up" %}</a>
</li>
<li>
<a href="#sidebar" aria-label="Aller au menu latéral">{% picto_from_name "chevron-down" %}</a>
</li>
{% endblock %}
{% block content %}
<div class="grid two-columns">
<article>
<header>
<div class="slide-buttons">
<a href="{% url 'add_specialperiod' %}" role="button">Ajouter {% picto_from_name "plus-circle" %}</a>
</div>
<h1>Périodes spéciales</h1>
</header>
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
{% if object_list %}
{% for sp in object_list %}
<article>
<header>
<div class="slide-buttons">
<a href="{% url 'edit_specialperiod' sp.pk %}" role="button">Modifier {% picto_from_name "edit-3" %}</a>
<a href="{% url 'delete_specialperiod' sp.pk %}" role="button">Supprimer {% picto_from_name "trash-2" %}</a>
</div>
<h2>{{ sp.get_periodtype_display }}&nbsp;: {{ sp.name }}</h2>
<p>
{% if sp.start_date == sp.end_date %}
le {{ sp.start_date }}
{% else %}
du {{ sp.start_date }} au {{ sp.end_date }}
{% endif %}
</p>
</header>
</article>
{% endfor %}
{% else %}
<p>Il n'y a aucune période spéciale définie.</p>
{% endif %}
<footer>
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
</footer>
</article>
{% include "agenda_culturel/side-nav.html" with current="special_periods" %}
</div>
{% endblock %}

View File

@ -106,6 +106,10 @@ from .views import (
moderation_rules, moderation_rules,
import_requirements, import_requirements,
UserProfileUpdateView, UserProfileUpdateView,
SpecialPeriodCreateView,
SpecialPeriodDeleteView,
SpecialPeriodListView,
SpecialPeriodUpdateView,
) )
event_dict = { event_dict = {
@ -480,6 +484,24 @@ urlpatterns = [
), ),
path("cache/clear", clear_cache, name="clear_cache"), path("cache/clear", clear_cache, name="clear_cache"),
path("profile/edit", UserProfileUpdateView.as_view(), name="edit_profile"), path("profile/edit", UserProfileUpdateView.as_view(), name="edit_profile"),
path(
"specialperiods/", SpecialPeriodListView.as_view(), name="list_specialperiods"
),
path(
"specialperiods/add",
SpecialPeriodCreateView.as_view(),
name="add_specialperiod",
),
path(
"specialperiods/<pk>/edit",
SpecialPeriodUpdateView.as_view(),
name="edit_specialperiod",
),
path(
"specialperiods/<pk>/delete",
SpecialPeriodDeleteView.as_view(),
name="delete_specialperiod",
),
] ]
if settings.DEBUG: if settings.DEBUG:

View File

@ -85,6 +85,7 @@ from .forms import (
URLSubmissionFormSet, URLSubmissionFormSet,
URLSubmissionFormWithContact, URLSubmissionFormWithContact,
UserProfileForm, UserProfileForm,
SpecialPeriodForm,
) )
from .import_tasks.extractor import Extractor from .import_tasks.extractor import Extractor
from .models import ( from .models import (
@ -102,6 +103,7 @@ from .models import (
remove_accents, remove_accents,
UserProfile, UserProfile,
SiteConfiguration, SiteConfiguration,
SpecialPeriod,
) )
from .utils import PlaceGuesser from .utils import PlaceGuesser
@ -3103,6 +3105,11 @@ def clear_cache(request):
) )
#########################
## User profile
#########################
class UserProfileUpdateView( class UserProfileUpdateView(
SuccessMessageMixin, SuccessMessageMixin,
LoginRequiredMixin, LoginRequiredMixin,
@ -3115,3 +3122,50 @@ class UserProfileUpdateView(
def get_object(self): def get_object(self):
return self.request.user.userprofile return self.request.user.userprofile
#########################
## Special period
#########################
class SpecialPeriodCreateView(
PermissionRequiredMixin, LoginRequiredMixin, SuccessMessageMixin, CreateView
):
model = SpecialPeriod
permission_required = "agenda_culturel.add_specialperiod"
success_message = _("The special period has been successfully created.")
success_url = reverse_lazy("list_specialperiods")
form_class = SpecialPeriodForm
class SpecialPeriodListView(PermissionRequiredMixin, LoginRequiredMixin, ListView):
model = SpecialPeriod
paginate_by = 10
permission_required = "agenda_culturel.add_specialperiod"
ordering = ["start_date", "name__unaccent"]
class SpecialPeriodDeleteView(
SuccessMessageMixin,
PermissionRequiredMixin,
LoginRequiredMixin,
DeleteView,
):
model = SpecialPeriod
permission_required = "agenda_culturel.delete_specialperiod"
success_url = reverse_lazy("list_specialperiods")
success_message = _("The special period has been successfully deleted.")
class SpecialPeriodUpdateView(
SuccessMessageMixin,
PermissionRequiredMixin,
LoginRequiredMixin,
UpdateView,
):
model = SpecialPeriod
permission_required = "agenda_culturel.change_specialperiod"
success_message = _("The special period has been successfully updated.")
success_url = reverse_lazy("list_specialperiods")
form_class = SpecialPeriodForm