Ajout d'une classe lieu

This commit is contained in:
Jean-Marie Favreau 2024-04-26 22:52:59 +02:00
parent 5822c7807c
commit 2df11abda3
30 changed files with 592 additions and 203 deletions

View File

@ -1,6 +1,6 @@
from django.contrib import admin
from django import forms
from .models import Event, Category, StaticContent, DuplicatedEvents, BatchImportation, RecurrentImport
from .models import Event, Category, StaticContent, DuplicatedEvents, BatchImportation, RecurrentImport, Place
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
from django_better_admin_arrayfield.models.fields import DynamicArrayField
@ -11,6 +11,7 @@ admin.site.register(StaticContent)
admin.site.register(DuplicatedEvents)
admin.site.register(BatchImportation)
admin.site.register(RecurrentImport)
admin.site.register(Place)
class URLWidget(DynamicArrayWidget):

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: agenda_culturel\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-22 09:16+0000\n"
"POT-Creation-Date: 2024-04-26 14:59+0000\n"
"PO-Revision-Date: 2023-10-29 14:16+0000\n"
"Last-Translator: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
"Language-Team: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
@ -39,457 +39,482 @@ msgstr "Catégorie de l'événement"
msgid "Cannot extract event from url {}"
msgstr "Impossible d'extraire l'événement depuis l'url {}"
#: agenda_culturel/models.py:37 agenda_culturel/models.py:66
#: agenda_culturel/models.py:735 agenda_culturel/models.py:774
#: agenda_culturel/models.py:39 agenda_culturel/models.py:68
#: agenda_culturel/models.py:162 agenda_culturel/models.py:753
#: agenda_culturel/models.py:792
msgid "Name"
msgstr "Nom"
#: agenda_culturel/models.py:37 agenda_culturel/models.py:66
#: agenda_culturel/models.py:39 agenda_culturel/models.py:68
msgid "Category name"
msgstr "Nom de la catégorie"
#: agenda_culturel/models.py:38
#: agenda_culturel/models.py:40
msgid "Content"
msgstr "Contenu"
#: agenda_culturel/models.py:38
#: agenda_culturel/models.py:40
msgid "Text as shown to the visitors"
msgstr "Text tel que présenté aux visiteureuses"
#: agenda_culturel/models.py:39
#: agenda_culturel/models.py:41
msgid "URL path"
msgstr "Chemin URL"
#: agenda_culturel/models.py:39
#: agenda_culturel/models.py:41
msgid "URL path where the content is included."
msgstr "Chemin URL où le contenu est présent."
#: agenda_culturel/models.py:67
#: agenda_culturel/models.py:69
msgid "Alternative Name"
msgstr "Nom alternatif"
#: agenda_culturel/models.py:67
#: agenda_culturel/models.py:69
msgid "Alternative name used with a time period"
msgstr "Nom alternatif utilisé avec une période de temps"
#: agenda_culturel/models.py:68
#: agenda_culturel/models.py:70
msgid "Short name"
msgstr "Nom court"
#: agenda_culturel/models.py:68
#: agenda_culturel/models.py:70
msgid "Short name of the category"
msgstr "Nom court de la catégorie"
#: agenda_culturel/models.py:69
#: agenda_culturel/models.py:71
msgid "Color"
msgstr "Couleur"
#: agenda_culturel/models.py:69
#: agenda_culturel/models.py:71
msgid "Color used as background for the category"
msgstr "Couleur utilisée comme fond de la catégorie"
#: agenda_culturel/models.py:106 agenda_culturel/models.py:174
#: agenda_culturel/models.py:786 agenda_culturel/models.py:837
#: agenda_culturel/models.py:115 agenda_culturel/models.py:195
#: agenda_culturel/models.py:804 agenda_culturel/models.py:855
msgid "Category"
msgstr "Catégorie"
#: agenda_culturel/models.py:107
#: agenda_culturel/models.py:116
msgid "Categories"
msgstr "Catégories"
#: agenda_culturel/models.py:158 agenda_culturel/models.py:784
#: agenda_culturel/models.py:162
msgid "Name of the place"
msgstr "Nom du lieu"
#: agenda_culturel/models.py:163
msgid "Address"
msgstr "Adresse"
#: agenda_culturel/models.py:163
msgid "Address of this place"
msgstr "Adresse de ce lieu"
#: agenda_culturel/models.py:166
msgid "Alternative names"
msgstr "Noms alternatifs"
#: agenda_culturel/models.py:166
msgid ""
"Alternative names or addresses used to match a place with the free-form "
"location of an event."
msgstr ""
"Noms et adresses alternatives qui seront utilisées pour associer une adresse "
"avec la localisation en forme libre d'un événement"
#: agenda_culturel/models.py:169
msgid "Place"
msgstr "Lieu"
#: agenda_culturel/models.py:170
msgid "Places"
msgstr "Lieux"
#: agenda_culturel/models.py:179 agenda_culturel/models.py:802
msgid "Published"
msgstr "Publié"
#: agenda_culturel/models.py:159
#: agenda_culturel/models.py:180
msgid "Draft"
msgstr "Brouillon"
#: agenda_culturel/models.py:160
#: agenda_culturel/models.py:181
msgid "Trash"
msgstr "Corbeille"
#: agenda_culturel/models.py:170
#: agenda_culturel/models.py:191
msgid "Title"
msgstr "Titre"
#: agenda_culturel/models.py:170
#: agenda_culturel/models.py:191
msgid "Short title"
msgstr "Titre court"
#: agenda_culturel/models.py:172 agenda_culturel/models.py:821
#: agenda_culturel/models.py:193 agenda_culturel/models.py:839
msgid "Status"
msgstr "Status"
#: agenda_culturel/models.py:174
#: agenda_culturel/models.py:195
msgid "Category of the event"
msgstr "Catégorie de l'événement"
#: agenda_culturel/models.py:176
#: agenda_culturel/models.py:197
msgid "Day of the event"
msgstr "Date de l'événement"
#: agenda_culturel/models.py:177
#: agenda_culturel/models.py:198
msgid "Starting time"
msgstr "Heure de début"
#: agenda_culturel/models.py:179
#: agenda_culturel/models.py:200
msgid "End day of the event"
msgstr "Fin de l'événement"
#: agenda_culturel/models.py:179
#: agenda_culturel/models.py:200
msgid "End day of the event, only required if different from the start day."
msgstr ""
"Date de fin de l'événement, uniquement nécessaire s'il est différent du "
"premier jour de l'événement"
#: agenda_culturel/models.py:180
#: agenda_culturel/models.py:201
msgid "Final time"
msgstr "Heure de fin"
#: agenda_culturel/models.py:182
#: agenda_culturel/models.py:203
msgid "Recurrence"
msgstr "Récurrence"
#: agenda_culturel/models.py:184 agenda_culturel/models.py:785
#: agenda_culturel/models.py:205 agenda_culturel/models.py:803
msgid "Location"
msgstr "Localisation"
#: agenda_culturel/models.py:184
#: agenda_culturel/models.py:205
msgid "Address of the event"
msgstr "Adresse de l'événement"
#: agenda_culturel/models.py:186
#: agenda_culturel/models.py:206
msgid "Location (free form)"
msgstr "Localisation (forme libre)"
#: agenda_culturel/models.py:206
msgid ""
"Address of the event in case its not available in the already known places "
"(free form)"
msgstr ""
"Addresse d'un événement si elle n'est pas déjà présente dans la liste des "
"lieux disponible (forme libre)"
#: agenda_culturel/models.py:208
msgid "Description"
msgstr "Description"
#: agenda_culturel/models.py:186
#: agenda_culturel/models.py:208
msgid "General description of the event"
msgstr "Description générale de l'événement"
#: agenda_culturel/models.py:188
#: agenda_culturel/models.py:210
msgid "Illustration (local image)"
msgstr "Illustration (image locale)"
#: agenda_culturel/models.py:188
#: agenda_culturel/models.py:210
msgid "Illustration image stored in the agenda server"
msgstr "Image d'illustration stockée sur le serveur de l'agenda"
#: agenda_culturel/models.py:190
#: agenda_culturel/models.py:212
msgid "Illustration"
msgstr "Illustration"
#: agenda_culturel/models.py:190
#: agenda_culturel/models.py:212
msgid "URL of the illustration image"
msgstr "URL de l'image illustrative"
#: agenda_culturel/models.py:191
#: agenda_culturel/models.py:213
msgid "Illustration description"
msgstr "Description de l'illustration"
#: agenda_culturel/models.py:191
#: agenda_culturel/models.py:213
msgid "Alternative text used by screen readers for the image"
msgstr "Texte alternatif utiliser par les lecteurs d'écrans pour l'image"
#: agenda_culturel/models.py:193
#: agenda_culturel/models.py:215
msgid "Importation source"
msgstr "Source d'importation"
#: agenda_culturel/models.py:193
#: agenda_culturel/models.py:215
msgid "Importation source used to detect removed entries."
msgstr "Source d'importation utilisée pour détecter les éléments supprimés/"
#: agenda_culturel/models.py:194
#: agenda_culturel/models.py:216
msgid "UUIDs"
msgstr "UUIDs"
#: agenda_culturel/models.py:194
#: agenda_culturel/models.py:216
msgid "UUIDs from import to detect duplicated entries."
msgstr "UUIDs utilisés pendant l'import pour détecter les entrées dupliquées"
#: agenda_culturel/models.py:195
#: agenda_culturel/models.py:217
msgid "URLs"
msgstr "URLs"
#: agenda_culturel/models.py:195
#: agenda_culturel/models.py:217
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é."
#: agenda_culturel/models.py:197
#: agenda_culturel/models.py:219
msgid "Tags"
msgstr "Étiquettes"
#: agenda_culturel/models.py:197
#: agenda_culturel/models.py:219
msgid "A list of tags that describe the event."
msgstr "Une liste d'étiquettes décrivant l'événement"
#: agenda_culturel/models.py:199
#: agenda_culturel/models.py:221
msgid "Possibly duplicated"
msgstr "Possibles doublons"
#: agenda_culturel/models.py:240
#: agenda_culturel/models.py:262
msgid "Event"
msgstr "Événement"
#: agenda_culturel/models.py:241
#: agenda_culturel/models.py:263
msgid "Events"
msgstr "Événements"
#: agenda_culturel/models.py:731
#: agenda_culturel/models.py:749
msgid "Contact message"
msgstr "Message de contact"
#: agenda_culturel/models.py:732
#: agenda_culturel/models.py:750
#, fuzzy
#| msgid "Your message"
msgid "Contact messages"
msgstr "Messages de contact"
#: agenda_culturel/models.py:734
#: agenda_culturel/models.py:752
msgid "Subject"
msgstr "Sujet"
#: agenda_culturel/models.py:734
#: agenda_culturel/models.py:752
msgid "The subject of your message"
msgstr "Sujet de votre message"
#: agenda_culturel/models.py:735
#: agenda_culturel/models.py:753
msgid "Your name"
msgstr "Votre nom"
#: agenda_culturel/models.py:736
#: agenda_culturel/models.py:754
msgid "Email address"
msgstr "Adresse email"
#: agenda_culturel/models.py:736
#: agenda_culturel/models.py:754
msgid "Your email address"
msgstr "Votre adresse email"
#: agenda_culturel/models.py:737
#: agenda_culturel/models.py:755
msgid "Message"
msgstr "Message"
#: agenda_culturel/models.py:737
#: agenda_culturel/models.py:755
msgid "Your message"
msgstr "Votre message"
#: agenda_culturel/models.py:741 agenda_culturel/views.py:437
#: agenda_culturel/models.py:759 agenda_culturel/views.py:462
msgid "Closed"
msgstr "Fermé"
#: agenda_culturel/models.py:741
#: agenda_culturel/models.py:759
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"
#: agenda_culturel/models.py:742
#: agenda_culturel/models.py:760
msgid "Comments"
msgstr "Commentaires"
#: agenda_culturel/models.py:742
#: agenda_culturel/models.py:760
msgid "Comments on the message from the moderation team"
msgstr "Commentaires sur ce message par l'équipe de modération"
#: agenda_culturel/models.py:752 agenda_culturel/models.py:819
#: agenda_culturel/models.py:770 agenda_culturel/models.py:837
msgid "Recurrent import"
msgstr "Import récurrent"
#: agenda_culturel/models.py:753
#: agenda_culturel/models.py:771
msgid "Recurrent imports"
msgstr "Imports récurrents"
#: agenda_culturel/models.py:757
#: agenda_culturel/models.py:775
msgid "ical"
msgstr "ical"
#: agenda_culturel/models.py:758
#: agenda_culturel/models.py:776
msgid "ical no busy"
msgstr "ical sans busy"
#: agenda_culturel/models.py:759
#: agenda_culturel/models.py:777
msgid "ical no VC"
msgstr "ical sans VC"
#: agenda_culturel/models.py:760
#: agenda_culturel/models.py:778
msgid "lacoope.org"
msgstr "lacoope.org"
#: agenda_culturel/models.py:761
#: agenda_culturel/models.py:779
msgid "la comédie"
msgstr "la comédie"
#: agenda_culturel/models.py:762
#: agenda_culturel/models.py:780
msgid "le fotomat"
msgstr "le fotomat"
#: agenda_culturel/models.py:763
#: agenda_culturel/models.py:781
msgid "la puce à loreille"
msgstr "la puce à loreille"
#: agenda_culturel/models.py:766
#: agenda_culturel/models.py:784
msgid "simple"
msgstr "simple"
#: agenda_culturel/models.py:767
#: agenda_culturel/models.py:785
msgid "Headless Chromium"
msgstr "chromium sans interface"
#: agenda_culturel/models.py:771
#: agenda_culturel/models.py:789
msgid "daily"
msgstr "chaque jour"
#: agenda_culturel/models.py:772
#: agenda_culturel/models.py:790
msgid "weekly"
msgstr "chaque semaine"
#: agenda_culturel/models.py:774
#: agenda_culturel/models.py:792
msgid ""
"Recurrent import name. Be careful to choose a name that is easy to "
"understand, as it will be public and displayed on the sites About page."
msgstr ""
"Nom de l'import récurrent. Attention à choisir un nom compréhensible,"
"car il sera public, et affiché sur la page à propos du site."
"Nom de l'import récurrent. Attention à choisir un nom compréhensible, car il "
"sera public, et affiché sur la page à propos du site."
#: agenda_culturel/models.py:775
#: agenda_culturel/models.py:793
msgid "Processor"
msgstr "Processeur"
#: agenda_culturel/models.py:776
#: agenda_culturel/models.py:794
msgid "Downloader"
msgstr "Téléchargeur"
#: agenda_culturel/models.py:778
#: agenda_culturel/models.py:796
msgid "Import recurrence"
msgstr "Récurrence d'import"
#: agenda_culturel/models.py:781
#: agenda_culturel/models.py:799
msgid "Source"
msgstr "Source"
#: agenda_culturel/models.py:781
#: agenda_culturel/models.py:799
msgid "URL of the source document"
msgstr "URL du document source"
#: agenda_culturel/models.py:782
#: agenda_culturel/models.py:800
msgid "Browsable url"
msgstr "URL navigable"
#: agenda_culturel/models.py:782
#: agenda_culturel/models.py:800
msgid "URL of the corresponding document that will be shown to visitors."
msgstr "URL correspondant au document et qui sera montrée aux visiteurs"
#: agenda_culturel/models.py:784
#: agenda_culturel/models.py:802
msgid "Status of each imported event (published or draft)"
msgstr "Status de chaque événement importé (publié ou brouillon)"
#: agenda_culturel/models.py:785
#: agenda_culturel/models.py:803
msgid "Address for each imported event"
msgstr "Adresse de chaque événement importé"
#: agenda_culturel/models.py:786
#: agenda_culturel/models.py:804
msgid "Category of each imported event"
msgstr "Catégorie de chaque événement importé"
#: agenda_culturel/models.py:787
#: agenda_culturel/models.py:805
msgid "Tags for each imported event"
msgstr "Étiquettes de chaque événement importé"
#: agenda_culturel/models.py:787
#: agenda_culturel/models.py:805
msgid "A list of tags that describe each imported event."
msgstr "Une liste d'étiquettes décrivant chaque événement importé"
#: agenda_culturel/models.py:806
#: agenda_culturel/models.py:824
msgid "Running"
msgstr "En cours"
#: agenda_culturel/models.py:807
#: agenda_culturel/models.py:825
msgid "Canceled"
msgstr "Annulé"
#: agenda_culturel/models.py:808
#: agenda_culturel/models.py:826
msgid "Success"
msgstr "Succès"
#: agenda_culturel/models.py:809
#: agenda_culturel/models.py:827
msgid "Failed"
msgstr "Erreur"
#: agenda_culturel/models.py:812
#: agenda_culturel/models.py:830
msgid "Batch importation"
msgstr "Importation par lot"
#: agenda_culturel/models.py:813
#: agenda_culturel/models.py:831
msgid "Batch importations"
msgstr "Importations par lot"
#: agenda_culturel/models.py:819
#: agenda_culturel/models.py:837
msgid "Reference to the recurrent import processing"
msgstr "Référence du processus d'import récurrent"
#: agenda_culturel/models.py:823
#: agenda_culturel/models.py:841
msgid "Error message"
msgstr "Votre message"
#: agenda_culturel/models.py:825
#: agenda_culturel/models.py:843
msgid "Number of collected events"
msgstr "Nombre d'événements collectés"
#: agenda_culturel/models.py:826
#: agenda_culturel/models.py:844
msgid "Number of imported events"
msgstr "Nombre d'événements importés"
#: agenda_culturel/models.py:827
#: agenda_culturel/models.py:845
msgid "Number of updated events"
msgstr "Nombre d'événements mis à jour"
#: agenda_culturel/models.py:828
#: agenda_culturel/models.py:846
msgid "Number of removed events"
msgstr "Nombre d'événements supprimés"
#: agenda_culturel/models.py:835
#: agenda_culturel/models.py:853
msgid "Weight"
msgstr "Poids"
#: agenda_culturel/models.py:835
#: agenda_culturel/models.py:853
msgid "The lower is the weight, the earlier the filter is applied"
msgstr "Plus le poids est léger, plus le filtre sera appliqué tôt"
#: agenda_culturel/models.py:837
#: agenda_culturel/models.py:855
msgid "Category applied to the event"
msgstr "Catégorie appliquée à l'événement"
#: agenda_culturel/models.py:839
msgid "Contained in the description"
msgstr "Contenu dans la description"
#: agenda_culturel/models.py:839
msgid "Text contained in the description"
msgstr "Texte contenu dans la description"
#: agenda_culturel/models.py:840
msgid "Exact description extract"
msgstr "Extrait exact de description"
#: agenda_culturel/models.py:840
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:842
#: agenda_culturel/models.py:857
msgid "Contained in the title"
msgstr "Contenu dans le titre"
#: agenda_culturel/models.py:842
#: agenda_culturel/models.py:857
msgid "Text contained in the event title"
msgstr "Texte contenu dans le titre de l'événement"
#: agenda_culturel/models.py:843
#: agenda_culturel/models.py:858
msgid "Exact title extract"
msgstr "Extrait exact du titre"
#: agenda_culturel/models.py:843
#: agenda_culturel/models.py:858
msgid ""
"If checked, the extract will be searched for in the title using the exact "
"form (capitals, accents)."
@ -497,19 +522,39 @@ msgstr ""
"Si coché, l'extrait sera recherché dans le titre en utilisant la forme "
"exacte (majuscules, accents)"
#: agenda_culturel/models.py:845
#: agenda_culturel/models.py:860
msgid "Contained in the description"
msgstr "Contenu dans la description"
#: agenda_culturel/models.py:860
msgid "Text contained in the description"
msgstr "Texte contenu dans la description"
#: agenda_culturel/models.py:861
msgid "Exact description extract"
msgstr "Extrait exact de description"
#: agenda_culturel/models.py:861
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:863
msgid "Contained in the location"
msgstr "Contenu dans la localisation"
#: agenda_culturel/models.py:845
#: agenda_culturel/models.py:863
msgid "Text contained in the event location"
msgstr "Texte contenu dans la localisation de l'événement"
#: agenda_culturel/models.py:846
#: agenda_culturel/models.py:864
msgid "Exact location extract"
msgstr "Extrait exact de localisation"
#: agenda_culturel/models.py:846
#: agenda_culturel/models.py:864
msgid ""
"If checked, the extract will be searched for in the location using the exact "
"form (capitals, accents)."
@ -517,85 +562,85 @@ msgstr ""
"Si coché, l'extrait sera recherché dans la localisation en utilisant la "
"forme exacte (majuscules, accents)"
#: agenda_culturel/models.py:849
#: agenda_culturel/models.py:867
msgid "Categorisation rule"
msgstr "Règle de catégorisation"
#: agenda_culturel/models.py:850
#: agenda_culturel/models.py:868
msgid "Categorisation rules"
msgstr "Règles de catégorisation"
#: agenda_culturel/models.py:911 agenda_culturel/models.py:932
#: agenda_culturel/models.py:924 agenda_culturel/models.py:945
msgid "Question"
msgstr "Question"
#: agenda_culturel/models.py:911 agenda_culturel/models.py:934
#: agenda_culturel/models.py:924 agenda_culturel/models.py:947
msgid "Text that will be shown to moderators"
msgstr "Text tel que présenté aux modérateurices"
#: agenda_culturel/models.py:914
#: agenda_culturel/models.py:927
msgid "Moderation question"
msgstr "Question de modération"
#: agenda_culturel/models.py:915
#: agenda_culturel/models.py:928
msgid "Moderation questions"
msgstr "Questions de modération"
#: agenda_culturel/models.py:932
#: agenda_culturel/models.py:945
msgid "Associated question from moderation"
msgstr "Question associée pour la modération"
#: agenda_culturel/models.py:934
#: agenda_culturel/models.py:947
msgid "Answer"
msgstr "Réponse"
#: agenda_culturel/models.py:936
#: agenda_culturel/models.py:949
msgid "Adds tags"
msgstr "Ajoute les étiquettes"
#: agenda_culturel/models.py:936
#: agenda_culturel/models.py:949
msgid "A list of tags that will be added if you choose this answer."
msgstr ""
"Une liste d'étiquettes qui seront ajoutées si vous choisissez cette réponse."
#: agenda_culturel/models.py:937
#: agenda_culturel/models.py:950
msgid "Removes tags"
msgstr "Retire les étiquettes"
#: agenda_culturel/models.py:937
#: agenda_culturel/models.py:950
msgid "A list of tags that will be removed if you choose this answer."
msgstr ""
"Une liste d'étiquettes qui seront retirées si vous choisissez cette réponse."
#: agenda_culturel/settings/base.py:137
#: agenda_culturel/settings/base.py:138
msgid "English"
msgstr "anglais"
#: agenda_culturel/settings/base.py:138
#: agenda_culturel/settings/base.py:139
msgid "French"
msgstr "français"
#: agenda_culturel/views.py:236
#: agenda_culturel/views.py:261
msgid "The static content has been successfully updated."
msgstr "Le contenu statique a été modifié avec succès."
#: agenda_culturel/views.py:243 agenda_culturel/views.py:278
#: agenda_culturel/views.py:268 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:255
#: agenda_culturel/views.py:280
msgid "The event has been successfully deleted."
msgstr "L'événement a été supprimé avec succès"
#: agenda_culturel/views.py:304
#: agenda_culturel/views.py:329
msgid "The status has been successfully modified."
msgstr "Le status a été modifié avec succès."
#: agenda_culturel/views.py:326
#: agenda_culturel/views.py:351
msgid "The event is saved."
msgstr "L'événement est enregistré."
#: agenda_culturel/views.py:329
#: agenda_culturel/views.py:354
msgid ""
"The event has been submitted and will be published as soon as it has been "
"validated by the moderation team."
@ -603,7 +648,7 @@ 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:366
#: agenda_culturel/views.py:391
msgid ""
"The event has been successfully extracted, and you can now submit it after "
"modifying it if necessary."
@ -611,7 +656,7 @@ msgstr ""
"L'événement a été extrait avec succès, vous pouvez maintenant le soumettre "
"après l'avoir modifié au besoin."
#: agenda_culturel/views.py:370
#: agenda_culturel/views.py:395
msgid ""
"Unable to extract an event from the proposed URL. Please use the form below "
"to submit the event."
@ -619,16 +664,16 @@ msgstr ""
"Impossible d'extraire un événement depuis l'URL proposée. Veuillez utiliser "
"le formulaire ci-dessous pour soumettre l'événement."
#: agenda_culturel/views.py:379
#: agenda_culturel/views.py:404
msgid "This URL has already been submitted, and you can find the event below."
msgstr ""
"Cette URL a déjà été soumise, et vous trouverez l'événement ci-dessous."
#: agenda_culturel/views.py:383
#: agenda_culturel/views.py:408
msgid "This URL has already been submitted and is awaiting moderation."
msgstr "Cette URL a déjà été soumise, et est en attente de modération"
#: agenda_culturel/views.py:385
#: agenda_culturel/views.py:410
msgid ""
"This URL has already been submitted, but has not been selected for "
"publication by the moderation team."
@ -636,51 +681,51 @@ msgstr ""
"Cette URL a déjà été soumise, mais n'a pas été retenue par l'équipe de "
"modération pour la publication."
#: agenda_culturel/views.py:407
#: agenda_culturel/views.py:432
msgid "Your message has been sent successfully."
msgstr "Votre message a été envoyé avec succès."
#: agenda_culturel/views.py:422
#: agenda_culturel/views.py:447
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:437
#: agenda_culturel/views.py:462
msgid "Open"
msgstr "Ouvert"
#: agenda_culturel/views.py:479
#: agenda_culturel/views.py:504
msgid "Search"
msgstr "Rechercher"
#: agenda_culturel/views.py:596
#: agenda_culturel/views.py:639
msgid "The import has been run successfully."
msgstr "L'import a été lancé avec succès"
#: agenda_culturel/views.py:613
#: agenda_culturel/views.py:656
msgid "The import has been canceled."
msgstr "L'import a été annulé"
#: agenda_culturel/views.py:650
#: agenda_culturel/views.py:693
msgid "The recurrent import has been successfully modified."
msgstr "L'import récurrent a été modifié avec succès."
#: agenda_culturel/views.py:657
#: agenda_culturel/views.py:700
msgid "The recurrent import has been successfully deleted."
msgstr "L'import récurrent a été supprimé avec succès"
#: agenda_culturel/views.py:688
#: agenda_culturel/views.py:731
msgid "The import has been launched."
msgstr "L'import a été lancé"
#: agenda_culturel/views.py:748
#: agenda_culturel/views.py:791
msgid "The merge has been successfully completed."
msgstr "La fusion a été réalisée avec succès."
#: agenda_culturel/views.py:778
#: agenda_culturel/views.py:821
msgid "Events have been marked as unduplicated."
msgstr "Les événements ont été marqués comme non dupliqués."
#: agenda_culturel/views.py:795
#: agenda_culturel/views.py:838
msgid ""
"The selected event has been retained, while the other has been moved to the "
"recycle bin."
@ -688,7 +733,7 @@ msgstr ""
"L'événement sélectionné a été conservé, l'autre a été déplacé dans la "
"corbeille."
#: agenda_culturel/views.py:797
#: agenda_culturel/views.py:840
msgid ""
"The selected event has been retained, while the others have been moved to "
"the recycle bin."
@ -696,15 +741,15 @@ msgstr ""
"L'événement sélectionné a été conservé, les autres ont été déplacés dans la "
"corbeille."
#: agenda_culturel/views.py:803
#: agenda_culturel/views.py:846
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:850
#: agenda_culturel/views.py:893
msgid "The event was successfully duplicated."
msgstr "L'événement a été marqué dupliqué avec succès."
#: agenda_culturel/views.py:853
#: agenda_culturel/views.py:896
msgid ""
"The event has been successfully flagged as a duplicate. The moderation team "
"will deal with your suggestion shortly."
@ -712,32 +757,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:892
#: agenda_culturel/views.py:935
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:899
#: agenda_culturel/views.py:942
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:919 agenda_culturel/views.py:948
#: agenda_culturel/views.py:962 agenda_culturel/views.py:991
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:921 agenda_culturel/views.py:950
#: agenda_culturel/views.py:964 agenda_culturel/views.py:993
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:923 agenda_culturel/views.py:952
#: agenda_culturel/views.py:966 agenda_culturel/views.py:995
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:980
#: agenda_culturel/views.py:1023
msgid "The moderation question has been created with success."
msgstr "La question de modération a été créée avec succès."

View File

@ -0,0 +1,40 @@
# Generated by Django 4.2.7 on 2024-04-26 14:24
from django.db import migrations, models
import django.db.models.deletion
import django_better_admin_arrayfield.models.fields
import location_field.models.plain
class Migration(migrations.Migration):
dependencies = [
('agenda_culturel', '0055_alter_recurrentimport_name'),
]
operations = [
migrations.CreateModel(
name='Place',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='Name of the place', verbose_name='Name')),
('address', models.CharField(help_text='Address of this place', verbose_name='Address')),
('location', location_field.models.plain.PlainLocationField(max_length=63)),
('aliases', django_better_admin_arrayfield.models.fields.ArrayField(base_field=models.CharField(max_length=512), blank=True, help_text='Alternative names or addresses used to match a place with a description form an event.', null=True, size=None, verbose_name='Alternative names')),
],
options={
'verbose_name': 'Place',
'verbose_name_plural': 'Places',
},
),
migrations.AlterField(
model_name='event',
name='location',
field=models.CharField(default='', help_text='Address of the event in case its not available in the already known places (free form)', max_length=512, verbose_name='Location (free form)'),
),
migrations.AddField(
model_name='event',
name='exact_location',
field=models.ForeignKey(help_text='Address of the event', null=True, on_delete=django.db.models.deletion.SET_NULL, to='agenda_culturel.place', verbose_name='Location'),
),
]

View File

@ -23,6 +23,8 @@ from datetime import time, timedelta, date
from django.utils.timezone import datetime
from django.utils import timezone
from location_field.models.plain import PlainLocationField
from .calendar import CalendarList, CalendarDay
import logging
@ -156,6 +158,25 @@ class DuplicatedEvents(models.Model):
def get_items_comparison(self):
return [self.get_item_comparison(e) for e in Event.data_fields(all=True)]
class Place(models.Model):
name = models.CharField(verbose_name=_('Name'), help_text=_('Name of the place'))
address = models.CharField(verbose_name=_('Address'), help_text=_('Address of this place'))
location = PlainLocationField(based_fields=['name', 'address'], zoom=12)
aliases = ArrayField(models.CharField(max_length=512), verbose_name=_('Alternative names'), help_text=_("Alternative names or addresses used to match a place with the free-form location of an event."), blank=True, null=True)
class Meta:
verbose_name = _('Place')
verbose_name_plural = _('Places')
def __str__(self):
return self.name + ", " + self.address
def get_absolute_url(self):
return reverse("view_place", kwargs={"pk": self.pk})
class Event(models.Model):
class STATUS(models.TextChoices):
@ -185,7 +206,8 @@ class Event(models.Model):
recurrences = recurrence.fields.RecurrenceField(verbose_name=_("Recurrence"), include_dtstart=False, blank=True, null=True)
location = models.CharField(verbose_name=_('Location'), help_text=_('Address of the event'), max_length=512, default="")
exact_location = models.ForeignKey(Place, verbose_name=_('Location'), help_text=_('Address of the event'), null=True, on_delete=models.SET_NULL)
location = models.CharField(verbose_name=_('Location (free form)'), help_text=_('Address of the event in case its not available in the already known places (free form)'), max_length=512, default="")
description = models.TextField(verbose_name=_('Description'), help_text=_('General description of the event'), blank=True, null=True)

View File

@ -47,6 +47,7 @@ INSTALLED_APPS = [
'compressor',
'ckeditor',
'recurrence',
'location_field.apps.DefaultConfig',
]
MIDDLEWARE = [
@ -206,4 +207,12 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000
# recurrence translation
RECURRENCE_I18N_URL = "javascript-catalog"
RECURRENCE_I18N_URL = "javascript-catalog"
# location field
LOCATION_FIELD = {
'map.provider': 'openstreetmap',
'provider.openstreetmap.max_zoom': 18,
'search.provider': 'addok',
}

View File

@ -629,6 +629,10 @@ form [role="button"], form button {
margin: var(--spacing) 0 var(--spacing) 0;
}
form .buttons [role="button"] {
margin: 0 0 var(--spacing) 0;
}
.large {
margin: 2em auto;
}
@ -810,3 +814,28 @@ table .buttons {
margin: 4em auto;
}
}
/** maps ***/
.leaflet-container {
width: 100%;
border-radius: var(--border-radius);
[role="button"].leaflet-marker-icon {
background: none;
border: none;
}
.leaflet-control {
a {
margin: 0;
padding: 0;
}
a:first-child {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
a:last-child {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
}

View File

@ -21,7 +21,7 @@
</ul>
{{ form }}
<div class="grid">
<div class="grid buttons">
<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>

View File

@ -17,7 +17,7 @@
<article>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<div class="grid">
<div class="grid buttons">
<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>

View File

@ -69,7 +69,7 @@
{{ field }}
{% endif %}
{% endfor %}
<div class="grid">
<div class="grid buttons">
<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>

View File

@ -40,7 +40,7 @@
<form method="post">{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<div class="grid">
<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="Enregistrer">
</div>

View File

@ -21,7 +21,7 @@
<form method="post">{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<div class="grid">
<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="Enregistrer">
</div>

View File

@ -21,7 +21,7 @@
<form method="post">
{% csrf_token %}
{{ form.as_grid }}
<div class="grid">
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% url 'fix_duplicate' object.pk %}{% endif %}" role="button" class="secondary">Annuler</a>
<input type="submit" value="Appliquer">
</div>

View File

@ -10,7 +10,7 @@
<p>Êtes-vous sûr·e de vouloir supprimer la réponse de modération #{{object.pk}} «&nbsp;{{ object.answer }}&nbsp;» associée à la question «&nbsp;{{ object.question.question }}&nbsp;»&nbsp;?
</p>
{{ form }}
<div class="grid">
<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>

View File

@ -21,7 +21,7 @@
<article>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<div class="grid">
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% url 'view_mquestion' question.pk %}{% endif %}" role="button" class="secondary">Annuler</a>
<input type="submit" value="Envoyer">
</div>

View File

@ -10,7 +10,7 @@
<p>Êtes-vous sûr·e de vouloir supprimer la question de modération #{{object.pk}} «&nbsp;{{ object.question }}&nbsp;» ainsi que les réponses associées&nbsp;?
</p>
{{ form }}
<div class="grid">
<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>

View File

@ -12,7 +12,7 @@
<article>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<div class="grid">
<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="Envoyer">
</div>

View File

@ -23,7 +23,7 @@
<h1>{{ title }}</h1>
</header>
{% include "agenda_culturel/static_content.html" with name=static_content url_path=url_path %}
</article>
</article>

View File

@ -0,0 +1,23 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}Supprimer {{ object.name }}{% endblock %}
{% block fluid %}{% endblock %}
{% block content %}
<article>
<header>
<h1>Suppression du lieu {{ object.name }}</h1>
</header>
<form method="post">{% csrf_token %}
<p>Êtes-vous sûr·e de vouloir supprimer le lieu «&nbsp;{{ object.name }} ({{ object.pk }})&nbsp;» situé à l'adresse {{ object.address }}, et de coordonnées {{ object.location }}&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>
</article>
{% endblock %}

View File

@ -0,0 +1,72 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}#{{ object.name }}{% endblock %}
{% load tag_extra %}
{% load utils_extra %}
{% load cat_extra %}
{% load static %}
{% block entete_header %}
{% css_categories %}
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script src="/static/admin/js/jquery.init.js"></script>
<script src="{% static 'location_field/leaflet/leaflet.js' %}"></script>
<link href="{% static 'location_field/leaflet/leaflet.css' %}" type="text/css" media="all" rel="stylesheet">
{% endblock %}
{% block fluid %}{% endblock %}
{% block content %}
<article>
<header>
{% if perms.agenda_culturel.change_place %}
<a href="{% url 'view_places' %}" role="button">&lt; Tous les lieux</a>
{% endif %}
<div class="slide-buttons">
{% if perms.agenda_culturel.change_place %}
<a href="{% url 'edit_place' place.pk %}" role="button">Modifier {% picto_from_name "edit-3" %}</a>
<a href="{% url 'delete_place' place.pk %}" role="button">Supprimer {% picto_from_name "trash-2" %}</a>
</div>
{% endif %}
<h1>{{ object.name }}</h1>
</header>
<div class="grid">
<div>
<ul>
<li><strong>Adresse&nbsp;:</strong> {{ object.address }}</li>
<li><strong>Coordonnée GPS&nbsp;:</strong> <a href="geo:{{ object.location }}">{{ object.location }}</a></li>
</ul>
{% if user.is_authenticated %}
{% if object.aliases|length > 0 %}
<p>Alias associés à ce lieu&nbsp;:</p>
<ul>
{% for alias in object.aliases %}
<li>{{ alias }}</li>
{% endfor %}
</ul>
{% else %}
<p><em>Ce lieu n'a pas d'alias défini</em></p>
{% endif %}
{% endif %}
</div>
<div>
<div id="map_location" style="width: 100%; aspect-ratio: 16/16"></div>
<script>
var map = L.map('map_location').setView([{{ object.location }}], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
var marker = L.marker([{{ object.location }}]).addTo(map);
</script>
</div>
</div>
<footer>
<!--p>Voir tous les événements de ce lieu</p-->
</footer>
</article>
{% endblock %}

View File

@ -0,0 +1,30 @@
{% extends "agenda_culturel/page.html" %}
{% load static %}
{% block title %}
{% if form.instance.pk %}Modification{% else %}Création{% endif %} d'un lieu
{% 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>
{{form.media}}
{% endblock %}
{% block content %}
<h1>{% if form.instance.pk %}Modification{% else %}Création{% endif %} d'un lieu</h1>
<article>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<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="Envoyer">
</div>
</form>
</article>
{% endblock %}

View File

@ -0,0 +1,67 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}Questions de modération{% endblock %}
{% load utils_extra %}
{% load cat_extra %}
{% block entete_header %}
{% css_categories %}
{% endblock %}
{% block content %}
<div class="grid two-columns">
<article>
<header>
<a class="slide-buttons" href="{% url 'add_place' %}" role="button">Ajouter {% picto_from_name "plus-circle" %}</a>
<h1>Lieux</h1>
</header>
{% if object_list %}
{% for place in object_list %}
<article>
<header>
<div class="slide-buttons">
<a href="{% url 'view_place' place.pk %}" role="button">Consulter {% picto_from_name "eye" %}</a>
<a href="{% url 'edit_place' place.pk %}" role="button">Modifier {% picto_from_name "edit-3" %}</a>
<a href="{% url 'delete_place' place.pk %}" role="button">Supprimer {% picto_from_name "trash-2" %}</a>
</div>
<h2>Lieu #{{ place.pk }}&nbsp;: {{ place.name }}</h2>
<ul>
<li><strong>Adresse&nbsp;:</strong> {{ place.address }}</li>
<li><strong>Coordonnée GPS&nbsp;:</strong> {{ place.location }}</li>
</ul>
{% if place.aliases|length > 0 %}
<p><strong>Alias&nbsp;:</strong> {% for alias in place.aliases %}{{ alias }}{% if not forloop.last %}, {% endif %}{% endfor %} </p>
{% else %}
<p><em>Ce lieu n'a pas d'alias défini</em></p>
{% endif %}
</header>
</article>
{% endfor %}
{% else %}
<p>Il n'y a aucun lieu défini.</p>
{% endif %}
<footer>
<span>
{% if page_obj.has_previous %}
<a href="?page=1" role="button">&laquo; premier</a>
<a href="?page={{ page_obj.previous_page_number }}" role="button">précédent</a>
{% endif %}
<span>
Page {{ page_obj.number }} sur {{ page_obj.paginator.num_pages }}
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}" role="button">suivant</a>
<a href="?page={{ page_obj.paginator.num_pages }}" role="button">dernier &raquo;</a>
{% endif %}
</span>
</footer>
</article>
{% include "agenda_culturel/side-nav.html" with current="places" %}
</div>
{% endblock %}

View File

@ -9,7 +9,7 @@
<form method="post">{% csrf_token %}
<p>Êtes-vous sûr·e de vouloir supprimer l'import récurrent «&nbsp;{{ object.name }} ({{ object.pk }})&nbsp;» correspondant à la source <a href="{{ object.source }}">{{ object.source }}</a>&nbsp;?</p>
{{ form }}
<div class="grid">
<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>

View File

@ -17,7 +17,7 @@
<article>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<div class="grid">
<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="Envoyer">
</div>

View File

@ -14,7 +14,7 @@
{{ form }}
<footer>
<div class="grid">
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% url 'recurrent_imports' %}{% endif %}" role="button" class="secondary">Annuler</a>
<input type="submit" value="Confirmer">
</div>

View File

@ -18,7 +18,7 @@
<form method="post">{% csrf_token %}
{{ form.as_p }}
<div class="grid">
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{{ event.get_absolute_url }}{% endif %}" role="button" class="secondary">Annuler</a>
<input type="submit" value="Marquer comme doublon">
</div>

View File

@ -18,7 +18,14 @@
<li><a {% if current == "tags" %}class="selected" {% endif %}href="{% url 'view_all_tags' %}">Consulter les étiquettes</a></li>
</ul>
</nav>
<h3>Lieux</h3>
<nav>
<ul>
{% if perms.agenda_culturel.change_place %}
<li><a {% if current == "places" %}class="selected" {% endif %}href="{% url 'view_places' %}">Liste des lieux</a></li>
{% endif %}
</ul>
</nav>
{% if perms.agenda_culturel.view_batchimportation or perms.agenda_culturel.view_recurrentimport or perms.agenda_culturel.view_categorisationrule%}
<h3>Traitements automatiques</h3>
<nav>

View File

@ -0,0 +1,12 @@
<div class="grid">
<div>
{{field_input}}
</div>
<div>
<div class="map-widget" style="margin-top: 4px">
<label></label>
<div id="map_{{field_name}}" style="width: 100%; aspect-ratio: 16/9"></div>
</div>
</div>
</div>

View File

@ -67,6 +67,11 @@ urlpatterns = [
path("mquestions/<int:qpk>/answers/<int:pk>/delete", ModerationAnswerDeleteView.as_view(), name="delete_manswer"),
path("404/", page_not_found, name="page_not_found"),
path("500/", internal_server_error, name="internal_server_error"),
path("place/<int:pk>", PlaceDetailView.as_view(), name="view_place"),
path("place/<int:pk>/edit", PlaceUpdateView.as_view(), name="edit_place"),
path("place/<int:pk>/delete", PlaceDeleteView.as_view(), name="delete_place"),
path("places/", PlaceListView.as_view(), name="view_places"),
path("places/add", PlaceCreateView.as_view(), name="add_place"),
]
if settings.DEBUG:

View File

@ -14,7 +14,7 @@ from collections import Counter
from .forms import EventSubmissionForm, EventForm, BatchImportationForm, FixDuplicates, SelectEventInList, MergeDuplicates, RecurrentImportForm, CategorisationRuleImportForm, ModerationQuestionForm, ModerationAnswerForm, ModerateForm, CategorisationForm
from .models import Event, Category, StaticContent, ContactMessage, BatchImportation, DuplicatedEvents, RecurrentImport, CategorisationRule, remove_accents, ModerationQuestion, ModerationAnswer
from .models import Event, Category, StaticContent, ContactMessage, BatchImportation, DuplicatedEvents, RecurrentImport, CategorisationRule, remove_accents, ModerationQuestion, ModerationAnswer, Place
from django.utils import timezone
from enum import StrEnum
from datetime import date, timedelta
@ -1073,3 +1073,30 @@ class ModerationAnswerUpdateView(PermissionRequiredMixin, UpdateView):
class ModerationAnswerDeleteView(PermissionRequiredMixin, DeleteView):
model = ModerationAnswer
permission_required = ("agenda_culturel.delete_answerquestion")
#########################
## Places
#########################
class PlaceListView(ListView):
model = Place
class PlaceDetailView(PermissionRequiredMixin, DetailView):
model = Place
permission_required = ("agenda_culturel.view_place")
class PlaceUpdateView(PermissionRequiredMixin, UpdateView):
model = Place
fields = '__all__'
permission_required = ("agenda_culturel.change_place")
class PlaceCreateView(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
model = Place
permission_required = ("agenda_culturel.add_place")
class PlaceDeleteView(PermissionRequiredMixin, DeleteView):
model = Place
permission_required = ("agenda_culturel.delete_place")

View File

@ -37,4 +37,4 @@ icalendar==5.0.11
lxml==5.1.0
bbcode==1.1.0
json5==0.9.25
django-location-field==2.7.3