From 18ca7200a0ea4003d3d8323e44d234bb1b348076 Mon Sep 17 00:00:00 2001 From: Jean-Marie Favreau Date: Sun, 10 Nov 2024 20:20:24 +0100 Subject: [PATCH] =?UTF-8?q?Am=C3=A9lioration=20de=20la=20gestion=20des=20d?= =?UTF-8?q?upliqu=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - beaucoup de bugs corrigés - stabilisation du fonctionnement général - amélioration des solutions de correction manuelles --- src/agenda_culturel/forms.py | 128 +++-- .../locale/fr/LC_MESSAGES/django.po | 455 +++++++++--------- src/agenda_culturel/models.py | 11 +- .../agenda_culturel/merge_duplicate.html | 6 +- .../agenda_culturel/update_duplicate.html | 32 ++ .../templatetags/event_extra.py | 2 +- src/agenda_culturel/urls.py | 1 + src/agenda_culturel/views.py | 80 ++- 8 files changed, 448 insertions(+), 267 deletions(-) create mode 100644 src/agenda_culturel/templates/agenda_culturel/update_duplicate.html diff --git a/src/agenda_culturel/forms.py b/src/agenda_culturel/forms.py index 814637b..e412872 100644 --- a/src/agenda_culturel/forms.py +++ b/src/agenda_culturel/forms.py @@ -25,6 +25,9 @@ from .models import ( Place, Category, ) +from django.conf import settings +from django.core.files import File + from django.utils.translation import gettext_lazy as _ from string import ascii_uppercase as auc from .templatetags.utils_extra import int_to_abc @@ -74,6 +77,8 @@ class CategorisationRuleImportForm(ModelForm): class EventForm(ModelForm): + old_local_image = CharField(widget=HiddenInput(), required=False) + class Meta: model = Event exclude = [ @@ -81,7 +86,7 @@ class EventForm(ModelForm): "modified_date", "moderated_date", "import_sources", - "uuids" + "image" ] widgets = { "start_day": TextInput( @@ -101,6 +106,7 @@ class EventForm(ModelForm): "end_day": TextInput(attrs={"type": "date"}), "end_time": TextInput(attrs={"type": "time"}), "other_versions": HiddenInput(), + "uuids": MultipleHiddenInput(), "reference_urls": DynamicArrayWidgetURLs(), "tags": DynamicArrayWidgetTags(), } @@ -144,6 +150,16 @@ class EventForm(ModelForm): return end_time + def clean(self): + super().clean() + + # when cloning an existing event, we need to copy the local image + if self.cleaned_data['local_image'] is None and not self.cleaned_data['old_local_image'] is None: + basename = self.cleaned_data['old_local_image'] + old = settings.MEDIA_ROOT + "/" + basename + self.cleaned_data['local_image'] = File(name=basename, file=open(old, "rb")) + + class BatchImportationForm(Form): json = CharField( @@ -224,13 +240,14 @@ class FixDuplicates(Form): return self.cleaned_data["action"].startswith("Remove") def get_selected_event_code(self): - if self.is_action_select() or self.is_action_remove(): + if self.is_action_select() or self.is_action_remove() or self.is_action_update(): return int(self.cleaned_data["action"].split("-")[-1]) else: return None def get_selected_event(self, edup): selected = self.get_selected_event_code() + logger.warning("selected " + str(selected)) for e in edup.get_duplicated(): if e.pk == selected: return e @@ -254,12 +271,21 @@ class MergeDuplicates(Form): def __init__(self, *args, **kwargs): self.duplicates = kwargs.pop("duplicates", None) - nb_events = self.duplicates.nb_duplicated() + self.event = kwargs.pop("event", None) + self.events = list(self.duplicates.get_duplicated()) + nb_events = len(self.events) super().__init__(*args, **kwargs) - choices = [ - ("event" + i, _("Value of event {}").format(i)) for i in auc[0:nb_events] - ] + + if self.event: + choices = [("event_" + str(self.event.pk), _("Value of the selected version"))] + \ + [ + ("event_" + str(e.pk), _("Value of version {}").format(e.pk)) for e in self.events if e != self.event + ] + else: + choices = [ + ("event_" + str(e.pk), _("Value of version {}").format(e.pk)) for e in self.events + ] for f in self.duplicates.get_items_comparison(): if not f["similar"]: @@ -274,7 +300,7 @@ class MergeDuplicates(Form): def as_grid(self): result = '
' - for i, e in enumerate(self.duplicates.get_duplicated()): + for i, e in enumerate(self.events): result += '
' result += '
' + int_to_abc(i) + "
" result += "
    " @@ -310,50 +336,82 @@ class MergeDuplicates(Form): ) else: result += "
    " + if key in self.errors: + result += '
      ' + for err in self.errors[key]: + result += "
    • " + err + "
    • " + result += "
    " result += '
    ' if hasattr(self, "cleaned_data"): checked = self.cleaned_data.get(key) else: checked = self.fields[key].initial - for i, (v, radio) in enumerate( - zip(e["values"], self.fields[e["key"]].choices) - ): - result += '
    ' - id = "id_" + key + "_" + str(i) - value = "event" + auc[i] - - result += '' - + int_to_abc(i) - + "
    " - + str(field_to_html(v, e["key"])) - + "
    " - ) + i = 0 + if self.event: + idx = self.events.index(self.event) + result += self.comparison_item(key, i, e["values"][idx], self.fields[e["key"]].choices[idx], self.event, checked) + i += 1 + + for (v, radio, ev) in zip(e["values"], self.fields[e["key"]].choices, self.events): + if self.event is None or ev != self.event: + result += self.comparison_item(key, i, v, radio, ev, checked) + i += 1 result += "
" return mark_safe(result) - def get_selected_events_id(self, key): + def comparison_item(self, key, i, v, radio, ev, checked): + result = '
' + id = "id_" + key + "_" + str(ev.pk) + value = "event_" + str(ev.pk) + + result += '' + + int_to_abc(i) + + "
") + result += "
" + if key == "image": + result += str(field_to_html(ev.local_image, "local_image")) + "
" + result += "
Lien d'import : " + + result += (str(field_to_html(v, key)) + "
") + result += "
" + return result + + + def get_selected_events(self, key): value = self.cleaned_data.get(key) if key not in self.fields: return None else: if isinstance(value, list): - return [auc.rfind(v[-1]) for v in value] + selected = [int(v.split("_")[-1]) for v in value] + result = [] + for s in selected: + for e in self.duplicates.get_duplicated(): + if e.pk == selected: + result.append(e) + break + return result else: - return auc.rfind(value[-1]) + selected = int(value.split("_")[-1]) + for e in self.duplicates.get_duplicated(): + if e.pk == selected: + return e + + return None class ModerationQuestionForm(ModelForm): diff --git a/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po b/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po index 8d65c36..16f4bc5 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-09 22:59+0100\n" +"POT-Creation-Date: 2024-11-10 20:19+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,88 +90,98 @@ msgstr "Après-midi" msgid "Evening" msgstr "Soir" -#: agenda_culturel/forms.py:44 agenda_culturel/models.py:165 -#: agenda_culturel/models.py:191 agenda_culturel/models.py:448 -#: agenda_culturel/models.py:1563 agenda_culturel/models.py:1668 +#: agenda_culturel/forms.py:47 agenda_culturel/models.py:165 +#: agenda_culturel/models.py:191 agenda_culturel/models.py:446 +#: agenda_culturel/models.py:1570 agenda_culturel/models.py:1675 msgid "Category" msgstr "Catégorie" -#: agenda_culturel/forms.py:47 +#: agenda_culturel/forms.py:50 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:126 +#: agenda_culturel/forms.py:132 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:142 +#: agenda_culturel/forms.py:148 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:152 +#: agenda_culturel/forms.py:168 msgid "JSON in the format expected for the import." msgstr "JSON dans le format attendu pour l'import" -#: agenda_culturel/forms.py:173 +#: agenda_culturel/forms.py:188 msgid " (locally modified version)" msgstr " (version modifiée localement)" -#: agenda_culturel/forms.py:176 +#: agenda_culturel/forms.py:191 msgid " (synchronized on import version)" msgstr " (version synchronisée sur l'import)" -#: agenda_culturel/forms.py:180 +#: agenda_culturel/forms.py:195 msgid "Select {} as representative version." msgstr "Sélectionner {} comme version représentative" -#: agenda_culturel/forms.py:185 +#: agenda_culturel/forms.py:204 +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:211 msgid " Warning: a version is already locally modified." msgstr " Attention: une version a déjà été modifiée localement." -#: agenda_culturel/forms.py:189 -msgid "Create a new version by merging." -msgstr "Créer une nouvelle version par fusion." +#: agenda_culturel/forms.py:216 +msgid "Create a new version by merging (interactive mode)." +msgstr "Créer une nouvelle version par fusion (mode interactif)." -#: agenda_culturel/forms.py:197 +#: agenda_culturel/forms.py:223 msgid "Make {} independent." msgstr "Rendre {} indépendant." -#: agenda_culturel/forms.py:199 +#: agenda_culturel/forms.py:225 msgid "Make all versions independent." msgstr "Rendre toutes les versions indépendantes." -#: agenda_culturel/forms.py:252 -msgid "Value of event {}" -msgstr "Valeur de l'événement {}" +#: agenda_culturel/forms.py:281 +msgid "Value of the selected version" +msgstr "Valeur de la version sélectionnée" -#: agenda_culturel/forms.py:407 +#: agenda_culturel/forms.py:283 agenda_culturel/forms.py:287 +msgid "Value of version {}" +msgstr "Valeur de la version {}" + +#: agenda_culturel/forms.py:474 msgid "Apply category {} to the event {}" msgstr "Appliquer la catégorie {} à l'événement {}" -#: agenda_culturel/forms.py:422 agenda_culturel/models.py:372 -#: agenda_culturel/models.py:1720 +#: agenda_culturel/forms.py:489 agenda_culturel/models.py:370 +#: agenda_culturel/models.py:1727 msgid "Place" msgstr "Lieu" -#: agenda_culturel/forms.py:424 +#: agenda_culturel/forms.py:491 msgid "Create a missing place" msgstr "Créer un lieu manquant" -#: agenda_culturel/forms.py:434 +#: agenda_culturel/forms.py:501 msgid "Add \"{}\" to the aliases of the place" msgstr "Ajouter « {} » aux alias du lieu" -#: agenda_culturel/forms.py:461 +#: agenda_culturel/forms.py:528 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 " "événements correspondants dont la place est manquante." #: agenda_culturel/models.py:49 agenda_culturel/models.py:94 -#: agenda_culturel/models.py:172 agenda_culturel/models.py:334 -#: agenda_culturel/models.py:351 agenda_culturel/models.py:1435 -#: agenda_culturel/models.py:1509 +#: agenda_culturel/models.py:172 agenda_culturel/models.py:332 +#: agenda_culturel/models.py:349 agenda_culturel/models.py:1442 +#: agenda_culturel/models.py:1516 msgid "Name" msgstr "Nom" @@ -231,7 +241,7 @@ msgstr "Catégories" msgid "Tag name" msgstr "Nom de l'étiquette" -#: agenda_culturel/models.py:177 agenda_culturel/models.py:501 +#: agenda_culturel/models.py:177 agenda_culturel/models.py:499 msgid "Description" msgstr "Description" @@ -269,51 +279,51 @@ msgstr "" msgid "Duplicated events" msgstr "Événements dupliqués" -#: agenda_culturel/models.py:334 +#: agenda_culturel/models.py:332 msgid "Name of the location" msgstr "Nom de la position" -#: agenda_culturel/models.py:337 +#: agenda_culturel/models.py:335 msgid "Main" msgstr "Principale" -#: agenda_culturel/models.py:338 +#: agenda_culturel/models.py:336 msgid "This location is one of the main locations (shown first)." msgstr "Cette position est une position principale (affichée en premier)." -#: agenda_culturel/models.py:343 +#: agenda_culturel/models.py:341 msgid "Reference location" msgstr "Position de référence" -#: agenda_culturel/models.py:344 +#: agenda_culturel/models.py:342 msgid "Reference locations" msgstr "Positions de référence" -#: agenda_culturel/models.py:351 +#: agenda_culturel/models.py:349 msgid "Name of the place" msgstr "Nom du lieu" -#: agenda_culturel/models.py:353 +#: agenda_culturel/models.py:351 msgid "Address" msgstr "Adresse" -#: agenda_culturel/models.py:354 +#: agenda_culturel/models.py:352 msgid "Address of this place (without city name)" msgstr "Adresse de ce lieu (sans le nom de la ville)" -#: agenda_culturel/models.py:358 +#: agenda_culturel/models.py:356 msgid "City" msgstr "Ville" -#: agenda_culturel/models.py:358 +#: agenda_culturel/models.py:356 msgid "City name" msgstr "Nom de la ville" -#: agenda_culturel/models.py:363 +#: agenda_culturel/models.py:361 msgid "Alternative names" msgstr "Noms alternatifs" -#: agenda_culturel/models.py:365 +#: agenda_culturel/models.py:363 msgid "" "Alternative names or addresses used to match a place with the free-form " "location of an event." @@ -321,77 +331,77 @@ 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:373 +#: agenda_culturel/models.py:371 msgid "Places" msgstr "Lieux" -#: agenda_culturel/models.py:426 agenda_culturel/models.py:1550 +#: agenda_culturel/models.py:424 agenda_culturel/models.py:1557 msgid "Published" msgstr "Publié" -#: agenda_culturel/models.py:427 +#: agenda_culturel/models.py:425 msgid "Draft" msgstr "Brouillon" -#: agenda_culturel/models.py:428 +#: agenda_culturel/models.py:426 msgid "Trash" msgstr "Corbeille" -#: agenda_culturel/models.py:439 +#: agenda_culturel/models.py:437 msgid "Title" msgstr "Titre" -#: agenda_culturel/models.py:439 +#: agenda_culturel/models.py:437 msgid "Short title" msgstr "Titre court" -#: agenda_culturel/models.py:443 agenda_culturel/models.py:1636 +#: agenda_culturel/models.py:441 agenda_culturel/models.py:1643 msgid "Status" msgstr "Status" -#: agenda_culturel/models.py:449 +#: agenda_culturel/models.py:447 msgid "Category of the event" msgstr "Catégorie de l'événement" -#: agenda_culturel/models.py:456 +#: agenda_culturel/models.py:454 msgid "Day of the event" msgstr "Date de l'événement" -#: agenda_culturel/models.py:459 agenda_culturel/models.py:460 +#: agenda_culturel/models.py:457 agenda_culturel/models.py:458 msgid "Starting time" msgstr "Heure de début" -#: agenda_culturel/models.py:466 +#: agenda_culturel/models.py:464 msgid "End day of the event" msgstr "Fin de l'événement" -#: agenda_culturel/models.py:468 +#: agenda_culturel/models.py:466 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:474 +#: agenda_culturel/models.py:472 msgid "Final time" msgstr "Heure de fin" -#: agenda_culturel/models.py:478 +#: agenda_culturel/models.py:476 msgid "Recurrence" msgstr "Récurrence" -#: agenda_culturel/models.py:483 agenda_culturel/models.py:1555 +#: agenda_culturel/models.py:481 agenda_culturel/models.py:1562 msgid "Location" msgstr "Localisation" -#: agenda_culturel/models.py:484 +#: agenda_culturel/models.py:482 msgid "Address of the event" msgstr "Adresse de l'événement" -#: agenda_culturel/models.py:490 +#: agenda_culturel/models.py:488 msgid "Location (free form)" msgstr "Localisation (forme libre)" -#: agenda_culturel/models.py:492 +#: agenda_culturel/models.py:490 msgid "" "Address of the event in case its not available in the already known places " "(free form)" @@ -399,211 +409,211 @@ 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:502 +#: agenda_culturel/models.py:500 msgid "General description of the event" msgstr "Description générale de l'événement" -#: agenda_culturel/models.py:508 +#: agenda_culturel/models.py:506 msgid "Illustration (local image)" msgstr "Illustration (image locale)" -#: agenda_culturel/models.py:509 +#: agenda_culturel/models.py:507 msgid "Illustration image stored in the agenda server" msgstr "Image d'illustration stockée sur le serveur de l'agenda" -#: agenda_culturel/models.py:516 +#: agenda_culturel/models.py:514 msgid "Illustration" msgstr "Illustration" -#: agenda_culturel/models.py:517 +#: agenda_culturel/models.py:515 msgid "URL of the illustration image" msgstr "URL de l'image illustrative" -#: agenda_culturel/models.py:523 +#: agenda_culturel/models.py:521 msgid "Illustration description" msgstr "Description de l'illustration" -#: agenda_culturel/models.py:524 +#: agenda_culturel/models.py:522 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:532 +#: agenda_culturel/models.py:530 msgid "Importation source" msgstr "Source d'importation" -#: agenda_culturel/models.py:533 +#: agenda_culturel/models.py:531 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:539 +#: agenda_culturel/models.py:537 msgid "UUIDs" msgstr "UUIDs" -#: agenda_culturel/models.py:540 +#: agenda_culturel/models.py:538 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:546 +#: agenda_culturel/models.py:544 msgid "URLs" msgstr "URLs" -#: agenda_culturel/models.py:547 +#: agenda_culturel/models.py:545 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:554 +#: agenda_culturel/models.py:552 msgid "Tags" msgstr "Étiquettes" -#: agenda_culturel/models.py:555 +#: agenda_culturel/models.py:553 msgid "A list of tags that describe the event." msgstr "Une liste d'étiquettes décrivant l'événement" -#: agenda_culturel/models.py:562 +#: agenda_culturel/models.py:560 msgid "Other versions" msgstr "" -#: agenda_culturel/models.py:627 +#: agenda_culturel/models.py:625 msgid "Event" msgstr "Événement" -#: agenda_culturel/models.py:628 +#: agenda_culturel/models.py:626 msgid "Events" msgstr "Événements" -#: agenda_culturel/models.py:1426 +#: agenda_culturel/models.py:1433 msgid "Contact message" msgstr "Message de contact" -#: agenda_culturel/models.py:1427 +#: agenda_culturel/models.py:1434 msgid "Contact messages" msgstr "Messages de contact" -#: agenda_culturel/models.py:1430 +#: agenda_culturel/models.py:1437 msgid "Subject" msgstr "Sujet" -#: agenda_culturel/models.py:1431 +#: agenda_culturel/models.py:1438 msgid "The subject of your message" msgstr "Sujet de votre message" -#: agenda_culturel/models.py:1436 +#: agenda_culturel/models.py:1443 msgid "Your name" msgstr "Votre nom" -#: agenda_culturel/models.py:1442 +#: agenda_culturel/models.py:1449 msgid "Email address" msgstr "Adresse email" -#: agenda_culturel/models.py:1443 +#: agenda_culturel/models.py:1450 msgid "Your email address" msgstr "Votre adresse email" -#: agenda_culturel/models.py:1448 +#: agenda_culturel/models.py:1455 msgid "Message" msgstr "Message" -#: agenda_culturel/models.py:1448 +#: agenda_culturel/models.py:1455 msgid "Your message" msgstr "Votre message" -#: agenda_culturel/models.py:1453 agenda_culturel/views.py:969 +#: agenda_culturel/models.py:1460 agenda_culturel/views.py:981 msgid "Spam" msgstr "Spam" -#: agenda_culturel/models.py:1454 +#: agenda_culturel/models.py:1461 msgid "This message is a spam." msgstr "Ce message est un spam." -#: agenda_culturel/models.py:1459 agenda_culturel/views.py:964 +#: agenda_culturel/models.py:1466 agenda_culturel/views.py:976 msgid "Closed" msgstr "Fermé" -#: agenda_culturel/models.py:1461 +#: agenda_culturel/models.py:1468 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:1466 +#: agenda_culturel/models.py:1473 msgid "Comments" msgstr "Commentaires" -#: agenda_culturel/models.py:1467 +#: agenda_culturel/models.py:1474 msgid "Comments on the message from the moderation team" msgstr "Commentaires sur ce message par l'équipe de modération" -#: agenda_culturel/models.py:1479 agenda_culturel/models.py:1616 +#: agenda_culturel/models.py:1486 agenda_culturel/models.py:1623 msgid "Recurrent import" msgstr "Import récurrent" -#: agenda_culturel/models.py:1480 +#: agenda_culturel/models.py:1487 msgid "Recurrent imports" msgstr "Imports récurrents" -#: agenda_culturel/models.py:1484 +#: agenda_culturel/models.py:1491 msgid "ical" msgstr "ical" -#: agenda_culturel/models.py:1485 +#: agenda_culturel/models.py:1492 msgid "ical no busy" msgstr "ical sans busy" -#: agenda_culturel/models.py:1486 +#: agenda_culturel/models.py:1493 msgid "ical no VC" msgstr "ical sans VC" -#: agenda_culturel/models.py:1487 +#: agenda_culturel/models.py:1494 msgid "lacoope.org" msgstr "lacoope.org" -#: agenda_culturel/models.py:1488 +#: agenda_culturel/models.py:1495 msgid "la comédie" msgstr "la comédie" -#: agenda_culturel/models.py:1489 +#: agenda_culturel/models.py:1496 msgid "le fotomat" msgstr "le fotomat" -#: agenda_culturel/models.py:1490 +#: agenda_culturel/models.py:1497 msgid "la puce à l'oreille" msgstr "la puce à loreille" -#: agenda_culturel/models.py:1491 +#: agenda_culturel/models.py:1498 msgid "Plugin wordpress MEC" msgstr "Plugin wordpress MEC" -#: agenda_culturel/models.py:1492 +#: agenda_culturel/models.py:1499 msgid "Événements d'une page FB" msgstr "Événements d'une page FB" -#: agenda_culturel/models.py:1493 +#: agenda_culturel/models.py:1500 msgid "la cour des 3 coquins" msgstr "la cour des 3 coquins" -#: agenda_culturel/models.py:1494 +#: agenda_culturel/models.py:1501 msgid "Arachnée concert" msgstr "Arachnée concert" -#: agenda_culturel/models.py:1497 +#: agenda_culturel/models.py:1504 msgid "simple" msgstr "simple" -#: agenda_culturel/models.py:1498 +#: agenda_culturel/models.py:1505 msgid "Headless Chromium" msgstr "chromium sans interface" -#: agenda_culturel/models.py:1499 +#: agenda_culturel/models.py:1506 msgid "Headless Chromium (pause)" msgstr "chromium sans interface (pause)" -#: agenda_culturel/models.py:1504 +#: agenda_culturel/models.py:1511 msgid "daily" msgstr "chaque jour" -#: agenda_culturel/models.py:1506 +#: agenda_culturel/models.py:1513 msgid "weekly" msgstr "chaque semaine" -#: agenda_culturel/models.py:1511 +#: agenda_culturel/models.py:1518 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." @@ -611,135 +621,135 @@ 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." -#: agenda_culturel/models.py:1518 +#: agenda_culturel/models.py:1525 msgid "Processor" msgstr "Processeur" -#: agenda_culturel/models.py:1521 +#: agenda_culturel/models.py:1528 msgid "Downloader" msgstr "Téléchargeur" -#: agenda_culturel/models.py:1528 +#: agenda_culturel/models.py:1535 msgid "Import recurrence" msgstr "Récurrence d'import" -#: agenda_culturel/models.py:1535 +#: agenda_culturel/models.py:1542 msgid "Source" msgstr "Source" -#: agenda_culturel/models.py:1536 +#: agenda_culturel/models.py:1543 msgid "URL of the source document" msgstr "URL du document source" -#: agenda_culturel/models.py:1540 +#: agenda_culturel/models.py:1547 msgid "Browsable url" msgstr "URL navigable" -#: agenda_culturel/models.py:1542 +#: agenda_culturel/models.py:1549 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:1551 +#: agenda_culturel/models.py:1558 msgid "Status of each imported event (published or draft)" msgstr "Status de chaque événement importé (publié ou brouillon)" -#: agenda_culturel/models.py:1556 +#: agenda_culturel/models.py:1563 msgid "Address for each imported event" msgstr "Adresse de chaque événement importé" -#: agenda_culturel/models.py:1564 +#: agenda_culturel/models.py:1571 msgid "Category of each imported event" msgstr "Catégorie de chaque événement importé" -#: agenda_culturel/models.py:1572 +#: agenda_culturel/models.py:1579 msgid "Tags for each imported event" msgstr "Étiquettes de chaque événement importé" -#: agenda_culturel/models.py:1573 +#: agenda_culturel/models.py:1580 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:1602 +#: agenda_culturel/models.py:1609 msgid "Running" msgstr "En cours" -#: agenda_culturel/models.py:1603 +#: agenda_culturel/models.py:1610 msgid "Canceled" msgstr "Annulé" -#: agenda_culturel/models.py:1604 +#: agenda_culturel/models.py:1611 msgid "Success" msgstr "Succès" -#: agenda_culturel/models.py:1605 +#: agenda_culturel/models.py:1612 msgid "Failed" msgstr "Erreur" -#: agenda_culturel/models.py:1608 +#: agenda_culturel/models.py:1615 msgid "Batch importation" msgstr "Importation par lot" -#: agenda_culturel/models.py:1609 +#: agenda_culturel/models.py:1616 msgid "Batch importations" msgstr "Importations par lot" -#: agenda_culturel/models.py:1617 +#: agenda_culturel/models.py:1624 msgid "Reference to the recurrent import processing" msgstr "Référence du processus d'import récurrent" -#: agenda_culturel/models.py:1625 +#: agenda_culturel/models.py:1632 msgid "URL (if not recurrent import)" msgstr "URL (si pas d'import récurrent)" -#: agenda_culturel/models.py:1627 +#: agenda_culturel/models.py:1634 msgid "Source URL if no RecurrentImport is associated." msgstr "URL source si aucun import récurrent n'est associé" -#: agenda_culturel/models.py:1640 +#: agenda_culturel/models.py:1647 msgid "Error message" msgstr "Votre message" -#: agenda_culturel/models.py:1644 +#: agenda_culturel/models.py:1651 msgid "Number of collected events" msgstr "Nombre d'événements collectés" -#: agenda_culturel/models.py:1647 +#: agenda_culturel/models.py:1654 msgid "Number of imported events" msgstr "Nombre d'événements importés" -#: agenda_culturel/models.py:1650 +#: agenda_culturel/models.py:1657 msgid "Number of updated events" msgstr "Nombre d'événements mis à jour" -#: agenda_culturel/models.py:1653 +#: agenda_culturel/models.py:1660 msgid "Number of removed events" msgstr "Nombre d'événements supprimés" -#: agenda_culturel/models.py:1661 +#: agenda_culturel/models.py:1668 msgid "Weight" msgstr "Poids" -#: agenda_culturel/models.py:1662 +#: agenda_culturel/models.py:1669 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:1669 +#: agenda_culturel/models.py:1676 msgid "Category applied to the event" msgstr "Catégorie appliquée à l'événement" -#: agenda_culturel/models.py:1674 +#: agenda_culturel/models.py:1681 msgid "Contained in the title" msgstr "Contenu dans le titre" -#: agenda_culturel/models.py:1675 +#: agenda_culturel/models.py:1682 msgid "Text contained in the event title" msgstr "Texte contenu dans le titre de l'événement" -#: agenda_culturel/models.py:1681 +#: agenda_culturel/models.py:1688 msgid "Exact title extract" msgstr "Extrait exact du titre" -#: agenda_culturel/models.py:1683 +#: agenda_culturel/models.py:1690 msgid "" "If checked, the extract will be searched for in the title using the exact " "form (capitals, accents)." @@ -747,19 +757,19 @@ msgstr "" "Si coché, l'extrait sera recherché dans le titre en utilisant la forme " "exacte (majuscules, accents)" -#: agenda_culturel/models.py:1689 +#: agenda_culturel/models.py:1696 msgid "Contained in the description" msgstr "Contenu dans la description" -#: agenda_culturel/models.py:1690 +#: agenda_culturel/models.py:1697 msgid "Text contained in the description" msgstr "Texte contenu dans la description" -#: agenda_culturel/models.py:1696 +#: agenda_culturel/models.py:1703 msgid "Exact description extract" msgstr "Extrait exact de description" -#: agenda_culturel/models.py:1698 +#: agenda_culturel/models.py:1705 msgid "" "If checked, the extract will be searched for in the description using the " "exact form (capitals, accents)." @@ -767,19 +777,19 @@ msgstr "" "Si coché, l'extrait sera recherché dans la description en utilisant la forme " "exacte (majuscules, accents)" -#: agenda_culturel/models.py:1704 +#: agenda_culturel/models.py:1711 msgid "Contained in the location" msgstr "Contenu dans la localisation" -#: agenda_culturel/models.py:1705 +#: agenda_culturel/models.py:1712 msgid "Text contained in the event location" msgstr "Texte contenu dans la localisation de l'événement" -#: agenda_culturel/models.py:1711 +#: agenda_culturel/models.py:1718 msgid "Exact location extract" msgstr "Extrait exact de localisation" -#: agenda_culturel/models.py:1713 +#: agenda_culturel/models.py:1720 msgid "" "If checked, the extract will be searched for in the location using the exact " "form (capitals, accents)." @@ -787,56 +797,56 @@ msgstr "" "Si coché, l'extrait sera recherché dans la localisation en utilisant la " "forme exacte (majuscules, accents)" -#: agenda_culturel/models.py:1721 +#: agenda_culturel/models.py:1728 msgid "Location from place" msgstr "Localisation depuis le lieu" -#: agenda_culturel/models.py:1730 +#: agenda_culturel/models.py:1737 msgid "Categorisation rule" msgstr "Règle de catégorisation" -#: agenda_culturel/models.py:1731 +#: agenda_culturel/models.py:1738 msgid "Categorisation rules" msgstr "Règles de catégorisation" -#: agenda_culturel/models.py:1802 agenda_culturel/models.py:1834 +#: agenda_culturel/models.py:1809 agenda_culturel/models.py:1841 msgid "Question" msgstr "Question" -#: agenda_culturel/models.py:1803 agenda_culturel/models.py:1841 +#: agenda_culturel/models.py:1810 agenda_culturel/models.py:1848 msgid "Text that will be shown to moderators" msgstr "Text tel que présenté aux modérateurices" -#: agenda_culturel/models.py:1809 +#: agenda_culturel/models.py:1816 msgid "Moderation question" msgstr "Question de modération" -#: agenda_culturel/models.py:1810 +#: agenda_culturel/models.py:1817 msgid "Moderation questions" msgstr "Questions de modération" -#: agenda_culturel/models.py:1835 +#: agenda_culturel/models.py:1842 msgid "Associated question from moderation" msgstr "Question associée pour la modération" -#: agenda_culturel/models.py:1840 +#: agenda_culturel/models.py:1847 msgid "Answer" msgstr "Réponse" -#: agenda_culturel/models.py:1847 +#: agenda_culturel/models.py:1854 msgid "Adds tags" msgstr "Ajoute les étiquettes" -#: agenda_culturel/models.py:1848 +#: agenda_culturel/models.py:1855 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:1854 +#: agenda_culturel/models.py:1861 msgid "Removes tags" msgstr "Retire les étiquettes" -#: agenda_culturel/models.py:1855 +#: agenda_culturel/models.py:1862 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." @@ -883,23 +893,23 @@ msgstr "" "La mise à jour de l'événement a été mise en attente et sera effectuée sous " "peu." -#: agenda_culturel/views.py:562 agenda_culturel/views.py:622 +#: agenda_culturel/views.py:562 agenda_culturel/views.py:635 msgid "The event has been successfully modified." msgstr "L'événement a été modifié avec succès." -#: agenda_culturel/views.py:591 +#: agenda_culturel/views.py:604 msgid "The event has been successfully deleted." msgstr "L'événement a été supprimé avec succès" -#: agenda_culturel/views.py:647 +#: agenda_culturel/views.py:660 msgid "The status has been successfully modified." msgstr "Le status a été modifié avec succès." -#: agenda_culturel/views.py:683 +#: agenda_culturel/views.py:696 msgid "The event was created: {}." msgstr "L'événement a été créé: {}." -#: agenda_culturel/views.py:685 agenda_culturel/views.py:700 +#: agenda_culturel/views.py:698 agenda_culturel/views.py:712 msgid "" "The event has been submitted and will be published as soon as it has been " "validated by the moderation team." @@ -907,105 +917,118 @@ 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:694 +#: agenda_culturel/views.py:706 msgid "The event is saved." msgstr "L'événement est enregistré." -#: agenda_culturel/views.py:786 agenda_culturel/views.py:838 +#: agenda_culturel/views.py:798 agenda_culturel/views.py:850 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:791 agenda_culturel/views.py:844 +#: agenda_culturel/views.py:803 agenda_culturel/views.py:856 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:801 +#: agenda_culturel/views.py:813 msgid "Integrating {} url(s) into our import process." msgstr "Intégration de {} url(s) dans notre processus d'import." -#: agenda_culturel/views.py:851 +#: agenda_culturel/views.py:863 msgid "Integrating {} into our import process." msgstr "Intégration de {} dans notre processus d'import." -#: agenda_culturel/views.py:924 +#: agenda_culturel/views.py:936 msgid "Your message has been sent successfully." msgstr "Votre message a été envoyé avec succès." -#: agenda_culturel/views.py:934 +#: agenda_culturel/views.py:946 msgid "The contact message has been successfully deleted." msgstr "Le message de contact a été supprimé avec succès." -#: agenda_culturel/views.py:948 +#: agenda_culturel/views.py:960 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:964 +#: agenda_culturel/views.py:976 msgid "Open" msgstr "Ouvert" -#: agenda_culturel/views.py:969 +#: agenda_culturel/views.py:981 msgid "Non spam" msgstr "Non spam" -#: agenda_culturel/views.py:1032 +#: agenda_culturel/views.py:1044 msgid "Spam has been successfully deleted." msgstr "Le spam a été supprimé avec succès" -#: agenda_culturel/views.py:1049 +#: agenda_culturel/views.py:1061 msgid "Search" msgstr "Rechercher" -#: agenda_culturel/views.py:1235 +#: agenda_culturel/views.py:1247 msgid "The import has been run successfully." msgstr "L'import a été lancé avec succès" -#: agenda_culturel/views.py:1254 +#: agenda_culturel/views.py:1266 msgid "The import has been canceled." msgstr "L'import a été annulé" -#: agenda_culturel/views.py:1328 +#: agenda_culturel/views.py:1340 msgid "The recurrent import has been successfully modified." msgstr "L'import récurrent a été modifié avec succès." -#: agenda_culturel/views.py:1337 +#: agenda_culturel/views.py:1349 msgid "The recurrent import has been successfully deleted." msgstr "L'import récurrent a été supprimé avec succès" -#: agenda_culturel/views.py:1377 +#: agenda_culturel/views.py:1389 msgid "The import has been launched." msgstr "L'import a été lancé" -#: agenda_culturel/views.py:1399 +#: agenda_culturel/views.py:1411 msgid "Imports has been launched." msgstr "Les imports ont été lancés" -#: agenda_culturel/views.py:1489 +#: agenda_culturel/views.py:1482 +msgid "Update successfully completed." +msgstr "Mise à jour réalisée avec succès." + +#: agenda_culturel/views.py:1540 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:1525 +#: agenda_culturel/views.py:1576 msgid "Events have been marked as unduplicated." msgstr "Les événements ont été marqués comme non dupliqués." -#: agenda_culturel/views.py:1539 +#: agenda_culturel/views.py:1590 agenda_culturel/views.py:1599 +#: agenda_culturel/views.py:1617 +msgid "" +"The selected item is no longer included in the list of duplicates. Someone " +"else has probably modified the list in the meantime." +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:1593 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:1550 +#: agenda_culturel/views.py:1608 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:1584 +#: agenda_culturel/views.py:1652 msgid "Cleaning up duplicates: {} item(s) fixed." msgstr "Nettoyage des dupliqués: {} élément(s) corrigé(s)." -#: agenda_culturel/views.py:1633 +#: agenda_culturel/views.py:1701 msgid "The event was successfully duplicated." msgstr "L'événement a été marqué dupliqué avec succès." -#: agenda_culturel/views.py:1641 +#: agenda_culturel/views.py:1709 msgid "" "The event has been successfully flagged as a duplicate. The moderation team " "will deal with your suggestion shortly." @@ -1013,32 +1036,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:1694 +#: agenda_culturel/views.py:1762 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:1703 +#: agenda_culturel/views.py:1771 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:1725 +#: agenda_culturel/views.py:1793 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:1732 +#: agenda_culturel/views.py:1800 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:1739 agenda_culturel/views.py:1792 +#: agenda_culturel/views.py:1807 agenda_culturel/views.py:1860 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:1778 +#: agenda_culturel/views.py:1846 msgid "" "The rules were successfully applied and 1 event with default category was " "categorised." @@ -1046,7 +1069,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:1785 +#: agenda_culturel/views.py:1853 msgid "" "The rules were successfully applied and {} events with default category were " "categorised." @@ -1054,46 +1077,46 @@ 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:1832 +#: agenda_culturel/views.py:1900 msgid "The moderation question has been created with success." msgstr "La question de modération a été créée avec succès." -#: agenda_culturel/views.py:1958 agenda_culturel/views.py:2020 -#: agenda_culturel/views.py:2058 +#: agenda_culturel/views.py:2026 agenda_culturel/views.py:2088 +#: agenda_culturel/views.py:2126 msgid "{} events have been updated." msgstr "{} événements ont été mis à jour." -#: agenda_culturel/views.py:1961 agenda_culturel/views.py:2022 -#: agenda_culturel/views.py:2061 +#: agenda_culturel/views.py:2029 agenda_culturel/views.py:2090 +#: agenda_culturel/views.py:2129 msgid "1 event has been updated." msgstr "1 événement a été mis à jour" -#: agenda_culturel/views.py:1963 agenda_culturel/views.py:2024 -#: agenda_culturel/views.py:2063 +#: agenda_culturel/views.py:2031 agenda_culturel/views.py:2092 +#: agenda_culturel/views.py:2131 msgid "No events have been modified." msgstr "Aucun événement n'a été modifié." -#: agenda_culturel/views.py:1972 +#: agenda_culturel/views.py:2040 msgid "The place has been successfully updated." msgstr "Le lieu a été modifié avec succès." -#: agenda_culturel/views.py:1981 +#: agenda_culturel/views.py:2049 msgid "The place has been successfully created." msgstr "Le lieu a été créé avec succès." -#: agenda_culturel/views.py:2046 +#: agenda_culturel/views.py:2114 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:2050 +#: agenda_culturel/views.py:2118 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:2106 +#: agenda_culturel/views.py:2174 msgid "The tag has been successfully updated." msgstr "L'étiquette a été modifiée avec succès." -#: agenda_culturel/views.py:2113 +#: agenda_culturel/views.py:2181 msgid "The tag has been successfully created." msgstr "L'étiquette a été créée avec succès." diff --git a/src/agenda_culturel/models.py b/src/agenda_culturel/models.py index 259081a..87b0d58 100644 --- a/src/agenda_culturel/models.py +++ b/src/agenda_culturel/models.py @@ -280,8 +280,6 @@ class DuplicatedEvents(models.Model): for e in events: if event is None: event = e - if e != event and e.same_uuid(event): - e.status = Event.STATUS.TRASH if not event is None: event.status = Event.STATUS.PUBLISHED self.representative = event @@ -1202,6 +1200,8 @@ class Event(models.Model): max_date = None uuids = set() + logger.warning("===================== 000") + # for each event, check if it's a new one, or a one to be updated for event in events: sdate = date.fromisoformat(event.start_day) @@ -1225,7 +1225,9 @@ class Event(models.Model): # check if the event has already be imported (using uuid) same_events = event.find_same_events_by_uuid() + logger.warning("===================== A") if len(same_events) != 0: + logger.warning("===================== B") # check if one event has been imported and not modified in this list same_imported = Event.find_last_pure_import(same_events) @@ -1233,15 +1235,18 @@ class Event(models.Model): if not same_imported: for e in same_events: if event.similar(e): + logger.warning("===================== C") same_imported = e break if same_imported: + logger.warning("===================== D") # reopen DuplicatedEvents if required if not event.similar(same_imported) and same_imported.other_versions: if same_imported.status != Event.STATUS.TRASH: if same_imported.other_versions.is_published(): if same_imported.other_versions.representative != same_imported: + logger.warning("===================== E") same_imported.other_versions.representative = None same_imported.other_versions.save() @@ -1250,6 +1255,7 @@ class Event(models.Model): same_imported.prepare_save() to_update.append(same_imported) else: + logger.warning("===================== F") # otherwise, the new event possibly a duplication of the remaining others. # check if it should be published @@ -1260,6 +1266,7 @@ class Event(models.Model): # it will be imported to_import.append(event) else: + logger.warning("===================== G") # if uuid is unique (or not available), check for similar events similar_events = event.find_similar_events() diff --git a/src/agenda_culturel/templates/agenda_culturel/merge_duplicate.html b/src/agenda_culturel/templates/agenda_culturel/merge_duplicate.html index 86289da..2bcdffc 100644 --- a/src/agenda_culturel/templates/agenda_culturel/merge_duplicate.html +++ b/src/agenda_culturel/templates/agenda_culturel/merge_duplicate.html @@ -3,7 +3,7 @@ {% load utils_extra %} {% load event_extra %} -{% block title %}{% block og_title %}Fusionner les événements dupliqués{% endblock %}{% endblock %} +{% block title %}{% block og_title %}Création d'une nouvelle version par fusion{% endblock %}{% endblock %} {% load cat_extra %} {% block entete_header %} @@ -13,9 +13,9 @@ {% block content %}
-

Fusionner les événements dupliqués

+

Création d'une nouvelle version par fusion

Pour chacun des champs non identiques, choisissez la version qui vous convient pour créer un événement - résultat de la fusion. Les événements source seront masqués.

+ résultat de la fusion. La version ainsi créée deviendra la version représentative.

diff --git a/src/agenda_culturel/templates/agenda_culturel/update_duplicate.html b/src/agenda_culturel/templates/agenda_culturel/update_duplicate.html new file mode 100644 index 0000000..de94b05 --- /dev/null +++ b/src/agenda_culturel/templates/agenda_culturel/update_duplicate.html @@ -0,0 +1,32 @@ +{% extends "agenda_culturel/page.html" %} + +{% load utils_extra %} +{% load event_extra %} + +{% block title %}{% block og_title %}Mise à jour par sélection de champs{% endblock %}{% endblock %} + +{% load cat_extra %} +{% block entete_header %} + {% css_categories %} +{% endblock %} + +{% block content %} +
+
+

Mise à jour par sélection de champs

+

Vous allez mettre à jour la version A en sélectionnant + pour chaque champ les valeurs des autres versions.

+

La version ainsi créée mise à jour deviendra la version représentative.

+ +
+ + {% csrf_token %} + {{ form.as_grid }} +
+ Annuler + +
+ +
+{% endblock %} + diff --git a/src/agenda_culturel/templatetags/event_extra.py b/src/agenda_culturel/templatetags/event_extra.py index d2e0a78..db22ed4 100644 --- a/src/agenda_culturel/templatetags/event_extra.py +++ b/src/agenda_culturel/templatetags/event_extra.py @@ -120,7 +120,7 @@ def field_to_html(field, key): return mark_safe('' + field + "") elif key == "local_image": if field: - return mark_safe('') + return mark_safe('') else: return "-" else: diff --git a/src/agenda_culturel/urls.py b/src/agenda_culturel/urls.py index 90fad48..758a773 100644 --- a/src/agenda_culturel/urls.py +++ b/src/agenda_culturel/urls.py @@ -120,6 +120,7 @@ urlpatterns = [ ), path("duplicates//fix", fix_duplicate, name="fix_duplicate"), path("duplicates//merge", merge_duplicate, name="merge_duplicate"), + path("duplicates//update/", update_duplicate_event, name="update_event"), path("mquestions/", ModerationQuestionListView.as_view(), name="view_mquestions"), path( "mquestions/add", ModerationQuestionCreateView.as_view(), name="add_mquestion" diff --git a/src/agenda_culturel/views.py b/src/agenda_culturel/views.py index b11b0b0..7f663f3 100644 --- a/src/agenda_culturel/views.py +++ b/src/agenda_culturel/views.py @@ -579,9 +579,22 @@ class EventUpdateView( obj.set_no_modification_date_changed() obj.save() result["other_versions"] = obj.other_versions + if obj.local_image: + result["old_local_image"] = obj.local_image.name return result + def form_valid(self, form): + original = self.get_object() + # if an image is uploaded, it removes the url stored + if form.cleaned_data['local_image'] != original.local_image: + form.instance.image = None + + form.instance.import_sources = None + + return super().form_valid(form) + + class EventDeleteView( SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, DeleteView ): @@ -685,7 +698,6 @@ class EventCreateView(SuccessMessageMixin, CreateView): return _("The event has been submitted and will be published as soon as it has been validated by the moderation team.") - def import_from_details(request): form = EventForm(request.POST, is_authenticated=request.user.is_authenticated) if form.is_valid(): @@ -780,7 +792,7 @@ def import_from_urls(request): # for each not new, add a message for uc in ucat: if uc.exists() and not uc.is_new(): - if uc.is_event_visible(): # TODO + if uc.is_event_visible(): messages.info( request, mark_safe(_('{} has not been submitted since it''s already known: {}.').format(uc.url, uc.get_link())) @@ -1429,6 +1441,54 @@ class DuplicatedEventsDetailView(LoginRequiredMixin, DetailView): template_name = "agenda_culturel/duplicate.html" +@login_required(login_url="/accounts/login/") +@permission_required( + ["agenda_culturel.change_event", "agenda_culturel.change_duplicatedevents"] +) +def update_duplicate_event(request, pk, epk): + edup = get_object_or_404(DuplicatedEvents, pk=pk) + event = get_object_or_404(Event, pk=epk) + + form = MergeDuplicates(duplicates=edup, event=event) + + if request.method == "POST": + form = MergeDuplicates(request.POST, duplicates=edup) + if form.is_valid(): + events = edup.get_duplicated() + + for f in edup.get_items_comparison(): + if not f["similar"]: + selected = form.get_selected_events(f["key"]) + if not selected is None: + if isinstance(selected, list): + values = [ + x + for x in [getattr(s, f["key"]) for s in selected] + if x is not None + ] + if len(values) != 0: + if isinstance(values[0], str): + setattr(event, f["key"], "\n".join(values)) + else: + setattr(event, f["key"], sum(values, [])) + else: + setattr(event, f["key"], getattr(selected, f["key"])) + if f["key"] == "image": + setattr(event, "local_image", getattr(selected, "local_image")) + + event.other_versions.fix(event) + event.save() + + messages.info(request, _("Update successfully completed.")) + return HttpResponseRedirect(event.get_absolute_url()) + + return render( + request, + "agenda_culturel/update_duplicate.html", + context={"form": form, "object": edup, "event": event}, + ) + + @login_required(login_url="/accounts/login/") @permission_required( ["agenda_culturel.change_event", "agenda_culturel.change_duplicatedevents"] @@ -1448,13 +1508,13 @@ def merge_duplicate(request, pk): if f["similar"]: new_event_data[f["key"]] = getattr(events[0], f["key"]) else: - selected = form.get_selected_events_id(f["key"]) + selected = form.get_selected_events(f["key"]) if selected is None: new_event_data[f["key"]] = None elif isinstance(selected, list): values = [ x - for x in [getattr(events[s], f["key"]) for s in selected] + for x in [getattr(s, f["key"]) for s in selected] if x is not None ] if len(values) == 0: @@ -1465,16 +1525,16 @@ def merge_duplicate(request, pk): else: new_event_data[f["key"]] = sum(values, []) else: - new_event_data[f["key"]] = getattr(events[selected], f["key"]) - # local_image field follows image field + new_event_data[f["key"]] = getattr(selected, f["key"]) if f["key"] == "image" and "local_image" not in new_event_data: - new_event_data["local_image"] = getattr(events[selected], "local_image") + new_event_data["local_image"] = getattr(selected, "local_image") # create a new event that merge the selected events new_event = Event(**new_event_data) new_event.status = Event.STATUS.PUBLISHED new_event.other_versions = edup + new_event.save() edup.fix(new_event) messages.info(request, _("Creation of a merged event has been successfully completed.")) @@ -1535,7 +1595,7 @@ def fix_duplicate(request, pk): elif form.is_action_remove(): # one element is removed from the set event = form.get_selected_event(edup) - if selected is None: + if event is None: messages.error(request, _("The selected item is no longer included in the list of duplicates. Someone else has probably modified the list in the meantime.")) return HttpResponseRedirect(edup.get_absolute_url()) else: @@ -1553,12 +1613,12 @@ def fix_duplicate(request, pk): elif form.is_action_update(): # otherwise, a new event will be created using a merging process event = form.get_selected_event(edup) - if selected is None: + if event is None: messages.error(request, _("The selected item is no longer included in the list of duplicates. Someone else has probably modified the list in the meantime.")) return HttpResponseRedirect(edup.get_absolute_url()) else: return HttpResponseRedirect( - reverse_lazy("update_event", args=[edup.ok, event.pk]) + reverse_lazy("update_event", args=[edup.pk, event.pk]) ) else: # otherwise, a new event will be created using a merging process