Séparation des vues event dupliqués
This commit is contained in:
		@@ -26,6 +26,13 @@ from .views import (
 | 
			
		||||
    # Errors
 | 
			
		||||
    internal_server_error,
 | 
			
		||||
    page_not_found,
 | 
			
		||||
    # Event duplicates
 | 
			
		||||
    DuplicatedEventsDetailView,
 | 
			
		||||
    duplicates,
 | 
			
		||||
    fix_duplicate,
 | 
			
		||||
    merge_duplicate,
 | 
			
		||||
    set_duplicate,
 | 
			
		||||
    update_duplicate_event,
 | 
			
		||||
    # General pages
 | 
			
		||||
    about,
 | 
			
		||||
    import_requirements,
 | 
			
		||||
@@ -88,18 +95,14 @@ from .views import (
 | 
			
		||||
    recent,
 | 
			
		||||
    administration,
 | 
			
		||||
    activite,
 | 
			
		||||
    fix_duplicate,
 | 
			
		||||
    clear_cache,
 | 
			
		||||
    export_event_ical,
 | 
			
		||||
    MessageDeleteView,
 | 
			
		||||
    EventDetailView,
 | 
			
		||||
    EventUpdateView,
 | 
			
		||||
    duplicates,
 | 
			
		||||
    DuplicatedEventsDetailView,
 | 
			
		||||
    StaticContentCreateView,
 | 
			
		||||
    StaticContentUpdateView,
 | 
			
		||||
    MessageCreateView,
 | 
			
		||||
    merge_duplicate,
 | 
			
		||||
    EventCreateView,
 | 
			
		||||
    event_search,
 | 
			
		||||
    event_search_full,
 | 
			
		||||
@@ -107,14 +110,12 @@ from .views import (
 | 
			
		||||
    update_from_source,
 | 
			
		||||
    change_status_event,
 | 
			
		||||
    EventDeleteView,
 | 
			
		||||
    set_duplicate,
 | 
			
		||||
    import_event_proxy,
 | 
			
		||||
    import_from_url,
 | 
			
		||||
    import_from_urls,
 | 
			
		||||
    view_messages,
 | 
			
		||||
    MessageUpdateView,
 | 
			
		||||
    statistics,
 | 
			
		||||
    update_duplicate_event,
 | 
			
		||||
    UserProfileUpdateView,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -167,6 +168,25 @@ urlpatterns = [
 | 
			
		||||
    # Errors
 | 
			
		||||
    path("500/", internal_server_error, name="internal_server_error"),
 | 
			
		||||
    path("404/", page_not_found, name="page_not_found"),
 | 
			
		||||
    path("duplicates/<int:pk>/merge", merge_duplicate, name="merge_duplicate"),
 | 
			
		||||
    path(
 | 
			
		||||
        "event/<int:year>/<int:month>/<int:day>/<int:pk>/set_duplicate",
 | 
			
		||||
        set_duplicate,
 | 
			
		||||
        name="set_duplicate",
 | 
			
		||||
    ),
 | 
			
		||||
    path(
 | 
			
		||||
        "duplicates/<int:pk>/update/<int:epk>",
 | 
			
		||||
        update_duplicate_event,
 | 
			
		||||
        name="update_event",
 | 
			
		||||
    ),
 | 
			
		||||
    # Event duplicates
 | 
			
		||||
    path(
 | 
			
		||||
        "duplicates/<int:pk>",
 | 
			
		||||
        DuplicatedEventsDetailView.as_view(),
 | 
			
		||||
        name="view_duplicate",
 | 
			
		||||
    ),
 | 
			
		||||
    path("duplicates/", duplicates, name="duplicates"),
 | 
			
		||||
    path("duplicates/<int:pk>/fix", fix_duplicate, name="fix_duplicate"),
 | 
			
		||||
    # General pages
 | 
			
		||||
    path("a-propos", about, name="about"),
 | 
			
		||||
    path("besoin-pour-import", import_requirements, name="import_requirements"),
 | 
			
		||||
@@ -424,11 +444,6 @@ urlpatterns = [
 | 
			
		||||
        name="change_status_event",
 | 
			
		||||
    ),
 | 
			
		||||
    path("event/<int:pk>/delete", EventDeleteView.as_view(), name="delete_event"),
 | 
			
		||||
    path(
 | 
			
		||||
        "event/<int:year>/<int:month>/<int:day>/<int:pk>/set_duplicate",
 | 
			
		||||
        set_duplicate,
 | 
			
		||||
        name="set_duplicate",
 | 
			
		||||
    ),
 | 
			
		||||
    path("ajouter", import_event_proxy, name="add_event"),
 | 
			
		||||
    path("ajouter/url", import_from_url, name="add_event_url"),
 | 
			
		||||
    path("ajouter/urls", import_from_urls, name="add_event_urls"),
 | 
			
		||||
@@ -463,19 +478,6 @@ urlpatterns = [
 | 
			
		||||
        name="delete_message",
 | 
			
		||||
    ),
 | 
			
		||||
    path("rimports/<int:pk>/stats", statistics, name="stats_rimport"),
 | 
			
		||||
    path("duplicates/", duplicates, name="duplicates"),
 | 
			
		||||
    path(
 | 
			
		||||
        "duplicates/<int:pk>",
 | 
			
		||||
        DuplicatedEventsDetailView.as_view(),
 | 
			
		||||
        name="view_duplicate",
 | 
			
		||||
    ),
 | 
			
		||||
    path("duplicates/<int:pk>/fix", fix_duplicate, name="fix_duplicate"),
 | 
			
		||||
    path("duplicates/<int:pk>/merge", merge_duplicate, name="merge_duplicate"),
 | 
			
		||||
    path(
 | 
			
		||||
        "duplicates/<int:pk>/update/<int:epk>",
 | 
			
		||||
        update_duplicate_event,
 | 
			
		||||
        name="update_event",
 | 
			
		||||
    ),
 | 
			
		||||
    path(
 | 
			
		||||
        "organisme/<int:organisation_pk>/ical",
 | 
			
		||||
        export_ical,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
from .oldviews import *
 | 
			
		||||
from .categorisation_rules_view import *
 | 
			
		||||
from .event_duplicate_views import *
 | 
			
		||||
from .errors import *
 | 
			
		||||
from .general_pages_views import *
 | 
			
		||||
from .import_batch_views import *
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										344
									
								
								src/agenda_culturel/views/event_duplicate_views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								src/agenda_culturel/views/event_duplicate_views.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,344 @@
 | 
			
		||||
from datetime import date
 | 
			
		||||
 | 
			
		||||
from django.contrib import messages
 | 
			
		||||
from django.contrib.auth.decorators import login_required, permission_required
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.core.paginator import PageNotAnInteger, EmptyPage
 | 
			
		||||
from django.http import HttpResponseRedirect
 | 
			
		||||
from django.shortcuts import get_object_or_404, render
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django.views.generic import DetailView, UpdateView
 | 
			
		||||
 | 
			
		||||
from src.agenda_culturel.calendar import CalendarDay
 | 
			
		||||
from src.agenda_culturel.filters import DuplicatedEventsFilter
 | 
			
		||||
from src.agenda_culturel.forms import MergeDuplicates, FixDuplicates, SelectEventInList
 | 
			
		||||
from src.agenda_culturel.models import DuplicatedEvents, Event
 | 
			
		||||
from src.agenda_culturel.views import PaginatorFilter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DuplicatedEventsDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = DuplicatedEvents
 | 
			
		||||
    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():
 | 
			
		||||
            for f in edup.get_items_comparison():
 | 
			
		||||
                if not f["similar"]:
 | 
			
		||||
                    selected = form.get_selected_events(f["key"])
 | 
			
		||||
                    if selected is not 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:
 | 
			
		||||
                            if f["key"] == "organisers":
 | 
			
		||||
                                event.organisers.set(selected.organisers.all())
 | 
			
		||||
                            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_id": edup.get_event_index(event),
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required(login_url="/accounts/login/")
 | 
			
		||||
@permission_required(
 | 
			
		||||
    ["agenda_culturel.change_event", "agenda_culturel.change_duplicatedevents"]
 | 
			
		||||
)
 | 
			
		||||
def merge_duplicate(request, pk):
 | 
			
		||||
    edup = get_object_or_404(DuplicatedEvents, pk=pk)
 | 
			
		||||
    form = MergeDuplicates(duplicates=edup)
 | 
			
		||||
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = MergeDuplicates(request.POST, duplicates=edup)
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            events = edup.get_duplicated()
 | 
			
		||||
 | 
			
		||||
            # build fields for the new event
 | 
			
		||||
            new_event_data = {}
 | 
			
		||||
            for f in edup.get_items_comparison():
 | 
			
		||||
                if f["similar"]:
 | 
			
		||||
                    new_event_data[f["key"]] = getattr(events[0], f["key"])
 | 
			
		||||
                else:
 | 
			
		||||
                    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(s, f["key"]) for s in selected]
 | 
			
		||||
                            if x is not None
 | 
			
		||||
                        ]
 | 
			
		||||
                        if len(values) == 0:
 | 
			
		||||
                            new_event_data[f["key"]] = None
 | 
			
		||||
                        else:
 | 
			
		||||
                            if isinstance(values[0], str):
 | 
			
		||||
                                new_event_data[f["key"]] = "\n".join(values)
 | 
			
		||||
                            else:
 | 
			
		||||
                                new_event_data[f["key"]] = sum(values, [])
 | 
			
		||||
                    else:
 | 
			
		||||
                        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(
 | 
			
		||||
                                selected, "local_image"
 | 
			
		||||
                            )
 | 
			
		||||
 | 
			
		||||
            organisers = new_event_data.pop("organisers", None)
 | 
			
		||||
            # 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()
 | 
			
		||||
            if organisers is not None:
 | 
			
		||||
                new_event.organisers.set(organisers.all())
 | 
			
		||||
            edup.fix(new_event)
 | 
			
		||||
 | 
			
		||||
            messages.info(
 | 
			
		||||
                request,
 | 
			
		||||
                _("Creation of a merged event has been successfully completed."),
 | 
			
		||||
            )
 | 
			
		||||
            return HttpResponseRedirect(new_event.get_absolute_url())
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/merge_duplicate.html",
 | 
			
		||||
        context={"form": form, "object": edup},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required(login_url="/accounts/login/")
 | 
			
		||||
@permission_required(
 | 
			
		||||
    ["agenda_culturel.change_event", "agenda_culturel.change_duplicatedevents"]
 | 
			
		||||
)
 | 
			
		||||
def fix_duplicate(request, pk):
 | 
			
		||||
    edup = get_object_or_404(DuplicatedEvents.objects.select_related(), pk=pk)
 | 
			
		||||
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = FixDuplicates(request.POST, edup=edup)
 | 
			
		||||
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            if form.is_action_no_duplicates():
 | 
			
		||||
                # all events are different
 | 
			
		||||
                events = edup.get_duplicated()
 | 
			
		||||
 | 
			
		||||
                # get redirection date
 | 
			
		||||
                if len(events) == 0:
 | 
			
		||||
                    date = None
 | 
			
		||||
                else:
 | 
			
		||||
                    s_events = [e for e in events if not e.has_recurrences()]
 | 
			
		||||
                    if len(s_events) != 0:
 | 
			
		||||
                        s_event = s_events[0]
 | 
			
		||||
                    else:
 | 
			
		||||
                        s_event = events[0]
 | 
			
		||||
                    date = s_event.start_day
 | 
			
		||||
 | 
			
		||||
                messages.success(request, _("Events have been marked as unduplicated."))
 | 
			
		||||
                # delete the duplicated event (other_versions will be set to None on all events)
 | 
			
		||||
                edup.delete()
 | 
			
		||||
                if date is None:
 | 
			
		||||
                    return HttpResponseRedirect(reverse_lazy("home"))
 | 
			
		||||
                else:
 | 
			
		||||
                    return HttpResponseRedirect(
 | 
			
		||||
                        reverse_lazy("day_view", args=[date.year, date.month, date.day])
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
            elif form.is_action_select():
 | 
			
		||||
                # one element has been selected to be the representative
 | 
			
		||||
                selected = form.get_selected_event(edup)
 | 
			
		||||
                if selected 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."
 | 
			
		||||
                        ),
 | 
			
		||||
                    )
 | 
			
		||||
                else:
 | 
			
		||||
                    edup.fix(selected)
 | 
			
		||||
                    messages.success(
 | 
			
		||||
                        request,
 | 
			
		||||
                        _("The selected event has been set as representative"),
 | 
			
		||||
                    )
 | 
			
		||||
                return HttpResponseRedirect(edup.get_absolute_url())
 | 
			
		||||
            elif form.is_action_remove():
 | 
			
		||||
                # one element is removed from the set
 | 
			
		||||
                event = form.get_selected_event(edup)
 | 
			
		||||
                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:
 | 
			
		||||
                    event.other_versions = None
 | 
			
		||||
                    if edup.representative == event:
 | 
			
		||||
                        edup.representative = None
 | 
			
		||||
                    event.set_no_modification_date_changed()
 | 
			
		||||
                    event.save()
 | 
			
		||||
                    edup.save()
 | 
			
		||||
                    edup.events = [e for e in edup.events if e.pk != event.pk]
 | 
			
		||||
                    messages.success(
 | 
			
		||||
                        request,
 | 
			
		||||
                        _(
 | 
			
		||||
                            "The event has been withdrawn from the group and made independent."
 | 
			
		||||
                        ),
 | 
			
		||||
                    )
 | 
			
		||||
                    if edup.nb_duplicated() == 1:
 | 
			
		||||
                        return HttpResponseRedirect(edup.get_absolute_url())
 | 
			
		||||
                    else:
 | 
			
		||||
                        form = FixDuplicates(edup=edup)
 | 
			
		||||
            elif form.is_action_update():
 | 
			
		||||
                # otherwise, an event will be updated using other elements
 | 
			
		||||
                event = form.get_selected_event(edup)
 | 
			
		||||
                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.pk, event.pk])
 | 
			
		||||
                    )
 | 
			
		||||
            else:
 | 
			
		||||
                # otherwise, a new event will be created using a merging process
 | 
			
		||||
                return HttpResponseRedirect(
 | 
			
		||||
                    reverse_lazy("merge_duplicate", args=[edup.pk])
 | 
			
		||||
                )
 | 
			
		||||
    else:
 | 
			
		||||
        form = FixDuplicates(edup=edup)
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/fix_duplicate.html",
 | 
			
		||||
        context={"form": form, "object": edup},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DuplicatedEventsUpdateView(
 | 
			
		||||
    LoginRequiredMixin, UpdateView
 | 
			
		||||
):  # Todo à supprimer, pas d’utilisation ?
 | 
			
		||||
    model = DuplicatedEvents
 | 
			
		||||
    fields = ()
 | 
			
		||||
    template_name = "agenda_culturel/fix_duplicate.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required(login_url="/accounts/login/")
 | 
			
		||||
@permission_required("agenda_culturel.view_duplicatedevents")
 | 
			
		||||
def duplicates(request):
 | 
			
		||||
    nb_removed = DuplicatedEvents.remove_singletons()
 | 
			
		||||
    if nb_removed > 0:
 | 
			
		||||
        messages.success(
 | 
			
		||||
            request,
 | 
			
		||||
            _("Cleaning up duplicates: {} item(s) fixed.").format(nb_removed),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    filter = DuplicatedEventsFilter(
 | 
			
		||||
        request.GET, queryset=DuplicatedEvents.objects.all().order_by("-pk")
 | 
			
		||||
    )
 | 
			
		||||
    paginator = PaginatorFilter(filter, 10, request)
 | 
			
		||||
    page = request.GET.get("page")
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        response = paginator.page(page)
 | 
			
		||||
    except PageNotAnInteger:
 | 
			
		||||
        response = paginator.page(1)
 | 
			
		||||
    except EmptyPage:
 | 
			
		||||
        response = paginator.page(paginator.num_pages)
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/duplicates.html",
 | 
			
		||||
        {
 | 
			
		||||
            "filter": filter,
 | 
			
		||||
            "paginator_filter": response,
 | 
			
		||||
            "paginator": paginator,
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_duplicate(request, year, month, day, pk):
 | 
			
		||||
    event = get_object_or_404(Event, pk=pk)
 | 
			
		||||
    cday = CalendarDay(date(year, month, day))
 | 
			
		||||
    others = [
 | 
			
		||||
        e
 | 
			
		||||
        for e in cday.get_events()
 | 
			
		||||
        if e != event
 | 
			
		||||
        and (event.other_versions is None or event.other_versions != e.other_versions)
 | 
			
		||||
        and e.status != Event.STATUS.TRASH
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    form = SelectEventInList(events=others)
 | 
			
		||||
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = SelectEventInList(request.POST, events=others)
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            selected = [o for o in others if o.pk == int(form.cleaned_data["event"])]
 | 
			
		||||
            event.set_other_versions(selected)
 | 
			
		||||
            # save them without updating modified date
 | 
			
		||||
            event.set_no_modification_date_changed()
 | 
			
		||||
            event.save()
 | 
			
		||||
            if request.user.is_authenticated:
 | 
			
		||||
                messages.success(request, _("The event was successfully duplicated."))
 | 
			
		||||
                return HttpResponseRedirect(
 | 
			
		||||
                    reverse_lazy("view_duplicate", args=[event.other_versions.pk])
 | 
			
		||||
                )
 | 
			
		||||
            else:
 | 
			
		||||
                messages.info(
 | 
			
		||||
                    request,
 | 
			
		||||
                    _(
 | 
			
		||||
                        "The event has been successfully flagged as a duplicate. The moderation team will deal with your suggestion shortly."
 | 
			
		||||
                    ),
 | 
			
		||||
                )
 | 
			
		||||
                return HttpResponseRedirect(event.get_absolute_url())
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/set_duplicate.html",
 | 
			
		||||
        context={"form": form, "event": event},
 | 
			
		||||
    )
 | 
			
		||||
@@ -42,13 +42,12 @@ from django.views.generic.edit import (
 | 
			
		||||
from honeypot.decorators import check_honeypot
 | 
			
		||||
 | 
			
		||||
from .utils import get_event_qs
 | 
			
		||||
from ..calendar import CalendarDay, CalendarList, CalendarMonth, CalendarWeek
 | 
			
		||||
from ..calendar import CalendarList, CalendarMonth, CalendarWeek
 | 
			
		||||
from ..celery import (
 | 
			
		||||
    import_events_from_url,
 | 
			
		||||
    import_events_from_urls,
 | 
			
		||||
)
 | 
			
		||||
from ..filters import (
 | 
			
		||||
    DuplicatedEventsFilter,
 | 
			
		||||
    EventFilter,
 | 
			
		||||
    EventFilterAdmin,
 | 
			
		||||
    MessagesFilterAdmin,
 | 
			
		||||
@@ -58,11 +57,8 @@ from ..filters import (
 | 
			
		||||
from ..forms import (
 | 
			
		||||
    EventForm,
 | 
			
		||||
    EventFormWithContact,
 | 
			
		||||
    FixDuplicates,
 | 
			
		||||
    MergeDuplicates,
 | 
			
		||||
    MessageEventForm,
 | 
			
		||||
    MessageForm,
 | 
			
		||||
    SelectEventInList,
 | 
			
		||||
    SimpleContactForm,
 | 
			
		||||
    URLSubmissionFormSet,
 | 
			
		||||
    URLSubmissionFormWithContact,
 | 
			
		||||
@@ -1293,336 +1289,6 @@ def event_search_full(request):
 | 
			
		||||
    return event_search(request, True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#########################
 | 
			
		||||
##   duplicated events
 | 
			
		||||
#########################
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DuplicatedEventsDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = DuplicatedEvents
 | 
			
		||||
    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():
 | 
			
		||||
            for f in edup.get_items_comparison():
 | 
			
		||||
                if not f["similar"]:
 | 
			
		||||
                    selected = form.get_selected_events(f["key"])
 | 
			
		||||
                    if selected is not 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:
 | 
			
		||||
                            if f["key"] == "organisers":
 | 
			
		||||
                                event.organisers.set(selected.organisers.all())
 | 
			
		||||
                            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_id": edup.get_event_index(event),
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required(login_url="/accounts/login/")
 | 
			
		||||
@permission_required(
 | 
			
		||||
    ["agenda_culturel.change_event", "agenda_culturel.change_duplicatedevents"]
 | 
			
		||||
)
 | 
			
		||||
def merge_duplicate(request, pk):
 | 
			
		||||
    edup = get_object_or_404(DuplicatedEvents, pk=pk)
 | 
			
		||||
    form = MergeDuplicates(duplicates=edup)
 | 
			
		||||
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = MergeDuplicates(request.POST, duplicates=edup)
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            events = edup.get_duplicated()
 | 
			
		||||
 | 
			
		||||
            # build fields for the new event
 | 
			
		||||
            new_event_data = {}
 | 
			
		||||
            for f in edup.get_items_comparison():
 | 
			
		||||
                if f["similar"]:
 | 
			
		||||
                    new_event_data[f["key"]] = getattr(events[0], f["key"])
 | 
			
		||||
                else:
 | 
			
		||||
                    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(s, f["key"]) for s in selected]
 | 
			
		||||
                            if x is not None
 | 
			
		||||
                        ]
 | 
			
		||||
                        if len(values) == 0:
 | 
			
		||||
                            new_event_data[f["key"]] = None
 | 
			
		||||
                        else:
 | 
			
		||||
                            if isinstance(values[0], str):
 | 
			
		||||
                                new_event_data[f["key"]] = "\n".join(values)
 | 
			
		||||
                            else:
 | 
			
		||||
                                new_event_data[f["key"]] = sum(values, [])
 | 
			
		||||
                    else:
 | 
			
		||||
                        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(
 | 
			
		||||
                                selected, "local_image"
 | 
			
		||||
                            )
 | 
			
		||||
 | 
			
		||||
            organisers = new_event_data.pop("organisers", None)
 | 
			
		||||
            # 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()
 | 
			
		||||
            if organisers is not None:
 | 
			
		||||
                new_event.organisers.set(organisers.all())
 | 
			
		||||
            edup.fix(new_event)
 | 
			
		||||
 | 
			
		||||
            messages.info(
 | 
			
		||||
                request,
 | 
			
		||||
                _("Creation of a merged event has been successfully completed."),
 | 
			
		||||
            )
 | 
			
		||||
            return HttpResponseRedirect(new_event.get_absolute_url())
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/merge_duplicate.html",
 | 
			
		||||
        context={"form": form, "object": edup},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required(login_url="/accounts/login/")
 | 
			
		||||
@permission_required(
 | 
			
		||||
    ["agenda_culturel.change_event", "agenda_culturel.change_duplicatedevents"]
 | 
			
		||||
)
 | 
			
		||||
def fix_duplicate(request, pk):
 | 
			
		||||
    edup = get_object_or_404(DuplicatedEvents.objects.select_related(), pk=pk)
 | 
			
		||||
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = FixDuplicates(request.POST, edup=edup)
 | 
			
		||||
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            if form.is_action_no_duplicates():
 | 
			
		||||
                # all events are different
 | 
			
		||||
                events = edup.get_duplicated()
 | 
			
		||||
 | 
			
		||||
                # get redirection date
 | 
			
		||||
                if len(events) == 0:
 | 
			
		||||
                    date = None
 | 
			
		||||
                else:
 | 
			
		||||
                    s_events = [e for e in events if not e.has_recurrences()]
 | 
			
		||||
                    if len(s_events) != 0:
 | 
			
		||||
                        s_event = s_events[0]
 | 
			
		||||
                    else:
 | 
			
		||||
                        s_event = events[0]
 | 
			
		||||
                    date = s_event.start_day
 | 
			
		||||
 | 
			
		||||
                messages.success(request, _("Events have been marked as unduplicated."))
 | 
			
		||||
                # delete the duplicated event (other_versions will be set to None on all events)
 | 
			
		||||
                edup.delete()
 | 
			
		||||
                if date is None:
 | 
			
		||||
                    return HttpResponseRedirect(reverse_lazy("home"))
 | 
			
		||||
                else:
 | 
			
		||||
                    return HttpResponseRedirect(
 | 
			
		||||
                        reverse_lazy("day_view", args=[date.year, date.month, date.day])
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
            elif form.is_action_select():
 | 
			
		||||
                # one element has been selected to be the representative
 | 
			
		||||
                selected = form.get_selected_event(edup)
 | 
			
		||||
                if selected 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."
 | 
			
		||||
                        ),
 | 
			
		||||
                    )
 | 
			
		||||
                else:
 | 
			
		||||
                    edup.fix(selected)
 | 
			
		||||
                    messages.success(
 | 
			
		||||
                        request,
 | 
			
		||||
                        _("The selected event has been set as representative"),
 | 
			
		||||
                    )
 | 
			
		||||
                return HttpResponseRedirect(edup.get_absolute_url())
 | 
			
		||||
            elif form.is_action_remove():
 | 
			
		||||
                # one element is removed from the set
 | 
			
		||||
                event = form.get_selected_event(edup)
 | 
			
		||||
                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:
 | 
			
		||||
                    event.other_versions = None
 | 
			
		||||
                    if edup.representative == event:
 | 
			
		||||
                        edup.representative = None
 | 
			
		||||
                    event.set_no_modification_date_changed()
 | 
			
		||||
                    event.save()
 | 
			
		||||
                    edup.save()
 | 
			
		||||
                    edup.events = [e for e in edup.events if e.pk != event.pk]
 | 
			
		||||
                    messages.success(
 | 
			
		||||
                        request,
 | 
			
		||||
                        _(
 | 
			
		||||
                            "The event has been withdrawn from the group and made independent."
 | 
			
		||||
                        ),
 | 
			
		||||
                    )
 | 
			
		||||
                    if edup.nb_duplicated() == 1:
 | 
			
		||||
                        return HttpResponseRedirect(edup.get_absolute_url())
 | 
			
		||||
                    else:
 | 
			
		||||
                        form = FixDuplicates(edup=edup)
 | 
			
		||||
            elif form.is_action_update():
 | 
			
		||||
                # otherwise, an event will be updated using other elements
 | 
			
		||||
                event = form.get_selected_event(edup)
 | 
			
		||||
                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.pk, event.pk])
 | 
			
		||||
                    )
 | 
			
		||||
            else:
 | 
			
		||||
                # otherwise, a new event will be created using a merging process
 | 
			
		||||
                return HttpResponseRedirect(
 | 
			
		||||
                    reverse_lazy("merge_duplicate", args=[edup.pk])
 | 
			
		||||
                )
 | 
			
		||||
    else:
 | 
			
		||||
        form = FixDuplicates(edup=edup)
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/fix_duplicate.html",
 | 
			
		||||
        context={"form": form, "object": edup},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DuplicatedEventsUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = DuplicatedEvents
 | 
			
		||||
    fields = ()
 | 
			
		||||
    template_name = "agenda_culturel/fix_duplicate.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required(login_url="/accounts/login/")
 | 
			
		||||
@permission_required("agenda_culturel.view_duplicatedevents")
 | 
			
		||||
def duplicates(request):
 | 
			
		||||
    nb_removed = DuplicatedEvents.remove_singletons()
 | 
			
		||||
    if nb_removed > 0:
 | 
			
		||||
        messages.success(
 | 
			
		||||
            request,
 | 
			
		||||
            _("Cleaning up duplicates: {} item(s) fixed.").format(nb_removed),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    filter = DuplicatedEventsFilter(
 | 
			
		||||
        request.GET, queryset=DuplicatedEvents.objects.all().order_by("-pk")
 | 
			
		||||
    )
 | 
			
		||||
    paginator = PaginatorFilter(filter, 10, request)
 | 
			
		||||
    page = request.GET.get("page")
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        response = paginator.page(page)
 | 
			
		||||
    except PageNotAnInteger:
 | 
			
		||||
        response = paginator.page(1)
 | 
			
		||||
    except EmptyPage:
 | 
			
		||||
        response = paginator.page(paginator.num_pages)
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/duplicates.html",
 | 
			
		||||
        {
 | 
			
		||||
            "filter": filter,
 | 
			
		||||
            "paginator_filter": response,
 | 
			
		||||
            "paginator": paginator,
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_duplicate(request, year, month, day, pk):
 | 
			
		||||
    event = get_object_or_404(Event, pk=pk)
 | 
			
		||||
    cday = CalendarDay(date(year, month, day))
 | 
			
		||||
    others = [
 | 
			
		||||
        e
 | 
			
		||||
        for e in cday.get_events()
 | 
			
		||||
        if e != event
 | 
			
		||||
        and (event.other_versions is None or event.other_versions != e.other_versions)
 | 
			
		||||
        and e.status != Event.STATUS.TRASH
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    form = SelectEventInList(events=others)
 | 
			
		||||
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = SelectEventInList(request.POST, events=others)
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            selected = [o for o in others if o.pk == int(form.cleaned_data["event"])]
 | 
			
		||||
            event.set_other_versions(selected)
 | 
			
		||||
            # save them without updating modified date
 | 
			
		||||
            event.set_no_modification_date_changed()
 | 
			
		||||
            event.save()
 | 
			
		||||
            if request.user.is_authenticated:
 | 
			
		||||
                messages.success(request, _("The event was successfully duplicated."))
 | 
			
		||||
                return HttpResponseRedirect(
 | 
			
		||||
                    reverse_lazy("view_duplicate", args=[event.other_versions.pk])
 | 
			
		||||
                )
 | 
			
		||||
            else:
 | 
			
		||||
                messages.info(
 | 
			
		||||
                    request,
 | 
			
		||||
                    _(
 | 
			
		||||
                        "The event has been successfully flagged as a duplicate. The moderation team will deal with your suggestion shortly."
 | 
			
		||||
                    ),
 | 
			
		||||
                )
 | 
			
		||||
                return HttpResponseRedirect(event.get_absolute_url())
 | 
			
		||||
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "agenda_culturel/set_duplicate.html",
 | 
			
		||||
        context={"form": form, "event": event},
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def statistics(request, pk=None):
 | 
			
		||||
    if pk is not None:
 | 
			
		||||
        rimport = RecurrentImport.objects.filter(pk=pk)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user