Merge branch 'main' of ssh://forge.chapril.org:222/jmtrivial/agenda_culturel
This commit is contained in:
commit
07395da9e0
@ -2,7 +2,7 @@ from django.forms import ModelForm, ValidationError, TextInput, Form, URLField,
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
|
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
|
||||||
|
|
||||||
from .models import Event, BatchImportation, RecurrentImport
|
from .models import Event, BatchImportation, RecurrentImport, CategorisationRule
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from string import ascii_uppercase as auc
|
from string import ascii_uppercase as auc
|
||||||
from .templatetags.utils_extra import int_to_abc
|
from .templatetags.utils_extra import int_to_abc
|
||||||
@ -33,6 +33,11 @@ class RecurrentImportForm(ModelForm):
|
|||||||
'defaultTags': DynamicArrayWidgetTags(),
|
'defaultTags': DynamicArrayWidgetTags(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategorisationRuleImportForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = CategorisationRule
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
class EventForm(ModelForm):
|
class EventForm(ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -143,7 +143,6 @@ class ICALNoVCExtractor(ICALExtractor):
|
|||||||
return text
|
return text
|
||||||
else:
|
else:
|
||||||
result = self.parser.format(text)
|
result = self.parser.format(text)
|
||||||
logger.warning(result)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def add_event(self, title, category, start_day, location, description, tags, uuid, recurrences=None, url_human=None, start_time=None, end_day=None, end_time=None, last_modified=None, published=False, image=None, image_alt=None):
|
def add_event(self, title, category, start_day, location, description, tags, uuid, recurrences=None, url_human=None, start_time=None, end_day=None, end_time=None, last_modified=None, published=False, image=None, image_alt=None):
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: agenda_culturel\n"
|
"Project-Id-Version: agenda_culturel\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-02-16 16:06+0000\n"
|
"POT-Creation-Date: 2024-02-17 11:31+0000\n"
|
||||||
"PO-Revision-Date: 2023-10-29 14:16+0000\n"
|
"PO-Revision-Date: 2023-10-29 14:16+0000\n"
|
||||||
"Last-Translator: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
|
"Last-Translator: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
|
||||||
"Language-Team: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
|
"Language-Team: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
|
||||||
@ -17,374 +17,430 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: agenda_culturel/forms.py:62
|
#: agenda_culturel/forms.py:70
|
||||||
msgid "The end date must be after the start date."
|
msgid "The end date must be after the start date."
|
||||||
msgstr "La date de fin doit être après la date de début."
|
msgstr "La date de fin doit être après la date de début."
|
||||||
|
|
||||||
#: agenda_culturel/forms.py:77
|
#: agenda_culturel/forms.py:85
|
||||||
msgid "The end time cannot be earlier than the start time."
|
msgid "The end time cannot be earlier than the start time."
|
||||||
msgstr "L'heure de fin ne peut pas être avant l'heure de début."
|
msgstr "L'heure de fin ne peut pas être avant l'heure de début."
|
||||||
|
|
||||||
#: agenda_culturel/forms.py:84
|
#: agenda_culturel/forms.py:92
|
||||||
msgid "JSON in the format expected for the import."
|
msgid "JSON in the format expected for the import."
|
||||||
msgstr "JSON dans le format attendu pour l'import"
|
msgstr "JSON dans le format attendu pour l'import"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:32 agenda_culturel/models.py:61
|
#: agenda_culturel/models.py:33 agenda_culturel/models.py:62
|
||||||
#: agenda_culturel/models.py:702
|
#: agenda_culturel/models.py:703
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:32 agenda_culturel/models.py:61
|
#: agenda_culturel/models.py:33 agenda_culturel/models.py:62
|
||||||
msgid "Category name"
|
msgid "Category name"
|
||||||
msgstr "Nom de la catégorie"
|
msgstr "Nom de la catégorie"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:33
|
#: agenda_culturel/models.py:34
|
||||||
msgid "Content"
|
msgid "Content"
|
||||||
msgstr "Contenu"
|
msgstr "Contenu"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:33
|
#: agenda_culturel/models.py:34
|
||||||
msgid "Text as shown to the visitors"
|
msgid "Text as shown to the visitors"
|
||||||
msgstr "Text tel que présenté aux visiteureuses"
|
msgstr "Text tel que présenté aux visiteureuses"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:34
|
#: agenda_culturel/models.py:35
|
||||||
msgid "URL path"
|
msgid "URL path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: agenda_culturel/models.py:34
|
#: agenda_culturel/models.py:35
|
||||||
msgid "URL path where the content is included."
|
msgid "URL path where the content is included."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: agenda_culturel/models.py:62
|
#: agenda_culturel/models.py:63
|
||||||
msgid "Alternative Name"
|
msgid "Alternative Name"
|
||||||
msgstr "Nom alternatif"
|
msgstr "Nom alternatif"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:62
|
#: agenda_culturel/models.py:63
|
||||||
msgid "Alternative name used with a time period"
|
msgid "Alternative name used with a time period"
|
||||||
msgstr "Nom alternatif utilisé avec une période de temps"
|
msgstr "Nom alternatif utilisé avec une période de temps"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:63
|
#: agenda_culturel/models.py:64
|
||||||
msgid "Short name"
|
msgid "Short name"
|
||||||
msgstr "Nom court"
|
msgstr "Nom court"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:63
|
#: agenda_culturel/models.py:64
|
||||||
msgid "Short name of the category"
|
msgid "Short name of the category"
|
||||||
msgstr "Nom court de la catégorie"
|
msgstr "Nom court de la catégorie"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:64
|
#: agenda_culturel/models.py:65
|
||||||
msgid "Color"
|
msgid "Color"
|
||||||
msgstr "Couleur"
|
msgstr "Couleur"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:64
|
#: agenda_culturel/models.py:65
|
||||||
msgid "Color used as background for the category"
|
msgid "Color used as background for the category"
|
||||||
msgstr "Couleur utilisée comme fond de la catégorie"
|
msgstr "Couleur utilisée comme fond de la catégorie"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:101 agenda_culturel/models.py:168
|
#: agenda_culturel/models.py:102 agenda_culturel/models.py:169
|
||||||
#: agenda_culturel/models.py:741
|
#: agenda_culturel/models.py:743 agenda_culturel/models.py:782
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Catégorie"
|
msgstr "Catégorie"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:102
|
#: agenda_culturel/models.py:103
|
||||||
msgid "Categories"
|
msgid "Categories"
|
||||||
msgstr "Catégories"
|
msgstr "Catégories"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:153 agenda_culturel/models.py:739
|
#: agenda_culturel/models.py:154 agenda_culturel/models.py:741
|
||||||
msgid "Published"
|
msgid "Published"
|
||||||
msgstr "Publié"
|
msgstr "Publié"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:154
|
#: agenda_culturel/models.py:155
|
||||||
msgid "Draft"
|
msgid "Draft"
|
||||||
msgstr "Brouillon"
|
msgstr "Brouillon"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:155
|
#: agenda_culturel/models.py:156
|
||||||
msgid "Trash"
|
msgid "Trash"
|
||||||
msgstr "Corbeille"
|
msgstr "Corbeille"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:164
|
#: agenda_culturel/models.py:165
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Titre"
|
msgstr "Titre"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:164
|
#: agenda_culturel/models.py:165
|
||||||
msgid "Short title"
|
msgid "Short title"
|
||||||
msgstr "Titre court"
|
msgstr "Titre court"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:166 agenda_culturel/models.py:764
|
#: agenda_culturel/models.py:167 agenda_culturel/models.py:766
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:168
|
#: agenda_culturel/models.py:169
|
||||||
msgid "Category of the event"
|
msgid "Category of the event"
|
||||||
msgstr "Catégorie de l'événement"
|
msgstr "Catégorie de l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:170
|
#: agenda_culturel/models.py:171
|
||||||
msgid "Day of the event"
|
msgid "Day of the event"
|
||||||
msgstr "Date de l'événement"
|
msgstr "Date de l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:171
|
#: agenda_culturel/models.py:172
|
||||||
msgid "Starting time"
|
msgid "Starting time"
|
||||||
msgstr "Heure de début"
|
msgstr "Heure de début"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:173
|
#: agenda_culturel/models.py:174
|
||||||
msgid "End day of the event"
|
msgid "End day of the event"
|
||||||
msgstr "Fin de l'événement"
|
msgstr "Fin de l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:173
|
#: agenda_culturel/models.py:174
|
||||||
msgid "End day of the event, only required if different from the start day."
|
msgid "End day of the event, only required if different from the start day."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Date de fin de l'événement, uniquement nécessaire s'il est différent du "
|
"Date de fin de l'événement, uniquement nécessaire s'il est différent du "
|
||||||
"premier jour de l'événement"
|
"premier jour de l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:174
|
#: agenda_culturel/models.py:175
|
||||||
msgid "Final time"
|
msgid "Final time"
|
||||||
msgstr "Heure de fin"
|
msgstr "Heure de fin"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:176
|
#: agenda_culturel/models.py:177
|
||||||
msgid "Recurrence"
|
msgid "Recurrence"
|
||||||
msgstr "Récurrence"
|
msgstr "Récurrence"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:178 agenda_culturel/models.py:740
|
#: agenda_culturel/models.py:179 agenda_culturel/models.py:742
|
||||||
msgid "Location"
|
msgid "Location"
|
||||||
msgstr "Localisation"
|
msgstr "Localisation"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:178
|
#: agenda_culturel/models.py:179
|
||||||
msgid "Address of the event"
|
msgid "Address of the event"
|
||||||
msgstr "Adresse de l'événement"
|
msgstr "Adresse de l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:180
|
#: agenda_culturel/models.py:181
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Description"
|
msgstr "Description"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:180
|
#: agenda_culturel/models.py:181
|
||||||
msgid "General description of the event"
|
msgid "General description of the event"
|
||||||
msgstr "Description générale de l'événement"
|
msgstr "Description générale de l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:182
|
#: agenda_culturel/models.py:183
|
||||||
msgid "Illustration (local image)"
|
msgid "Illustration (local image)"
|
||||||
msgstr "Illustration (image locale)"
|
msgstr "Illustration (image locale)"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:182
|
#: agenda_culturel/models.py:183
|
||||||
msgid "Illustration image stored in the agenda server"
|
msgid "Illustration image stored in the agenda server"
|
||||||
msgstr "Image d'illustration stockée sur le serveur de l'agenda"
|
msgstr "Image d'illustration stockée sur le serveur de l'agenda"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:184
|
#: agenda_culturel/models.py:185
|
||||||
msgid "Illustration"
|
msgid "Illustration"
|
||||||
msgstr "Illustration"
|
msgstr "Illustration"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:184
|
#: agenda_culturel/models.py:185
|
||||||
msgid "URL of the illustration image"
|
msgid "URL of the illustration image"
|
||||||
msgstr "URL de l'image illustrative"
|
msgstr "URL de l'image illustrative"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:185
|
#: agenda_culturel/models.py:186
|
||||||
msgid "Illustration description"
|
msgid "Illustration description"
|
||||||
msgstr "Description de l'illustration"
|
msgstr "Description de l'illustration"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:185
|
#: agenda_culturel/models.py:186
|
||||||
msgid "Alternative text used by screen readers for the image"
|
msgid "Alternative text used by screen readers for the image"
|
||||||
msgstr "Texte alternatif utiliser par les lecteurs d'écrans pour l'image"
|
msgstr "Texte alternatif utiliser par les lecteurs d'écrans pour l'image"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:187
|
#: agenda_culturel/models.py:188
|
||||||
msgid "Importation source"
|
msgid "Importation source"
|
||||||
msgstr "Source d'importation"
|
msgstr "Source d'importation"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:187
|
#: agenda_culturel/models.py:188
|
||||||
msgid "Importation source used to detect removed entries."
|
msgid "Importation source used to detect removed entries."
|
||||||
msgstr "Source d'importation utilisée pour détecter les éléments supprimés/"
|
msgstr "Source d'importation utilisée pour détecter les éléments supprimés/"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:188
|
#: agenda_culturel/models.py:189
|
||||||
msgid "UUIDs"
|
msgid "UUIDs"
|
||||||
msgstr "UUIDs"
|
msgstr "UUIDs"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:188
|
#: agenda_culturel/models.py:189
|
||||||
msgid "UUIDs from import to detect duplicated entries."
|
msgid "UUIDs from import to detect duplicated entries."
|
||||||
msgstr "UUIDs utilisés pendant l'import pour détecter les entrées dupliquées"
|
msgstr "UUIDs utilisés pendant l'import pour détecter les entrées dupliquées"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:189
|
#: agenda_culturel/models.py:190
|
||||||
msgid "URLs"
|
msgid "URLs"
|
||||||
msgstr "URLs"
|
msgstr "URLs"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:189
|
#: agenda_culturel/models.py:190
|
||||||
msgid "List of all the urls where this event can be found."
|
msgid "List of all the urls where this event can be found."
|
||||||
msgstr "Liste de toutes les urls où l'événement peut être trouvé."
|
msgstr "Liste de toutes les urls où l'événement peut être trouvé."
|
||||||
|
|
||||||
#: agenda_culturel/models.py:191
|
#: agenda_culturel/models.py:192
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr "Étiquettes"
|
msgstr "Étiquettes"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:191
|
#: agenda_culturel/models.py:192
|
||||||
msgid "A list of tags that describe the event."
|
msgid "A list of tags that describe the event."
|
||||||
msgstr "Une liste d'étiquettes décrivant l'événement"
|
msgstr "Une liste d'étiquettes décrivant l'événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:193
|
#: agenda_culturel/models.py:194
|
||||||
msgid "Possibly duplicated"
|
msgid "Possibly duplicated"
|
||||||
msgstr "Possibles doublons"
|
msgstr "Possibles doublons"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:234
|
#: agenda_culturel/models.py:235
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr "Événement"
|
msgstr "Événement"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:235
|
#: agenda_culturel/models.py:236
|
||||||
msgid "Events"
|
msgid "Events"
|
||||||
msgstr "Événements"
|
msgstr "Événements"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:701
|
#: agenda_culturel/models.py:702
|
||||||
msgid "Subject"
|
msgid "Subject"
|
||||||
msgstr "Sujet"
|
msgstr "Sujet"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:701
|
#: agenda_culturel/models.py:702
|
||||||
msgid "The subject of your message"
|
msgid "The subject of your message"
|
||||||
msgstr "Sujet de votre message"
|
msgstr "Sujet de votre message"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:702
|
#: agenda_culturel/models.py:703
|
||||||
msgid "Your name"
|
msgid "Your name"
|
||||||
msgstr "Votre nom"
|
msgstr "Votre nom"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:703
|
#: agenda_culturel/models.py:704
|
||||||
msgid "Email address"
|
msgid "Email address"
|
||||||
msgstr "Adresse email"
|
msgstr "Adresse email"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:703
|
#: agenda_culturel/models.py:704
|
||||||
msgid "Your email address"
|
msgid "Your email address"
|
||||||
msgstr "Votre adresse email"
|
msgstr "Votre adresse email"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:704
|
#: agenda_culturel/models.py:705
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Message"
|
msgstr "Message"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:704
|
#: agenda_culturel/models.py:705
|
||||||
msgid "Your message"
|
msgid "Your message"
|
||||||
msgstr "Votre message"
|
msgstr "Votre message"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:708 agenda_culturel/views.py:376
|
#: agenda_culturel/models.py:709 agenda_culturel/views.py:376
|
||||||
msgid "Closed"
|
msgid "Closed"
|
||||||
msgstr "Fermé"
|
msgstr "Fermé"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:708
|
#: agenda_culturel/models.py:709
|
||||||
msgid "this message has been processed and no longer needs to be handled"
|
msgid "this message has been processed and no longer needs to be handled"
|
||||||
msgstr "Ce message a été traité et ne nécessite plus d'être pris en charge"
|
msgstr "Ce message a été traité et ne nécessite plus d'être pris en charge"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:709
|
#: agenda_culturel/models.py:710
|
||||||
msgid "Comments"
|
msgid "Comments"
|
||||||
msgstr "Commentaires"
|
msgstr "Commentaires"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:709
|
#: agenda_culturel/models.py:710
|
||||||
msgid "Comments on the message from the moderation team"
|
msgid "Comments on the message from the moderation team"
|
||||||
msgstr "Commentaires sur ce message par l'équipe de modération"
|
msgstr "Commentaires sur ce message par l'équipe de modération"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:718
|
#: agenda_culturel/models.py:719
|
||||||
msgid "ical"
|
msgid "ical"
|
||||||
msgstr "ical"
|
msgstr "ical"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:719
|
#: agenda_culturel/models.py:720
|
||||||
msgid "ical no busy"
|
msgid "ical no busy"
|
||||||
msgstr "ical sans busy"
|
msgstr "ical sans busy"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:722
|
#: agenda_culturel/models.py:721
|
||||||
|
msgid "ical no VC"
|
||||||
|
msgstr "ical sans VC"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:724
|
||||||
msgid "simple"
|
msgid "simple"
|
||||||
msgstr "simple"
|
msgstr "simple"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:723
|
#: agenda_culturel/models.py:725
|
||||||
msgid "Headless Chromium"
|
msgid "Headless Chromium"
|
||||||
msgstr "chromium sans interface"
|
msgstr "chromium sans interface"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:727
|
#: agenda_culturel/models.py:729
|
||||||
msgid "daily"
|
msgid "daily"
|
||||||
msgstr "chaque jour"
|
msgstr "chaque jour"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:728
|
#: agenda_culturel/models.py:730
|
||||||
msgid "weekly"
|
msgid "weekly"
|
||||||
msgstr "chaque semaine"
|
msgstr "chaque semaine"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:730
|
#: agenda_culturel/models.py:732
|
||||||
msgid "Processor"
|
msgid "Processor"
|
||||||
msgstr "Processeur"
|
msgstr "Processeur"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:731
|
#: agenda_culturel/models.py:733
|
||||||
msgid "Downloader"
|
msgid "Downloader"
|
||||||
msgstr "Téléchargeur"
|
msgstr "Téléchargeur"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:733
|
#: agenda_culturel/models.py:735
|
||||||
msgid "Import recurrence"
|
msgid "Import recurrence"
|
||||||
msgstr "Récurrence d'import"
|
msgstr "Récurrence d'import"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:736
|
#: agenda_culturel/models.py:738
|
||||||
msgid "Source"
|
msgid "Source"
|
||||||
msgstr "Source"
|
msgstr "Source"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:736
|
#: agenda_culturel/models.py:738
|
||||||
msgid "URL of the source document"
|
msgid "URL of the source document"
|
||||||
msgstr "URL du document source"
|
msgstr "URL du document source"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:737
|
#: agenda_culturel/models.py:739
|
||||||
msgid "Browsable url"
|
msgid "Browsable url"
|
||||||
msgstr "URL navigable"
|
msgstr "URL navigable"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:737
|
#: agenda_culturel/models.py:739
|
||||||
msgid "URL of the corresponding document that will be shown to visitors."
|
msgid "URL of the corresponding document that will be shown to visitors."
|
||||||
msgstr "URL correspondant au document et qui sera montrée aux visiteurs"
|
msgstr "URL correspondant au document et qui sera montrée aux visiteurs"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:739
|
#: agenda_culturel/models.py:741
|
||||||
msgid "Status of each imported event (published or draft)"
|
msgid "Status of each imported event (published or draft)"
|
||||||
msgstr "Status de chaque événement importé (publié ou brouillon)"
|
msgstr "Status de chaque événement importé (publié ou brouillon)"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:740
|
#: agenda_culturel/models.py:742
|
||||||
msgid "Address for each imported event"
|
msgid "Address for each imported event"
|
||||||
msgstr "Adresse de chaque événement importé"
|
msgstr "Adresse de chaque événement importé"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:741
|
#: agenda_culturel/models.py:743
|
||||||
msgid "Category of each imported event"
|
msgid "Category of each imported event"
|
||||||
msgstr "Catégorie de chaque événement importé"
|
msgstr "Catégorie de chaque événement importé"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:742
|
#: agenda_culturel/models.py:744
|
||||||
msgid "Tags for each imported event"
|
msgid "Tags for each imported event"
|
||||||
msgstr "Étiquettes de chaque événement importé"
|
msgstr "Étiquettes de chaque événement importé"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:742
|
#: agenda_culturel/models.py:744
|
||||||
msgid "A list of tags that describe each imported event."
|
msgid "A list of tags that describe each imported event."
|
||||||
msgstr "Une liste d'étiquettes décrivant chaque événement importé"
|
msgstr "Une liste d'étiquettes décrivant chaque événement importé"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:754
|
#: agenda_culturel/models.py:756
|
||||||
msgid "Running"
|
msgid "Running"
|
||||||
msgstr "En cours"
|
msgstr "En cours"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:755
|
#: agenda_culturel/models.py:757
|
||||||
msgid "Canceled"
|
msgid "Canceled"
|
||||||
msgstr "Annulé"
|
msgstr "Annulé"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:756
|
#: agenda_culturel/models.py:758
|
||||||
msgid "Success"
|
msgid "Success"
|
||||||
msgstr "Succès"
|
msgstr "Succès"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:757
|
#: agenda_culturel/models.py:759
|
||||||
msgid "Failed"
|
msgid "Failed"
|
||||||
msgstr "Erreur"
|
msgstr "Erreur"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:762
|
#: agenda_culturel/models.py:764
|
||||||
msgid "Recurrent import"
|
msgid "Recurrent import"
|
||||||
msgstr "Import récurrent"
|
msgstr "Import récurrent"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:762
|
#: agenda_culturel/models.py:764
|
||||||
msgid "Reference to the recurrent import processing"
|
msgid "Reference to the recurrent import processing"
|
||||||
msgstr "Référence du processus d'import récurrent"
|
msgstr "Référence du processus d'import récurrent"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:766
|
#: agenda_culturel/models.py:768
|
||||||
msgid "Error message"
|
msgid "Error message"
|
||||||
msgstr "Votre message"
|
msgstr "Votre message"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:768
|
#: agenda_culturel/models.py:770
|
||||||
msgid "Number of collected events"
|
msgid "Number of collected events"
|
||||||
msgstr "Nombre d'événements collectés"
|
msgstr "Nombre d'événements collectés"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:769
|
#: agenda_culturel/models.py:771
|
||||||
msgid "Number of imported events"
|
msgid "Number of imported events"
|
||||||
msgstr "Nombre d'événements importés"
|
msgstr "Nombre d'événements importés"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:770
|
#: agenda_culturel/models.py:772
|
||||||
msgid "Number of updated events"
|
msgid "Number of updated events"
|
||||||
msgstr "Nombre d'événements mis à jour"
|
msgstr "Nombre d'événements mis à jour"
|
||||||
|
|
||||||
#: agenda_culturel/models.py:771
|
#: agenda_culturel/models.py:773
|
||||||
msgid "Number of removed events"
|
msgid "Number of removed events"
|
||||||
msgstr "Nombre d'événements supprimés"
|
msgstr "Nombre d'événements supprimés"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:780
|
||||||
|
msgid "Weight"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:780
|
||||||
|
msgid "The lower is the weight, the earlier the filter is applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:782
|
||||||
|
msgid "Category applied to the event"
|
||||||
|
msgstr "Catégorie appliquée à l'événement"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:784
|
||||||
|
msgid "Contained in the description"
|
||||||
|
msgstr "Contenu dans la description"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:784
|
||||||
|
msgid "Text contained in the description"
|
||||||
|
msgstr "Texte contenu dans la description"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:785
|
||||||
|
msgid "Exact description extract"
|
||||||
|
msgstr "Extrait exact de description"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:785
|
||||||
|
msgid ""
|
||||||
|
"If checked, the extract will be searched for in the description using the "
|
||||||
|
"exact form (capitals, accents)."
|
||||||
|
msgstr ""
|
||||||
|
"Si coché, l'extrait sera recherché dans la description en utilisant la forme "
|
||||||
|
"exacte (majuscules, accents)"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:787
|
||||||
|
msgid "Contained in the title"
|
||||||
|
msgstr "Contenu dans le titre"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:787
|
||||||
|
msgid "Text contained in the event title"
|
||||||
|
msgstr "Texte contenu dans le titre de l'événement"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:788
|
||||||
|
msgid "Exact title extract"
|
||||||
|
msgstr "Extrait exact du titre"
|
||||||
|
|
||||||
|
#: agenda_culturel/models.py:788
|
||||||
|
msgid ""
|
||||||
|
"If checked, the extract will be searched for in the title using the exact "
|
||||||
|
"form (capitals, accents)."
|
||||||
|
msgstr ""
|
||||||
|
"Si coché, l'extrait sera recherché dans le titre en utilisant la forme "
|
||||||
|
"exacte (majuscules, accents)"
|
||||||
|
|
||||||
#: agenda_culturel/settings/base.py:135
|
#: agenda_culturel/settings/base.py:135
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "anglais"
|
msgstr "anglais"
|
||||||
@ -530,6 +586,31 @@ msgstr ""
|
|||||||
"L'événement a été signalé comme dupliqué avec succès. Votre suggestion sera "
|
"L'événement a été signalé comme dupliqué avec succès. Votre suggestion sera "
|
||||||
"prochainement prise en charge par l'équipe de modération."
|
"prochainement prise en charge par l'équipe de modération."
|
||||||
|
|
||||||
|
#: agenda_culturel/views.py:814
|
||||||
|
msgid "The categorisation rule has been successfully modified."
|
||||||
|
msgstr "La règle de catégorisation a été modifiée avec succès."
|
||||||
|
|
||||||
|
#: agenda_culturel/views.py:820
|
||||||
|
msgid "The categorisation rule has been successfully deleted."
|
||||||
|
msgstr "La règle de catégorisation a été supprimée avec succès"
|
||||||
|
|
||||||
|
#: agenda_culturel/views.py:831
|
||||||
|
msgid "The rules were successfully applied and 1 event was categorised."
|
||||||
|
msgstr ""
|
||||||
|
"Les règles ont été appliquées avec succès et 1 événement a été catégorisé"
|
||||||
|
|
||||||
|
#: agenda_culturel/views.py:833
|
||||||
|
msgid "The rules were successfully applied and {} events were categorised."
|
||||||
|
msgstr ""
|
||||||
|
"Les règles ont été appliquées avec succès et {} événements ont été "
|
||||||
|
"catégorisés"
|
||||||
|
|
||||||
|
#: agenda_culturel/views.py:835
|
||||||
|
msgid "The rules were successfully applied and no events were categorised."
|
||||||
|
msgstr ""
|
||||||
|
"Les règles ont été appliquées avec succès et aucun événement n'a été "
|
||||||
|
"catégorisé"
|
||||||
|
|
||||||
msgid "Add another"
|
msgid "Add another"
|
||||||
msgstr "Ajouter un autre"
|
msgstr "Ajouter un autre"
|
||||||
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 4.2.7 on 2024-02-17 08:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('agenda_culturel', '0031_recurrentimport_defaultpublished'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='recurrentimport',
|
||||||
|
name='defaultCategory',
|
||||||
|
field=models.ForeignKey(default=1, help_text='Category of each imported event', on_delete=django.db.models.deletion.SET_DEFAULT, to='agenda_culturel.category', verbose_name='Category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='recurrentimport',
|
||||||
|
name='processor',
|
||||||
|
field=models.CharField(choices=[('ical', 'ical'), ('icalnobusy', 'ical no busy'), ('icalnovc', 'ical no VC')], default='ical', max_length=20, verbose_name='Processor'),
|
||||||
|
),
|
||||||
|
]
|
26
src/agenda_culturel/migrations/0033_categorisationrule.py
Normal file
26
src/agenda_culturel/migrations/0033_categorisationrule.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 4.2.7 on 2024-02-17 10:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('agenda_culturel', '0032_alter_recurrentimport_defaultcategory_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CategorisationRule',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('weight', models.IntegerField(default=0, help_text='The lower is the weight, the earlier the filter is applied', verbose_name='Weight')),
|
||||||
|
('description_contains', models.CharField(blank=True, help_text='Text contained in the description', max_length=512, null=True, verbose_name='Contained in the description')),
|
||||||
|
('desc_exact', models.BooleanField(default=False, help_text='If checked, the extract will be searched for in the description using the exact form (capitals, accents).', verbose_name='Exact description extract')),
|
||||||
|
('title_contains', models.CharField(blank=True, help_text='Text contained in the event title', max_length=512, null=True, verbose_name='Contained in the title')),
|
||||||
|
('title_exact', models.BooleanField(default=False, help_text='If checked, the extract will be searched for in the title using the exact form (capitals, accents).', verbose_name='Exact title extract')),
|
||||||
|
('category', models.ForeignKey(help_text='Category applied to the event', on_delete=django.db.models.deletion.CASCADE, to='agenda_culturel.category', verbose_name='Category')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
@ -15,6 +15,7 @@ from django.db.models import Q
|
|||||||
import recurrence.fields
|
import recurrence.fields
|
||||||
import recurrence
|
import recurrence
|
||||||
import copy
|
import copy
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
from django.template.defaultfilters import date as _date
|
from django.template.defaultfilters import date as _date
|
||||||
from datetime import time, timedelta, date
|
from datetime import time, timedelta, date
|
||||||
@ -26,6 +27,9 @@ from .calendar import CalendarList, CalendarDay
|
|||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def remove_accents(input_str):
|
||||||
|
nfkd_form = unicodedata.normalize('NFKD', input_str)
|
||||||
|
return u"".join([c for c in nfkd_form if not unicodedata.combining(c)])
|
||||||
|
|
||||||
class StaticContent(models.Model):
|
class StaticContent(models.Model):
|
||||||
|
|
||||||
@ -363,6 +367,10 @@ class Event(models.Model):
|
|||||||
if self.image and not self.local_image:
|
if self.image and not self.local_image:
|
||||||
self.download_image()
|
self.download_image()
|
||||||
|
|
||||||
|
# try to detect category
|
||||||
|
if self.is_in_importation_process():
|
||||||
|
CategorisationRule.apply_rules(self)
|
||||||
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
@ -772,3 +780,46 @@ class BatchImportation(models.Model):
|
|||||||
nb_removed = models.PositiveIntegerField(verbose_name=_('Number of removed events'), default=0)
|
nb_removed = models.PositiveIntegerField(verbose_name=_('Number of removed events'), default=0)
|
||||||
|
|
||||||
celery_id = models.CharField(max_length=128, default="")
|
celery_id = models.CharField(max_length=128, default="")
|
||||||
|
|
||||||
|
|
||||||
|
class CategorisationRule(models.Model):
|
||||||
|
|
||||||
|
weight = models.IntegerField(verbose_name=_('Weight'), help_text=_("The lower is the weight, the earlier the filter is applied"), default=0)
|
||||||
|
|
||||||
|
category = models.ForeignKey(Category, verbose_name=_('Category'), help_text=_('Category applied to the event'), on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
description_contains = models.CharField(verbose_name=_('Contained in the description'), help_text=_('Text contained in the description'), max_length=512, blank=True, null=True)
|
||||||
|
desc_exact = models.BooleanField(verbose_name=_('Exact description extract'), help_text=_("If checked, the extract will be searched for in the description using the exact form (capitals, accents)."), default=False)
|
||||||
|
|
||||||
|
title_contains = models.CharField(verbose_name=_('Contained in the title'), help_text=_('Text contained in the event title'), max_length=512, blank=True, null=True)
|
||||||
|
title_exact = models.BooleanField(verbose_name=_('Exact title extract'), help_text=_("If checked, the extract will be searched for in the title using the exact form (capitals, accents)."), default=False)
|
||||||
|
|
||||||
|
# on applique toutes les règles, de la première à la dernière
|
||||||
|
def apply_rules(event):
|
||||||
|
rules = CategorisationRule.objects.all().order_by("weight", "pk")
|
||||||
|
|
||||||
|
for rule in rules:
|
||||||
|
if rule.match(event):
|
||||||
|
event.category = rule.category
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def match(self, event):
|
||||||
|
if self.description_contains:
|
||||||
|
if self.desc_exact:
|
||||||
|
if self.description_contains in event.description:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
if remove_accents(self.description_contains).lower() in remove_accents(event.description).lower():
|
||||||
|
return True
|
||||||
|
|
||||||
|
if self.title_contains:
|
||||||
|
if self.title_exact:
|
||||||
|
if self.title_contains in event.title:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
if remove_accents(self.title_contains).lower() in remove_accents(event.title).lower():
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
|
||||||
|
{% block title %}Règles de catégorisation{% endblock %}
|
||||||
|
|
||||||
|
{% load utils_extra %}
|
||||||
|
{% load cat_extra %}
|
||||||
|
{% block entete_header %}
|
||||||
|
{% css_categories %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="grid two-columns">
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<div class="slide-buttons">
|
||||||
|
<a href="{% url 'apply_catrules'%}" role="button" data-tooltip="Appliquer à tous les événements sans catégorie">Appliquer {% picto_from_name "arrow-down-circle" %}</a>
|
||||||
|
<a href="{% url 'add_catrule'%}" role="button">Ajouter {% picto_from_name "plus-circle" %}</a>
|
||||||
|
</div>
|
||||||
|
<h1>Règles de catégorisation</h1>
|
||||||
|
<p>Chaque règle est considérée dans l'ordre croissant des poids. La première règle satisfaite est appliquée par un changement de catégorie, et on les suivantes ne sont pas appliquées.</p>
|
||||||
|
<p>Une règle est satisfaite si au moins une des conditions est satisfaite.</p>
|
||||||
|
<p>Les règles sont appliquées à l'import sur tous les événements, et à la demande sur les événements sans catégorie.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<table role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Identifiant</th>
|
||||||
|
<th>Catégorie</th>
|
||||||
|
<th>Conditions</th>
|
||||||
|
<th>Poids</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for obj in paginator_filter %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ obj.pk }}</a></td>
|
||||||
|
<td>{{ obj.category }}</td>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
{% if obj.title_contains %}
|
||||||
|
<li>Le titre contient {% if obj.title_exact %}exactement {% endif %} « {{ obj.title_contains }} »</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if obj.description_contains %}
|
||||||
|
<li>La description contient {% if obj.desc_exact %}exactement {% endif %} « {{ obj.description_contains }} »</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>{{ obj.weight }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{% url 'edit_catrule' obj.pk %}" role="button">Modifier</a>
|
||||||
|
<a href="{% url 'delete_catrule' obj.pk %}" role="button">Supprimer</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<span>
|
||||||
|
{% if paginator_filter.has_previous %}
|
||||||
|
<a href="?page=1" role="button">« premier</a>
|
||||||
|
<a href="?page={{ paginator_filter.previous_page_number }}" role="button">précédent</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span>
|
||||||
|
Page {{ paginator_filter.number }} sur {{ paginator_filter.paginator.num_pages }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if paginator_filter.has_next %}
|
||||||
|
<a href="?page={{ paginator_filter.next_page_number }}" role="button">suivant</a>
|
||||||
|
<a href="?page={{ paginator_filter.paginator.num_pages }}" role="button">dernier »</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{% include "agenda_culturel/side-nav.html" with current="catrules" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,30 @@
|
|||||||
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
|
||||||
|
{% block title %}Supprimer la règle de catégorisation {{ object.pk }}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Suppression de la règle de catégorisation {{ object.pk }}</h1>
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
<p>Êtes-vous sûr·e de vouloir supprimer la règle de catégorisation « {{ object.pk }} »
|
||||||
|
par la catégorie {{ object.category }},
|
||||||
|
de poids {{ object.weight }} et
|
||||||
|
correspondant aux filtres ci-dessous ?</p>
|
||||||
|
<ul>
|
||||||
|
{% if object.title_contains %}
|
||||||
|
<li>Le titre contient {% if object.title_exact %}exactement {% endif %} « {{ object.title_contains }} »</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if object.description_contains %}
|
||||||
|
<li>La description contient {% if object.desc_exact %}exactement {% endif %} « {{ object.description_contains }} »</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form }}
|
||||||
|
<div class="grid">
|
||||||
|
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% url 'categorisation_rules' %}{% endif %}" role="button" class="secondary">Annuler</a>
|
||||||
|
<input type="submit" value="Confirmer">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,27 @@
|
|||||||
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Règle de catéorisation{% endblock %}
|
||||||
|
|
||||||
|
{% block entete_header %}
|
||||||
|
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
|
||||||
|
<script src="/static/admin/js/jquery.init.js"></script>
|
||||||
|
<link href="{% static 'css/django_better_admin_arrayfield.min.css' %}" type="text/css" media="all" rel="stylesheet">
|
||||||
|
<script src="{% static 'js/django_better_admin_arrayfield.min.js' %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Règle de catéorisation</h1>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<div class="grid">
|
||||||
|
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% url 'categorisation_rules' %}{% endif %}" role="button" class="secondary">Annuler</a>
|
||||||
|
<input type="submit" value="Envoyer">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -4,41 +4,31 @@
|
|||||||
<aside>
|
<aside>
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<h2>Consulter</h2>
|
<h2>Administrer</h2>
|
||||||
</header>
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<li><a {% if current == "tags" %}class="selected" {% endif %}href="{% url 'view_all_tags' %}">Toutes les étiquettes</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</article>
|
|
||||||
<article>
|
|
||||||
<header>
|
|
||||||
<h2>Administrer</h2>
|
|
||||||
</header>
|
</header>
|
||||||
|
<h3>Événements</h3>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a {% if current == "moderation" %}class="selected" {% endif %}href="{% url 'moderation' %}">Derniers événements soumis</a>{% show_badges_events "left" %}</li>
|
<li><a {% if current == "moderation" %}class="selected" {% endif %}href="{% url 'moderation' %}">Derniers événements soumis</a>{% show_badges_events "left" %}</li>
|
||||||
<li><a {% if current == "contactmessages" %}class="selected" {% endif %}href="{% url 'contactmessages' %}">Messages de contact</a>{% show_badge_contactmessages "left" %}</li>
|
|
||||||
<li><a {% if current == "duplicates" %}class="selected" {% endif %}href="{% url 'duplicates' %}">Gestion des doublons</a>{% show_badge_duplicated "left" %}</li>
|
<li><a {% if current == "duplicates" %}class="selected" {% endif %}href="{% url 'duplicates' %}">Gestion des doublons</a>{% show_badge_duplicated "left" %}</li>
|
||||||
|
<li><a {% if current == "tags" %}class="selected" {% endif %}href="{% url 'view_all_tags' %}">Consulter les étiquettes</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</article>
|
<h3>Traitements automatiques</h3>
|
||||||
<article>
|
|
||||||
<header>
|
|
||||||
<h2>Importations</h2>
|
|
||||||
</header>
|
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a {% if current == "imports" %}class="selected" {% endif %}href="{% url 'imports' %}">Historiques des importations</a></li>
|
<li><a {% if current == "imports" %}class="selected" {% endif %}href="{% url 'imports' %}">Historiques des importations</a></li>
|
||||||
<li><a {% if current == "rimports" %}class="selected" {% endif %}href="{% url 'recurrent_imports' %}">Importations récurrentes</a></li>
|
<li><a {% if current == "rimports" %}class="selected" {% endif %}href="{% url 'recurrent_imports' %}">Importations récurrentes</a></li>
|
||||||
|
<li><a {% if current == "catrules" %}class="selected" {% endif %}href="{% url 'categorisation_rules' %}">Règles de catégorisation</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</article>
|
<h3>Messages</h3>
|
||||||
<article>
|
<nav>
|
||||||
<header>
|
<ul>
|
||||||
<h2>Configurer</h2>
|
<li><a {% if current == "contactmessages" %}class="selected" {% endif %}href="{% url 'contactmessages' %}">Messages de contact</a>{% show_badge_contactmessages "left" %}</li>
|
||||||
</header>
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<h3>Configuration interne</h3>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'admin:index' %}">Administration de django</a></li>
|
<li><a href="{% url 'admin:index' %}">Administration de django</a></li>
|
||||||
|
@ -46,6 +46,11 @@ urlpatterns = [
|
|||||||
path("rimports/<int:pk>/edit", RecurrentImportUpdateView.as_view(), name="edit_rimport"),
|
path("rimports/<int:pk>/edit", RecurrentImportUpdateView.as_view(), name="edit_rimport"),
|
||||||
path("rimports/<int:pk>/delete", RecurrentImportDeleteView.as_view(), name="delete_rimport"),
|
path("rimports/<int:pk>/delete", RecurrentImportDeleteView.as_view(), name="delete_rimport"),
|
||||||
path("rimports/<int:pk>/run", run_rimport, name="run_rimport"),
|
path("rimports/<int:pk>/run", run_rimport, name="run_rimport"),
|
||||||
|
path("catrules/", categorisation_rules, name="categorisation_rules"),
|
||||||
|
path("catrules/add", CategorisationRuleCreateView.as_view(), name="add_catrule"),
|
||||||
|
path("catrules/<int:pk>/edit", CategorisationRuleUpdateView.as_view(), name="edit_catrule"),
|
||||||
|
path("catrules/<int:pk>/delete", CategorisationRuleDeleteView.as_view(), name="delete_catrule"),
|
||||||
|
path("catrules/apply", apply_categorisation_rules, name="apply_catrules"),
|
||||||
path("duplicates/", duplicates, name="duplicates"),
|
path("duplicates/", duplicates, name="duplicates"),
|
||||||
path("duplicates/<int:pk>", DuplicatedEventsDetailView.as_view(), name="view_duplicate"),
|
path("duplicates/<int:pk>", DuplicatedEventsDetailView.as_view(), name="view_duplicate"),
|
||||||
path("duplicates/<int:pk>/fix", fix_duplicate, name="fix_duplicate"),
|
path("duplicates/<int:pk>/fix", fix_duplicate, name="fix_duplicate"),
|
||||||
|
@ -11,9 +11,9 @@ from django.http import HttpResponseRedirect
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
from .forms import EventSubmissionForm, EventForm, BatchImportationForm, FixDuplicates, SelectEventInList, MergeDuplicates, RecurrentImportForm
|
from .forms import EventSubmissionForm, EventForm, BatchImportationForm, FixDuplicates, SelectEventInList, MergeDuplicates, RecurrentImportForm, CategorisationRuleImportForm
|
||||||
|
|
||||||
from .models import Event, Category, StaticContent, ContactMessage, BatchImportation, DuplicatedEvents, RecurrentImport
|
from .models import Event, Category, StaticContent, ContactMessage, BatchImportation, DuplicatedEvents, RecurrentImport, CategorisationRule, remove_accents
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
@ -181,9 +181,6 @@ def view_tag(request, t):
|
|||||||
|
|
||||||
|
|
||||||
def tag_list(request):
|
def tag_list(request):
|
||||||
def remove_accents(input_str):
|
|
||||||
nfkd_form = unicodedata.normalize('NFKD', input_str)
|
|
||||||
return u"".join([c for c in nfkd_form if not unicodedata.combining(c)])
|
|
||||||
|
|
||||||
tags = Event.get_all_tags()
|
tags = Event.get_all_tags()
|
||||||
context = {"tags": sorted(tags, key=lambda x: remove_accents(x).lower())}
|
context = {"tags": sorted(tags, key=lambda x: remove_accents(x).lower())}
|
||||||
@ -782,3 +779,62 @@ def set_duplicate(request, year, month, day, pk):
|
|||||||
return render(request, 'agenda_culturel/set_duplicate.html', context={'form': form, 'event': event})
|
return render(request, 'agenda_culturel/set_duplicate.html', context={'form': form, 'event': event})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
## categorisation rules
|
||||||
|
#########################
|
||||||
|
|
||||||
|
@login_required(login_url="/accounts/login/")
|
||||||
|
def categorisation_rules(request):
|
||||||
|
paginator = Paginator(CategorisationRule.objects.all().order_by("weight", "pk"), 10)
|
||||||
|
page = request.GET.get('page')
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = paginator.page(page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
response = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
response = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
|
return render(request, 'agenda_culturel/categorisation_rules.html', {'paginator_filter': response} )
|
||||||
|
|
||||||
|
class CategorisationRuleCreateView(LoginRequiredMixin, CreateView):
|
||||||
|
model = CategorisationRule
|
||||||
|
success_url = reverse_lazy('categorisation_rules')
|
||||||
|
form_class = CategorisationRuleImportForm
|
||||||
|
|
||||||
|
|
||||||
|
class CategorisationRuleUpdateView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
|
||||||
|
model = CategorisationRule
|
||||||
|
form_class = CategorisationRuleImportForm
|
||||||
|
success_url = reverse_lazy('categorisation_rules')
|
||||||
|
success_message = _('The categorisation rule has been successfully modified.')
|
||||||
|
|
||||||
|
|
||||||
|
class CategorisationRuleDeleteView(SuccessMessageMixin, LoginRequiredMixin, DeleteView):
|
||||||
|
model = CategorisationRule
|
||||||
|
success_url = reverse_lazy('categorisation_rules')
|
||||||
|
success_message = _('The categorisation rule has been successfully deleted.')
|
||||||
|
|
||||||
|
@login_required(login_url="/accounts/login/")
|
||||||
|
def apply_categorisation_rules(request):
|
||||||
|
|
||||||
|
nb = 0
|
||||||
|
for e in Event.objects.filter(category=Category.get_default_category_id()):
|
||||||
|
success = CategorisationRule.apply_rules(e)
|
||||||
|
if success:
|
||||||
|
nb += 1
|
||||||
|
e.save()
|
||||||
|
|
||||||
|
|
||||||
|
if nb != 0:
|
||||||
|
if nb == 1:
|
||||||
|
messages.success(request, _("The rules were successfully applied and 1 event was categorised."))
|
||||||
|
else:
|
||||||
|
messages.success(request, _("The rules were successfully applied and {} events were categorised.").format(nb))
|
||||||
|
else:
|
||||||
|
messages.info(request, _("The rules were successfully applied and no events were categorised."))
|
||||||
|
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse_lazy("categorisation_rules"))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user