diff --git a/src/agenda_culturel/forms.py b/src/agenda_culturel/forms.py index 52f57af..2a082f1 100644 --- a/src/agenda_culturel/forms.py +++ b/src/agenda_culturel/forms.py @@ -40,6 +40,41 @@ import logging logger = logging.getLogger(__name__) +class TagForm(ModelForm): + class Meta: + model = Tag + fields = ["name", "description", "in_included_suggestions", "in_excluded_suggestions", "principal", "category"] + widgets = { + "name": HiddenInput() + } + +class TagRenameForm(Form): + name = CharField( + label=_('Name of new tag'), + required=True + ) + + force = BooleanField( + label=_('Force renaming despite the existence of events already using the chosen tag.'), + ) + + def __init__(self, *args, **kwargs): + force = kwargs.pop("force", False) + name = kwargs.pop("name", None) + super().__init__(*args, **kwargs) + if not (force or (not len(args) == 0 and 'force' in args[0])): + logger.warning('on delete ' + str(args)) + del self.fields["force"] + else: + logger.warning('on delete pas') + if not name is None and self.fields["name"].initial is None: + self.fields["name"].initial = name + + + def is_force(self): + logger.warning(self.cleaned_data) + return "force" in self.fields and self.cleaned_data["force"] == True + class URLSubmissionForm(Form): url = URLField(max_length=512) category = ModelChoiceField( diff --git a/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po b/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po index e6470e8..39f40ee 100644 --- a/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po +++ b/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: agenda_culturel\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-17 14:11+0100\n" +"POT-Creation-Date: 2024-11-17 22:38+0100\n" "PO-Revision-Date: 2023-10-29 14:16+0000\n" "Last-Translator: Jean-Marie Favreau \n" "Language-Team: Jean-Marie Favreau \n" @@ -90,63 +90,74 @@ msgstr "Après-midi" msgid "Evening" msgstr "Soir" -#: agenda_culturel/filters.py:60 +#: agenda_culturel/filters.py:63 msgid "Select a location" msgstr "Choisir une localité" -#: agenda_culturel/filters.py:318 +#: agenda_culturel/filters.py:321 msgid "Representative version" msgstr "Version représentative" -#: agenda_culturel/filters.py:319 +#: agenda_culturel/filters.py:322 msgid "Yes" msgstr "Oui" -#: agenda_culturel/filters.py:319 +#: agenda_culturel/filters.py:322 msgid "Non" msgstr "Non" -#: agenda_culturel/filters.py:324 +#: agenda_culturel/filters.py:327 msgid "Imported from" msgstr "Importé depuis" -#: agenda_culturel/filters.py:354 agenda_culturel/models.py:1564 +#: agenda_culturel/filters.py:357 agenda_culturel/models.py:1564 msgid "Closed" msgstr "Fermé" -#: agenda_culturel/filters.py:354 +#: agenda_culturel/filters.py:357 msgid "Open" msgstr "Ouvert" -#: agenda_culturel/filters.py:359 agenda_culturel/models.py:1558 +#: agenda_culturel/filters.py:362 agenda_culturel/models.py:1558 msgid "Spam" msgstr "Spam" -#: agenda_culturel/filters.py:359 +#: agenda_culturel/filters.py:362 msgid "Non spam" msgstr "Non spam" -#: agenda_culturel/filters.py:370 +#: agenda_culturel/filters.py:373 msgid "Search" msgstr "Rechercher" -#: agenda_culturel/forms.py:46 agenda_culturel/models.py:169 +#: agenda_culturel/forms.py:53 +msgid "Name of new tag" +msgstr "Nom de la nouvelle étiquette" + +#: agenda_culturel/forms.py:58 +msgid "" +"Force renaming despite the existence of events already using the chosen tag." +msgstr "" +"Forcer le renommage malgré l'existence d'événements utilisant déjà " +"l'étiquette choisie." + +#: agenda_culturel/forms.py:81 agenda_culturel/models.py:169 #: agenda_culturel/models.py:207 agenda_culturel/models.py:508 #: agenda_culturel/models.py:1668 agenda_culturel/models.py:1773 msgid "Category" msgstr "Catégorie" -#: agenda_culturel/forms.py:49 +#: agenda_culturel/forms.py:84 msgid "Optional. If you dont specify a category, well find it for you." msgstr "" "Facultatif. Si tu ne donnes pas la catégorie, on s'occupe de la trouver." -#: agenda_culturel/forms.py:53 agenda_culturel/forms.py:94 -#: agenda_culturel/forms.py:193 agenda_culturel/models.py:614 +#: agenda_culturel/forms.py:88 agenda_culturel/forms.py:129 +#: agenda_culturel/forms.py:228 agenda_culturel/models.py:614 msgid "Tags" msgstr "Étiquettes" -#: agenda_culturel/forms.py:56 agenda_culturel/forms.py:97 +#: agenda_culturel/forms.py:91 agenda_culturel/forms.py:132 msgid "" "Optional. If you offer labels, theyll make it easier for your girlfriends to " "find your event." @@ -154,90 +165,90 @@ msgstr "" "Facultatif. Si tu proposes des étiquettes, ça aidera les copaines à " "retrouver facilement ton événement." -#: agenda_culturel/forms.py:152 +#: agenda_culturel/forms.py:187 msgid "The end date must be after the start date." msgstr "La date de fin doit être après la date de début." -#: agenda_culturel/forms.py:168 +#: agenda_culturel/forms.py:203 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." -#: agenda_culturel/forms.py:194 +#: agenda_culturel/forms.py:229 msgid "Select tags from existing ones." msgstr "Sélectionner des étiquettes depuis celles existantes." -#: agenda_culturel/forms.py:199 +#: agenda_culturel/forms.py:234 msgid "New tags" msgstr "Nouvelles étiquettes" -#: agenda_culturel/forms.py:200 +#: agenda_culturel/forms.py:235 msgid "Create new labels (sparingly)." msgstr "Créer (avec parcimonie) de nouvelles étiquettes." -#: agenda_culturel/forms.py:240 +#: agenda_culturel/forms.py:275 msgid "JSON in the format expected for the import." msgstr "JSON dans le format attendu pour l'import" -#: agenda_culturel/forms.py:260 +#: agenda_culturel/forms.py:295 msgid " (locally modified version)" msgstr " (version modifiée localement)" -#: agenda_culturel/forms.py:264 +#: agenda_culturel/forms.py:299 msgid " (synchronized on import version)" msgstr " (version synchronisée sur l'import)" -#: agenda_culturel/forms.py:268 +#: agenda_culturel/forms.py:303 msgid "Select {} as representative version." msgstr "Sélectionner {} comme version représentative" -#: agenda_culturel/forms.py:277 +#: agenda_culturel/forms.py:312 msgid "Update {} using some fields from other versions (interactive mode)." msgstr "" "Mettre à jour {} en utilisant quelques champs des autres versions (mode " "interactif)." -#: agenda_culturel/forms.py:284 +#: agenda_culturel/forms.py:319 msgid " Warning: a version is already locally modified." msgstr " Attention: une version a déjà été modifiée localement." -#: agenda_culturel/forms.py:289 +#: agenda_culturel/forms.py:324 msgid "Create a new version by merging (interactive mode)." msgstr "Créer une nouvelle version par fusion (mode interactif)." -#: agenda_culturel/forms.py:296 +#: agenda_culturel/forms.py:331 msgid "Make {} independent." msgstr "Rendre {} indépendant." -#: agenda_culturel/forms.py:298 +#: agenda_culturel/forms.py:333 msgid "Make all versions independent." msgstr "Rendre toutes les versions indépendantes." -#: agenda_culturel/forms.py:353 +#: agenda_culturel/forms.py:388 msgid "Value of the selected version" msgstr "Valeur de la version sélectionnée" -#: agenda_culturel/forms.py:355 agenda_culturel/forms.py:359 +#: agenda_culturel/forms.py:390 agenda_culturel/forms.py:394 msgid "Value of version {}" msgstr "Valeur de la version {}" -#: agenda_culturel/forms.py:506 +#: agenda_culturel/forms.py:541 msgid "Apply category {} to the event {}" msgstr "Appliquer la catégorie {} à l'événement {}" -#: agenda_culturel/forms.py:521 agenda_culturel/models.py:432 +#: agenda_culturel/forms.py:556 agenda_culturel/models.py:432 #: agenda_culturel/models.py:1825 msgid "Place" msgstr "Lieu" -#: agenda_culturel/forms.py:523 +#: agenda_culturel/forms.py:558 msgid "Create a missing place" msgstr "Créer un lieu manquant" -#: agenda_culturel/forms.py:533 +#: agenda_culturel/forms.py:568 msgid "Add \"{}\" to the aliases of the place" msgstr "Ajouter « {} » aux alias du lieu" -#: agenda_culturel/forms.py:560 +#: agenda_culturel/forms.py:595 msgid "On saving, use aliases to detect all matching events with missing place" msgstr "" "Lors de l'enregistrement, utiliser des alias pour détecter tous les " @@ -378,7 +389,9 @@ msgstr "Principale" #: agenda_culturel/models.py:398 msgid "This location is one of the main locations (shown first higher values)." -msgstr "Cette position est une position principale (affichage en premier des plus grandes valeurs)." +msgstr "" +"Cette position est une position principale (affichage en premier des plus " +"grandes valeurs)." #: agenda_culturel/models.py:403 msgid "Reference location" @@ -894,27 +907,27 @@ msgstr "anglais" msgid "French" msgstr "français" -#: agenda_culturel/views.py:141 +#: agenda_culturel/views.py:143 msgid "Recurrent import name" msgstr "Nome de l'import récurrent" -#: agenda_culturel/views.py:142 +#: agenda_culturel/views.py:144 msgid "Add another" msgstr "Ajouter un autre" -#: agenda_culturel/views.py:143 +#: agenda_culturel/views.py:145 msgid "Browse..." msgstr "Naviguer..." -#: agenda_culturel/views.py:144 +#: agenda_culturel/views.py:146 msgid "No file selected." msgstr "Pas de fichier sélectionné." -#: agenda_culturel/views.py:280 +#: agenda_culturel/views.py:282 msgid "The static content has been successfully updated." msgstr "Le contenu statique a été modifié avec succès." -#: agenda_culturel/views.py:288 +#: agenda_culturel/views.py:290 msgid "" "The event cannot be updated because the import process is not available for " "the referenced sources." @@ -922,33 +935,33 @@ msgstr "" "La mise à jour de l'événement n'est pas possible car le processus d'import " "n'est pas disponible pour les sources référencées." -#: agenda_culturel/views.py:291 +#: agenda_culturel/views.py:293 msgid "The event update has been queued and will be completed shortly." msgstr "" "La mise à jour de l'événement a été mise en attente et sera effectuée sous " "peu." -#: agenda_culturel/views.py:301 +#: agenda_culturel/views.py:303 msgid "The event has been successfully modified." msgstr "L'événement a été modifié avec succès." -#: agenda_culturel/views.py:345 +#: agenda_culturel/views.py:347 msgid "The event has been successfully moderated." msgstr "L'événement a été modéré avec succès." -#: agenda_culturel/views.py:433 +#: agenda_culturel/views.py:435 msgid "The event has been successfully deleted." msgstr "L'événement a été supprimé avec succès." -#: agenda_culturel/views.py:465 +#: agenda_culturel/views.py:467 msgid "The status has been successfully modified." msgstr "Le status a été modifié avec succès." -#: agenda_culturel/views.py:501 +#: agenda_culturel/views.py:503 msgid "The event was created: {}." msgstr "L'événement a été créé: {}." -#: agenda_culturel/views.py:503 agenda_culturel/views.py:517 +#: agenda_culturel/views.py:505 agenda_culturel/views.py:519 msgid "" "The event has been submitted and will be published as soon as it has been " "validated by the moderation team." @@ -956,82 +969,82 @@ msgstr "" "L'événement a été soumis et sera publié dès qu'il aura été validé par " "l'équipe de modération." -#: agenda_culturel/views.py:511 +#: agenda_culturel/views.py:513 msgid "The event is saved." msgstr "L'événement est enregistré." -#: agenda_culturel/views.py:605 agenda_culturel/views.py:657 +#: agenda_culturel/views.py:607 agenda_culturel/views.py:659 msgid "{} has not been submitted since its already known: {}." msgstr "{} n'a pas été soumis car il est déjà connu: {}." -#: agenda_culturel/views.py:610 agenda_culturel/views.py:663 +#: agenda_culturel/views.py:612 agenda_culturel/views.py:665 msgid "" "{} has not been submitted since its already known and currently into " "moderation process." msgstr "{} n'a pas été soumis car il est déjà connu et en cours de modération" -#: agenda_culturel/views.py:620 +#: agenda_culturel/views.py:622 msgid "Integrating {} url(s) into our import process." msgstr "Intégration de {} url(s) dans notre processus d'import." -#: agenda_culturel/views.py:670 +#: agenda_culturel/views.py:672 msgid "Integrating {} into our import process." msgstr "Intégration de {} dans notre processus d'import." -#: agenda_culturel/views.py:725 +#: agenda_culturel/views.py:727 msgid "Your message has been sent successfully." msgstr "Votre message a été envoyé avec succès." -#: agenda_culturel/views.py:735 +#: agenda_culturel/views.py:737 msgid "The contact message has been successfully deleted." msgstr "Le message de contact a été supprimé avec succès." -#: agenda_culturel/views.py:749 +#: agenda_culturel/views.py:751 msgid "The contact message properties has been successfully modified." msgstr "Les propriétés du message de contact ont été modifié avec succès." -#: agenda_culturel/views.py:886 +#: agenda_culturel/views.py:888 msgid "Spam has been successfully deleted." msgstr "Le spam a été supprimé avec succès" -#: agenda_culturel/views.py:998 +#: agenda_culturel/views.py:1000 msgid "The import has been run successfully." msgstr "L'import a été lancé avec succès" -#: agenda_culturel/views.py:1017 +#: agenda_culturel/views.py:1019 msgid "The import has been canceled." msgstr "L'import a été annulé" -#: agenda_culturel/views.py:1091 +#: agenda_culturel/views.py:1093 msgid "The recurrent import has been successfully modified." msgstr "L'import récurrent a été modifié avec succès." -#: agenda_culturel/views.py:1100 +#: agenda_culturel/views.py:1102 msgid "The recurrent import has been successfully deleted." msgstr "L'import récurrent a été supprimé avec succès" -#: agenda_culturel/views.py:1140 +#: agenda_culturel/views.py:1142 msgid "The import has been launched." msgstr "L'import a été lancé" -#: agenda_culturel/views.py:1162 +#: agenda_culturel/views.py:1164 msgid "Imports has been launched." msgstr "Les imports ont été lancés" -#: agenda_culturel/views.py:1221 +#: agenda_culturel/views.py:1223 msgid "Update successfully completed." msgstr "Mise à jour réalisée avec succès." -#: agenda_culturel/views.py:1279 +#: agenda_culturel/views.py:1281 msgid "Creation of a merged event has been successfully completed." msgstr "Création d'un événement fusionné réalisée avec succès." -#: agenda_culturel/views.py:1315 +#: agenda_culturel/views.py:1317 msgid "Events have been marked as unduplicated." msgstr "Les événements ont été marqués comme non dupliqués." -#: agenda_culturel/views.py:1329 agenda_culturel/views.py:1338 -#: agenda_culturel/views.py:1356 +#: agenda_culturel/views.py:1331 agenda_culturel/views.py:1340 +#: agenda_culturel/views.py:1358 msgid "" "The selected item is no longer included in the list of duplicates. Someone " "else has probably modified the list in the meantime." @@ -1039,23 +1052,23 @@ msgstr "" "L'élément sélectionné ne fait plus partie de la liste des dupliqués. Une " "autre personne a probablement modifié la liste entre temps." -#: agenda_culturel/views.py:1332 +#: agenda_culturel/views.py:1334 msgid "The selected event has been set as representative" msgstr "L'événement sélectionné a été défini comme representatif." -#: agenda_culturel/views.py:1347 +#: agenda_culturel/views.py:1349 msgid "The event has been withdrawn from the group and made independent." msgstr "L'événement a été retiré du groupe et rendu indépendant." -#: agenda_culturel/views.py:1391 +#: agenda_culturel/views.py:1393 msgid "Cleaning up duplicates: {} item(s) fixed." msgstr "Nettoyage des dupliqués: {} élément(s) corrigé(s)." -#: agenda_culturel/views.py:1440 +#: agenda_culturel/views.py:1442 msgid "The event was successfully duplicated." msgstr "L'événement a été marqué dupliqué avec succès." -#: agenda_culturel/views.py:1448 +#: agenda_culturel/views.py:1450 msgid "" "The event has been successfully flagged as a duplicate. The moderation team " "will deal with your suggestion shortly." @@ -1063,32 +1076,32 @@ msgstr "" "L'événement a été signalé comme dupliqué avec succès. Votre suggestion sera " "prochainement prise en charge par l'équipe de modération." -#: agenda_culturel/views.py:1501 +#: agenda_culturel/views.py:1503 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:1510 +#: agenda_culturel/views.py:1512 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:1532 +#: agenda_culturel/views.py:1534 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:1539 +#: agenda_culturel/views.py:1541 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:1546 agenda_culturel/views.py:1599 +#: agenda_culturel/views.py:1548 agenda_culturel/views.py:1601 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é" -#: agenda_culturel/views.py:1585 +#: agenda_culturel/views.py:1587 msgid "" "The rules were successfully applied and 1 event with default category was " "categorised." @@ -1096,7 +1109,7 @@ msgstr "" "Les règles ont été appliquées avec succès et 1 événement avec catégorie par " "défaut a été catégorisé" -#: agenda_culturel/views.py:1592 +#: agenda_culturel/views.py:1594 msgid "" "The rules were successfully applied and {} events with default category were " "categorised." @@ -1104,41 +1117,70 @@ msgstr "" "Les règles ont été appliquées avec succès et {} événements avec catégorie " "par défaut ont été catégorisés" -#: agenda_culturel/views.py:1681 agenda_culturel/views.py:1743 -#: agenda_culturel/views.py:1781 +#: agenda_culturel/views.py:1683 agenda_culturel/views.py:1745 +#: agenda_culturel/views.py:1783 msgid "{} events have been updated." msgstr "{} événements ont été mis à jour." -#: agenda_culturel/views.py:1684 agenda_culturel/views.py:1745 -#: agenda_culturel/views.py:1784 +#: agenda_culturel/views.py:1686 agenda_culturel/views.py:1747 +#: agenda_culturel/views.py:1786 msgid "1 event has been updated." msgstr "1 événement a été mis à jour" -#: agenda_culturel/views.py:1686 agenda_culturel/views.py:1747 -#: agenda_culturel/views.py:1786 +#: agenda_culturel/views.py:1688 agenda_culturel/views.py:1749 +#: agenda_culturel/views.py:1788 msgid "No events have been modified." msgstr "Aucun événement n'a été modifié." -#: agenda_culturel/views.py:1695 +#: agenda_culturel/views.py:1697 msgid "The place has been successfully updated." msgstr "Le lieu a été modifié avec succès." -#: agenda_culturel/views.py:1704 +#: agenda_culturel/views.py:1706 msgid "The place has been successfully created." msgstr "Le lieu a été créé avec succès." -#: agenda_culturel/views.py:1769 +#: agenda_culturel/views.py:1771 msgid "The selected place has been assigned to the event." msgstr "Le lieu sélectionné a été assigné à l'événement." -#: agenda_culturel/views.py:1773 +#: agenda_culturel/views.py:1775 msgid "A new alias has been added to the selected place." msgstr "Un nouvel alias a été créé pour le lieu sélectionné." -#: agenda_culturel/views.py:1829 +#: agenda_culturel/views.py:1831 msgid "The tag has been successfully updated." msgstr "L'étiquette a été modifiée avec succès." -#: agenda_culturel/views.py:1836 +#: agenda_culturel/views.py:1838 msgid "The tag has been successfully created." msgstr "L'étiquette a été créée avec succès." + +#: agenda_culturel/views.py:1901 +msgid "You have not modified the tag name." +msgstr "Vous n'avez pas modifié le nom de l'étiquette." + +#: agenda_culturel/views.py:1911 +msgid "" +"This tag {} is already in use, and is described by different information " +"from the current tag. You can force renaming by checking the corresponding " +"option. The information associated with tag {} will be deleted, and all " +"events associated with tag {} will be associated with tag {}." +msgstr "" +"Cette étiquette {} est déjà utilisée, et est décrite par des informations " +"différentes de l'étiquette courante. Vous pouvez forcer le renommage en " +"cochant l'option correspondante. L'information associée à l'étiquette {} " +"sera supprimée, et tous les événements associés à l'étiquette {} seront " +"associés à l'étiquette {}." + +#: agenda_culturel/views.py:1918 +msgid "" +"This tag {} is already in use. You can force renaming by checking the " +"corresponding option." +msgstr "" +"Cette étiquette {} est déjà utilisée. Vous pouvez forcer le renommage en " +"cochant l'option correspondante." + +#: agenda_culturel/views.py:1941 +msgid "The tag {} has been successfully renamed to {}." +msgstr "L'étiquette {} a été renommée avec succès en {}." diff --git a/src/agenda_culturel/static/style.scss b/src/agenda_culturel/static/style.scss index 0346b14..5f0ac34 100644 --- a/src/agenda_culturel/static/style.scss +++ b/src/agenda_culturel/static/style.scss @@ -549,6 +549,12 @@ article#filters { font-size: 100%; } } +.helptext { + display: block; + margin-top: 0; +} + + header .remarque { font-style: italic; } @@ -567,6 +573,8 @@ header .remarque { .slide-buttons { float: right; + max-width: 30em; + text-align: right; } .left-buttons { display: inline-block; diff --git a/src/agenda_culturel/templates/agenda_culturel/tag.html b/src/agenda_culturel/templates/agenda_culturel/tag.html index 9eb9137..d1ac7fd 100644 --- a/src/agenda_culturel/templates/agenda_culturel/tag.html +++ b/src/agenda_culturel/templates/agenda_culturel/tag.html @@ -3,6 +3,7 @@ {% block title %}{% block og_title %}Les événements {{ tag }}{% endblock %}{% endblock %} {% load cat_extra %} +{% load utils_extra %} {% block fluid %}{% endblock %} @@ -16,21 +17,28 @@ {% block content %}
+ + < Toutes les étiquettes +
{% if object %} {% if perms.agenda_culturel.change_tag %} - Modifier + Modifier {% picto_from_name "edit" %} {% endif %} {% if perms.agenda_culturel.delete_tag %} - Supprimer les informations - {% endif %} - {% else %} - {% if perms.agenda_culturel.add_tag %} - Renseigner l'étiquette + Supprimer les informations {% picto_from_name "trash-2" %} + {% endif %} + {% else %} + {% if perms.agenda_culturel.add_tag %} + Renseigner {% picto_from_name "edit" %} {% endif %} {% endif %} + {% if perms.agenda_culturel.change_tag %} + Renommer {% picto_from_name "edit-3" %} + Supprimer {% picto_from_name "trash-2" %} + {% endif %}
-

Les événements {{ tag }}

+

Les événements {{ tag }}

{% if user.is_authenticated and object %} {% if object.in_excluded_suggestions %}

Cette étiquette fait partie des étiquettes suggérées pour l'exclusion.

@@ -42,6 +50,7 @@

Cette étiquette fait partie des étiquettes principales mises en avant.

{% endif %} {% endif %} +
diff --git a/src/agenda_culturel/templates/agenda_culturel/tag_confirm_delete_by_name.html b/src/agenda_culturel/templates/agenda_culturel/tag_confirm_delete_by_name.html new file mode 100644 index 0000000..f385a7b --- /dev/null +++ b/src/agenda_culturel/templates/agenda_culturel/tag_confirm_delete_by_name.html @@ -0,0 +1,35 @@ +{% extends "agenda_culturel/page.html" %} + +{% block title %}{% block og_title %}Suppression de l'étiquette {{ tag }}{% endblock %}{% endblock %} + +{% block fluid %}{% endblock %} + +{% block configurer-bouton %}{% endblock %} + +{% block content %} + +
+
+

Suppression de l'étiquette {{ yag }}

+
+
{% csrf_token %} +

Êtes-vous sûr·e de vouloir supprimer l'étiquette « {{ tag }} » ?

+ {% if nb > 0 %} +

Remarquez qu'elle est associée à {{ nb }} événement{{ nb|pluralize }}, qui + {% if nb > 1 %} seront bien sûr conservés, mais perdront cette étiquette. + {% else %} sera bien sûr conservé, mais perdra cette étiquette. + {% endif %}

+ {% endif %} + {% if obj %} +

Différentes informations sont associées à cette étiquette (description, suggestion d'inclusion, etc) + seront également perdues lors de cette suppression.

+ {% endif %} + {{ form }} +
+ Annuler + +
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/src/agenda_culturel/templates/agenda_culturel/tag_form.html b/src/agenda_culturel/templates/agenda_culturel/tag_form.html index 91ca84b..d0177e2 100644 --- a/src/agenda_culturel/templates/agenda_culturel/tag_form.html +++ b/src/agenda_culturel/templates/agenda_culturel/tag_form.html @@ -8,15 +8,17 @@ {% endblock %} -{% block title %}{% block og_title %}Renseignement d'une étiquette{% endblock %}{% endblock %} +{% block title %}{% block og_title %}Renseignement de l'étiquette {{ form.name.value }}{% endblock %}{% endblock %} {% block fluid %}{% endblock %} {% block content %} -

Renseignement d'une étiquette

-
+
+

Renseignement de l'étiquette {{ form.name.value }}

+
+
{% csrf_token %} {{ form.media }} {{ form.as_p }} diff --git a/src/agenda_culturel/templates/agenda_culturel/tag_rename_form.html b/src/agenda_culturel/templates/agenda_culturel/tag_rename_form.html new file mode 100644 index 0000000..2690840 --- /dev/null +++ b/src/agenda_culturel/templates/agenda_culturel/tag_rename_form.html @@ -0,0 +1,34 @@ +{% extends "agenda_culturel/page-admin.html" %} +{% load static %} + +{% block entete_header %} + + + + +{% endblock %} + +{% block title %}{% block og_title %}Renommer l'étiquette {{ tag }}{% endblock %}{% endblock %} + +{% block fluid %}{% endblock %} + +{% block content %} + +
+
+

Renommer l'étiquette {{ tag }}

+

En renommant l'étiquette {{ tag }}, vous remplacerez cette étiquette par la nouvelle pour tous les événements concernés.

+
+ + + {% csrf_token %} + {{ form.media }} + {{ form.as_p }} +
+ Annuler + +
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/src/agenda_culturel/urls.py b/src/agenda_culturel/urls.py index 5301742..93eab8d 100644 --- a/src/agenda_culturel/urls.py +++ b/src/agenda_culturel/urls.py @@ -21,7 +21,9 @@ urlpatterns = [ path("tag//", view_tag, name="view_tag"), path("tags/", tag_list, name="view_all_tags"), path("tag//edit", TagUpdateView.as_view(), name="edit_tag"), - path("tag//delete", TagDeleteView.as_view(), name="delete_tag"), + path("tag//delete", TagDeleteView.as_view(), name="delete_object_tag"), + path("tag//rename", rename_tag, name="rename_tag"), + path("tag//delete", delete_tag, name="delete_tag"), path("tags/add", TagCreateView.as_view(), name="add_tag"), path("recent/", recent, name="recent"), path("administration/", administration, name="administration"), diff --git a/src/agenda_culturel/views.py b/src/agenda_culturel/views.py index 0a48594..1ca4dac 100644 --- a/src/agenda_culturel/views.py +++ b/src/agenda_culturel/views.py @@ -33,7 +33,9 @@ from .forms import ( EventAddPlaceForm, PlaceForm, MultipleHiddenInput, - EventModerateForm + EventModerateForm, + TagForm, + TagRenameForm ) from .filters import ( @@ -1825,14 +1827,14 @@ class PlaceFromEventCreateView(PlaceCreateView): class TagUpdateView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView): model = Tag permission_required = "agenda_culturel.change_tag" - fields = ["name", "description", "principal", "category", "in_excluded_suggestions", "in_included_suggestions"] + form_class = TagForm success_message = _("The tag has been successfully updated.") class TagCreateView(PermissionRequiredMixin, SuccessMessageMixin, CreateView): model = Tag permission_required = "agenda_culturel.add_tag" - fields = ["name", "description", "principal", "category", "in_excluded_suggestions", "in_included_suggestions"] + form_class = TagForm success_message = _("The tag has been successfully created.") def get_initial(self, *args, **kwargs): @@ -1881,4 +1883,106 @@ def tag_list(request): tags = [t | {'obj': d_objects[t["tag"]]} if t["tag"] in d_objects else t for t in tags] context = {"tags": sorted(tags, key=lambda x: remove_accents(x["tag"]).lower())} - return render(request, "agenda_culturel/tags.html", context) \ No newline at end of file + return render(request, "agenda_culturel/tags.html", context) + +@login_required(login_url="/accounts/login/") +@permission_required("agenda_culturel.change_tag") +def rename_tag(request, t): + form = TagRenameForm(name=t) + force = False + + if request.method == "POST": + form = TagRenameForm(request.POST, name=t) + if form.is_valid(): + save = True + if form.cleaned_data["name"] == t: + messages.warning( + request, + _( + "You have not modified the tag name." + ), + ) + save = False + elif not form.is_force(): + if Event.objects.filter(tags__contains=[form.cleaned_data["name"]]).count() > 0: + if Tag.objects.filter(name=form.cleaned_data["name"]): + messages.warning( + request, + (_( + "This tag {} is already in use, and is described by different information from the current tag. You can force renaming by checking the corresponding option. The information associated with tag {} will be deleted, and all events associated with tag {} will be associated with tag {}." + )).format(form.cleaned_data["name"], t, t, form.cleaned_data["name"]), + ) + else: + messages.warning( + request, + (_( + "This tag {} is already in use. You can force renaming by checking the corresponding option." + )).format(form.cleaned_data["name"]), + ) + save = False + form = TagRenameForm(request.POST, name=t, force=True) + + if save: + # find all matching events and update them + events = Event.objects.filter(tags__contains=[t]) + new_name = form.cleaned_data["name"] + for e in events: + e.tags = [te for te in e.tags if te != t] + if not new_name in e.tags: + e.tags += [new_name] + Event.objects.bulk_update(events, fields=["tags"]) + + # find tag object + tag_object = Tag.objects.filter(name=t).first() + if tag_object: + tag_object.delete() + messages.success( + request, + (_( + "The tag {} has been successfully renamed to {}." + )).format(t, form.cleaned_data["name"]), + ) + return HttpResponseRedirect(reverse_lazy("view_tag", kwargs={"t": form.cleaned_data["name"]})) + + nb = Event.objects.filter(tags__contains=[t]).count() + + return render( + request, "agenda_culturel/tag_rename_form.html", context={"form": form, "tag": t, "nb": nb} + ) + +@login_required(login_url="/accounts/login/") +@permission_required("agenda_culturel.delete_tag") +def delete_tag(request, t): + respage = reverse_lazy("view_all_tags") + nb = Event.objects.filter(tags__contains=[t]).count() + obj = Tag.objects.filter(name=t).first() + + if request.method == "POST": + + # remove tag from events + events = Event.objects.filter(tags__contains=[t]) + for e in events: + e.tags = [te for te in e.tags if te != t] + Event.objects.bulk_update(events, fields=["tags"]) + + # find tag object + tag_object = Tag.objects.filter(name=t).first() + if tag_object: + tag_object.delete() + + messages.success( + request, + (_( + "The tag {} has been successfully deleted." + )).format(t), + ) + return HttpResponseRedirect(respage) + else: + cancel_url = request.META.get("HTTP_REFERER", "") + if cancel_url == "": + cancel_url = respage + return render( + request, + "agenda_culturel/tag_confirm_delete_by_name.html", + {"tag": t, "nb": nb, "cancel_url": cancel_url, "obj": obj}, + )