1225 lines
47 KiB
Python
1225 lines
47 KiB
Python
from django.shortcuts import render, get_object_or_404
|
|
from django.views.generic import ListView, DetailView, FormView
|
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin, PermissionRequiredMixin
|
|
from django.http import QueryDict
|
|
from django import forms
|
|
from django.contrib.postgres.search import SearchQuery, SearchHeadline
|
|
from django.core.exceptions import PermissionDenied
|
|
|
|
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseNotFound
|
|
from django.urls import reverse
|
|
import urllib
|
|
from collections import Counter
|
|
|
|
from .forms import EventSubmissionForm, EventForm, BatchImportationForm, FixDuplicates, SelectEventInList, MergeDuplicates, RecurrentImportForm, CategorisationRuleImportForm, ModerationQuestionForm, ModerationAnswerForm, ModerateForm, CategorisationForm, EventAddPlaceForm, PlaceForm
|
|
|
|
from .models import Event, Category, StaticContent, ContactMessage, BatchImportation, DuplicatedEvents, RecurrentImport, CategorisationRule, remove_accents, ModerationQuestion, ModerationAnswer, Place
|
|
from django.utils import timezone
|
|
from enum import StrEnum
|
|
from datetime import date, timedelta
|
|
from django.db.models import Q, F
|
|
|
|
from django.urls import reverse_lazy
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.utils.translation import activate, get_language_info
|
|
import django_filters
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
from django.contrib.auth.decorators import login_required, permission_required
|
|
|
|
from django.contrib import messages
|
|
from django.contrib.messages.views import SuccessMessageMixin
|
|
|
|
from .calendar import CalendarMonth, CalendarWeek, CalendarDay
|
|
|
|
from .import_tasks.importer import URL2Events
|
|
from .import_tasks.extractor import Extractor
|
|
from .import_tasks.downloader import ChromiumHeadlessDownloader
|
|
|
|
from .celery import app as celery_app, import_events_from_json, run_recurrent_import
|
|
|
|
import unicodedata
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
def get_event_qs(request):
|
|
if request.user.is_authenticated:
|
|
return Event.objects.filter()
|
|
else:
|
|
return Event.objects.filter(status=Event.STATUS.PUBLISHED)
|
|
|
|
|
|
def page_not_found(request, exception=None):
|
|
return render(request, 'page-erreur.html', status=404, context={"error": 404})
|
|
|
|
|
|
def internal_server_error(request):
|
|
return render(request, 'page-erreur.html', status=500, context={"error": 500})
|
|
|
|
|
|
class CategoryCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
|
template_name = 'agenda_culturel/forms/category-checkbox.html'
|
|
option_template_name = 'agenda_culturel/forms/checkbox-option.html'
|
|
|
|
class TagCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
|
template_name = 'agenda_culturel/forms/tag-checkbox.html'
|
|
option_template_name = 'agenda_culturel/forms/checkbox-option.html'
|
|
|
|
|
|
class EventFilter(django_filters.FilterSet):
|
|
RECURRENT_CHOICES = [("remove_recurrent", "Masquer les événements récurrents"), ("only_recurrent", "Montrer uniquement les événements récurrents")]
|
|
|
|
exclude_tags = django_filters.MultipleChoiceFilter(label="Exclure les étiquettes",
|
|
choices=[(t, t) for t in Event.get_all_tags()],
|
|
lookup_expr='icontains',
|
|
field_name="tags",
|
|
exclude=True,
|
|
widget=TagCheckboxSelectMultiple)
|
|
|
|
tags = django_filters.MultipleChoiceFilter(label="Filtrer par étiquettes",
|
|
choices=[(t, t) for t in Event.get_all_tags()],
|
|
lookup_expr='icontains',
|
|
field_name="tags",
|
|
widget=TagCheckboxSelectMultiple)
|
|
|
|
recurrences = django_filters.ChoiceFilter(label="Filtrer par récurrence",
|
|
choices=RECURRENT_CHOICES,
|
|
method="filter_recurrences")
|
|
|
|
category = django_filters.ModelMultipleChoiceFilter(label="Filtrer par catégories",
|
|
field_name="category__id",
|
|
to_field_name='id',
|
|
queryset=Category.objects.all(),
|
|
widget=CategoryCheckboxSelectMultiple)
|
|
|
|
city = django_filters.MultipleChoiceFilter(label="Filtrer par ville",
|
|
field_name='exact_location__city',
|
|
choices=[(c, c) for c in Place.get_all_cities()],
|
|
widget=forms.CheckboxSelectMultiple)
|
|
|
|
status = django_filters.MultipleChoiceFilter(label="Filtrer par status",
|
|
choices=Event.STATUS.choices,
|
|
field_name="status",
|
|
widget=forms.CheckboxSelectMultiple)
|
|
|
|
|
|
class Meta:
|
|
model = Event
|
|
fields = ["category", "city", "tags", "exclude_tags", "status", "recurrences"]
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
if not kwargs["request"].user.is_authenticated:
|
|
self.form.fields.pop("status")
|
|
|
|
def filter_recurrences(self, queryset, name, value):
|
|
# construct the full lookup expression
|
|
lookup = '__'.join([name, 'isnull'])
|
|
return queryset.filter(**{lookup: value == "remove_recurrent"})
|
|
|
|
def get_url(self):
|
|
if isinstance(self.form.data, QueryDict):
|
|
return self.form.data.urlencode()
|
|
else:
|
|
print(self.form.data)
|
|
return ""
|
|
|
|
def get_url_without_filters(self):
|
|
return self.request.get_full_path().split("?")[0]
|
|
|
|
def get_categories(self):
|
|
return self.form.cleaned_data["category"]
|
|
|
|
def get_tags(self):
|
|
return self.form.cleaned_data["tags"]
|
|
|
|
def get_exclude_tags(self):
|
|
return self.form.cleaned_data["exclude_tags"]
|
|
|
|
def get_status(self):
|
|
return self.form.cleaned_data["status"]
|
|
|
|
def get_cities(self):
|
|
return self.form.cleaned_data["city"]
|
|
|
|
def get_status_names(self):
|
|
if "status" in self.form.cleaned_data:
|
|
return [dict(Event.STATUS.choices)[s] for s in self.form.cleaned_data["status"]]
|
|
else:
|
|
return []
|
|
def get_recurrence_filtering(self):
|
|
if "recurrences" in self.form.cleaned_data:
|
|
d = dict(self.RECURRENT_CHOICES)
|
|
v = self.form.cleaned_data["recurrences"]
|
|
if v in d:
|
|
return d[v]
|
|
else:
|
|
return ""
|
|
else:
|
|
return ""
|
|
|
|
def is_active(self, only_categories=False):
|
|
if only_categories:
|
|
return len(self.form.cleaned_data["category"]) != 0
|
|
else:
|
|
if "status" in self.form.cleaned_data and len(self.form.cleaned_data["status"]) != 0:
|
|
return True
|
|
return len(self.form.cleaned_data["category"]) != 0 or len(self.form.cleaned_data["tags"]) != 0 or len(self.form.cleaned_data["exclude_tags"]) != 0 or len(self.form.cleaned_data["recurrences"]) != 0 or len(self.form.cleaned_data["city"]) != 0
|
|
|
|
def is_selected(self, cat):
|
|
return cat in self.form.cleaned_data["category"]
|
|
|
|
|
|
def mentions_legales(request):
|
|
context = { "title": "Mentions légales", "static_content": "mentions_legales", "url_path": reverse_lazy("mentions_legales") }
|
|
return render(request, 'agenda_culturel/page-single.html', context)
|
|
|
|
def about(request):
|
|
rimports = RecurrentImport.objects.order_by("name").all()
|
|
context = { "title": "À propos", "static_content": "about", "url_path": reverse_lazy("about"), "rimports": rimports }
|
|
return render(request, 'agenda_culturel/page-rimports-list.html', context)
|
|
|
|
|
|
def home(request):
|
|
return week_view(request, home=True)
|
|
|
|
def month_view(request, year = None, month = None):
|
|
now = date.today()
|
|
if year is None:
|
|
year = now.year
|
|
if month is None:
|
|
month = now.month
|
|
|
|
filter = EventFilter(request.GET, queryset=get_event_qs(request), request=request)
|
|
cmonth = CalendarMonth(year, month, filter)
|
|
|
|
|
|
context = {"year": year, "month": cmonth.get_month_name(), "calendar": cmonth, "filter": filter }
|
|
return render(request, 'agenda_culturel/page-month.html', context)
|
|
|
|
|
|
def week_view(request, year=None, week=None, home=False):
|
|
now = date.today()
|
|
if year is None:
|
|
year = now.year
|
|
if week is None:
|
|
week = now.isocalendar()[1]
|
|
|
|
filter = EventFilter(request.GET, queryset=get_event_qs(request), request=request)
|
|
cweek = CalendarWeek(year, week, filter)
|
|
|
|
context = {"year": year, "week": week, "calendar": cweek, "filter": filter }
|
|
if home:
|
|
context["home"] = 1
|
|
return render(request, 'agenda_culturel/page-week.html', context)
|
|
|
|
|
|
def day_view(request, year = None, month = None, day = None):
|
|
now = date.today()
|
|
if year is None:
|
|
year = now.year
|
|
if month is None:
|
|
month = now.month
|
|
if day is None:
|
|
day = now.day
|
|
|
|
day = date(year, month, day)
|
|
|
|
filter = EventFilter(request.GET, get_event_qs(request), request=request)
|
|
cday = CalendarDay(day, filter)
|
|
|
|
categories = Counter([e.category if e.category is not None else Category.get_default_category() for e in cday.get_events()])
|
|
categories = [(k, v) for k, v in categories.items()]
|
|
categories.sort(key=lambda k: -k[1])
|
|
|
|
context = {"day": day, "events": cday.get_events(), "filter": filter, "categories": categories}
|
|
return render(request, 'agenda_culturel/page-day.html', context)
|
|
|
|
|
|
def view_tag(request, t):
|
|
events = Event.objects.filter(tags__contains=[t]).order_by("start_day", "start_time")
|
|
context = {"tag": t, "events": events}
|
|
return render(request, 'agenda_culturel/tag.html', context)
|
|
|
|
|
|
def tag_list(request):
|
|
|
|
tags = Event.get_all_tags()
|
|
context = {"tags": sorted(tags, key=lambda x: remove_accents(x).lower())}
|
|
return render(request, 'agenda_culturel/tags.html', context)
|
|
|
|
|
|
class StaticContentCreateView(LoginRequiredMixin, CreateView):
|
|
model = StaticContent
|
|
fields = ['text']
|
|
permission_required = ("agenda_culturel.add_staticcontent")
|
|
|
|
def form_valid(self, form):
|
|
form.instance.name = self.request.GET["name"]
|
|
form.instance.url_path = self.request.GET["url_path"]
|
|
return super().form_valid(form)
|
|
|
|
|
|
class StaticContentUpdateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
|
|
model = StaticContent
|
|
permission_required = ("agenda_culturel.change_staticcontent")
|
|
fields = ['text']
|
|
success_message = _('The static content has been successfully updated.')
|
|
|
|
|
|
class EventUpdateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
|
|
model = Event
|
|
permission_required = ("agenda_culturel.change_event")
|
|
form_class = EventForm
|
|
success_message = _('The event has been successfully modified.')
|
|
|
|
def get_form_kwargs(self):
|
|
kwargs = super().get_form_kwargs()
|
|
kwargs['is_authenticated'] = self.request.user.is_authenticated
|
|
return kwargs
|
|
|
|
|
|
class EventDeleteView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, DeleteView):
|
|
model = Event
|
|
permission_required = ("agenda_culturel.delete_event")
|
|
success_url = reverse_lazy('moderation')
|
|
success_message = _('The event has been successfully deleted.')
|
|
|
|
|
|
class EventDetailView(UserPassesTestMixin, DetailView):
|
|
model = Event
|
|
template_name = "agenda_culturel/page-event.html"
|
|
|
|
def test_func(self):
|
|
return self.request.user.is_authenticated or self.get_object().status == Event.STATUS.PUBLISHED
|
|
|
|
def get_object(self):
|
|
o = super().get_object()
|
|
y = self.kwargs["year"]
|
|
m = self.kwargs["month"]
|
|
d = self.kwargs["day"]
|
|
obj = o.get_recurrence_at_date(y, m, d)
|
|
obj.set_current_date(date(y, m, d))
|
|
return obj
|
|
|
|
|
|
class EventModerateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
|
|
model = Event
|
|
permission_required = ("agenda_culturel.change_event", "agenda_culturel.use_moderation_question")
|
|
success_message = _('The event has been successfully modified.')
|
|
form_class = ModerateForm
|
|
template_name = 'agenda_culturel/event_moderation_form.html'
|
|
|
|
def form_valid(self, form):
|
|
|
|
mas = ModerationAnswer.objects.all()
|
|
logger.warning("ON valide la forme")
|
|
|
|
for f in form.cleaned_data:
|
|
ModerationAnswer.objects.get(pk=form.cleaned_data[f]).apply_answer(form.instance)
|
|
|
|
form.instance.moderated_date = timezone.now()
|
|
|
|
return super().form_valid(form)
|
|
|
|
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.change_event')
|
|
def change_status_event(request, pk, status):
|
|
event = get_object_or_404(Event, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
event.status = Event.STATUS(status)
|
|
event.save(update_fields=["status"])
|
|
messages.success(request, _("The status has been successfully modified."))
|
|
|
|
if request.user.is_authenticated:
|
|
return HttpResponseRedirect(event.get_absolute_url())
|
|
else:
|
|
return HttpResponseRedirect(reverse_lazy("home"))
|
|
else:
|
|
cancel_url = request.META.get('HTTP_REFERER', '')
|
|
if cancel_url == "":
|
|
cancel_url = reverse_lazy("home")
|
|
return render(request, 'agenda_culturel/event_confirm_change_status.html', {"status": status, "event": event, "cancel_url": cancel_url})
|
|
|
|
def import_from_url(request):
|
|
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if request.method == 'POST' and "title" in request.POST:
|
|
form = EventForm(request.POST, is_authenticated=request.user.is_authenticated)
|
|
if form.is_valid():
|
|
new_event = form.save()
|
|
if request.user.is_authenticated:
|
|
messages.success(request, _("The event is saved."))
|
|
return HttpResponseRedirect(new_event.get_absolute_url())
|
|
else:
|
|
messages.success(request, _("The event has been submitted and will be published as soon as it has been validated by the moderation team."))
|
|
return HttpResponseRedirect(reverse("home"))
|
|
else:
|
|
return render(request, 'agenda_culturel/event_form.html', context={'form': form })
|
|
|
|
else:
|
|
form = EventSubmissionForm()
|
|
|
|
initial = {"start_day": date.today() + timedelta(days=1),
|
|
"start_time": "20:00",
|
|
"end_time": "22:00"}
|
|
|
|
form_event = EventForm(initial=initial)
|
|
|
|
if request.method == 'POST':
|
|
|
|
form = EventSubmissionForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
cd = form.cleaned_data
|
|
url = cd.get('url')
|
|
|
|
url = Extractor.clean_url(url)
|
|
|
|
existing = Event.objects.filter(uuids__contains=[url])
|
|
|
|
if len(existing) == 0:
|
|
event = None
|
|
|
|
u2e = URL2Events(ChromiumHeadlessDownloader(), single_event=True)
|
|
events_structure = u2e.process(url, published=request.user.is_authenticated)
|
|
if events_structure is not None and "events" in events_structure and len(events_structure["events"]) > 0:
|
|
event = Event.from_structure(events_structure["events"][0], events_structure["header"]["url"])
|
|
# TODO: use celery to import the other events
|
|
|
|
if event != None:
|
|
form = EventForm(instance=event, is_authenticated=request.user.is_authenticated)
|
|
messages.success(request, _("The event has been successfully extracted, and you can now submit it after modifying it if necessary."))
|
|
return render(request, 'agenda_culturel/event_form.html', context={'form': form })
|
|
else:
|
|
form = EventForm(initial={'reference_urls': [url]}, is_authenticated=request.user.is_authenticated)
|
|
messages.error(request, _("Unable to extract an event from the proposed URL. Please use the form below to submit the event."))
|
|
return render(request, 'agenda_culturel/import.html', context={'form': form, 'form_event': form_event})
|
|
else:
|
|
published = [e for e in existing if e.status == Event.STATUS.PUBLISHED]
|
|
drafts = [e for e in existing if e.status == Event.STATUS.DRAFT]
|
|
trash = [e for e in existing if e.status == Event.STATUS.TRASH]
|
|
|
|
if request.user.is_authenticated or len(published) > 1:
|
|
event = published[0] if len(published) > 1 else existing[0]
|
|
messages.info(request, _("This URL has already been submitted, and you can find the event below."))
|
|
return HttpResponseRedirect(event.get_absolute_url())
|
|
else:
|
|
if len(drafts) > 0:
|
|
messages.info(request, _("This URL has already been submitted and is awaiting moderation."))
|
|
elif len(trash) > 0:
|
|
messages.info(request, _("This URL has already been submitted, but has not been selected for publication by the moderation team."))
|
|
|
|
|
|
return render(request, 'agenda_culturel/import.html', context={'form': form, 'form_event': form_event})
|
|
|
|
|
|
class EventFilterAdmin(django_filters.FilterSet):
|
|
status = django_filters.MultipleChoiceFilter(choices=Event.STATUS.choices, widget=forms.CheckboxSelectMultiple)
|
|
|
|
class Meta:
|
|
model = Event
|
|
fields = ['status']
|
|
|
|
|
|
|
|
|
|
class ContactMessageCreateView(SuccessMessageMixin, CreateView):
|
|
model = ContactMessage
|
|
template_name = "agenda_culturel/contactmessage_create_form.html"
|
|
fields = ['subject', 'name', 'email', 'message']
|
|
|
|
success_url = reverse_lazy('home')
|
|
success_message = _('Your message has been sent successfully.')
|
|
|
|
def get_form(self, form_class=None):
|
|
if form_class is None:
|
|
form_class = self.get_form_class()
|
|
return form_class(**self.get_form_kwargs())
|
|
|
|
|
|
|
|
class ContactMessageUpdateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
|
|
model = ContactMessage
|
|
permission_required = ("agenda_culturel.change_contactmessage")
|
|
template_name = "agenda_culturel/contactmessage_moderation_form.html"
|
|
fields = ('closed', 'comments')
|
|
|
|
success_message = _('The contact message properties has been successfully modified.')
|
|
|
|
success_url = reverse_lazy('contactmessages')
|
|
|
|
|
|
def get_form_kwargs(self):
|
|
"""Return the keyword arguments for instantiating the form."""
|
|
kwargs = super().get_form_kwargs()
|
|
if hasattr(self, 'object'):
|
|
kwargs.update({'instance': self.object})
|
|
return kwargs
|
|
|
|
|
|
|
|
class ContactMessagesFilterAdmin(django_filters.FilterSet):
|
|
closed = django_filters.MultipleChoiceFilter(label="Status", choices=((True, _("Closed")), (False, _("Open"))), widget=forms.CheckboxSelectMultiple)
|
|
class Meta:
|
|
model = ContactMessage
|
|
fields = ['closed']
|
|
|
|
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.view_event')
|
|
def moderation(request):
|
|
filter = EventFilterAdmin(request.GET, queryset=Event.objects.all().order_by("-created_date"))
|
|
paginator = Paginator(filter.qs, 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/moderation.html', {'filter': filter, 'paginator_filter': response} )
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.view_contactmessage')
|
|
def contactmessages(request):
|
|
filter = ContactMessagesFilterAdmin(request.GET, queryset=ContactMessage.objects.all().order_by("-date"))
|
|
paginator = Paginator(filter.qs, 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/contactmessages.html', {'filter': filter, 'paginator_filter': response} )
|
|
|
|
|
|
|
|
class SimpleSearchEventFilter(django_filters.FilterSet):
|
|
q = django_filters.CharFilter(method='custom_filter', label=_("Search"))
|
|
|
|
status = django_filters.MultipleChoiceFilter(label="Filtrer par status",
|
|
choices=Event.STATUS.choices,
|
|
field_name="status",
|
|
widget=forms.CheckboxSelectMultiple)
|
|
|
|
def custom_filter(self, queryset, name, value):
|
|
search_query = SearchQuery(value, config='french')
|
|
qs = queryset.filter(
|
|
Q(title__icontains=value) | Q(location__icontains=value) | Q(description__icontains=value))
|
|
for f in ["title", "location", "description"]:
|
|
params = { f + "_hl": SearchHeadline(f,
|
|
search_query,
|
|
start_sel="<span class=\"highlight\">",
|
|
stop_sel="</span>",
|
|
config='french')}
|
|
qs = qs.annotate(**params)
|
|
return qs
|
|
|
|
class Meta:
|
|
model = Event
|
|
fields = ['q']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
if not kwargs["request"].user.is_authenticated:
|
|
self.form.fields.pop("status")
|
|
|
|
|
|
class SearchEventFilter(django_filters.FilterSet):
|
|
tags = django_filters.CharFilter(lookup_expr='icontains')
|
|
title = django_filters.CharFilter(method="hl_filter_contains")
|
|
location = django_filters.CharFilter(method="hl_filter_contains")
|
|
description = django_filters.CharFilter(method="hl_filter_contains")
|
|
start_day = django_filters.DateFromToRangeFilter(widget=django_filters.widgets.RangeWidget(attrs={'type': 'date'}))
|
|
status = django_filters.MultipleChoiceFilter(label="Filtrer par status",
|
|
choices=Event.STATUS.choices,
|
|
field_name="status",
|
|
widget=forms.CheckboxSelectMultiple)
|
|
|
|
o = django_filters.OrderingFilter(
|
|
# tuple-mapping retains order
|
|
fields=(
|
|
('title', 'title'),
|
|
('description', 'description'),
|
|
('start_day', 'start_day'),
|
|
),
|
|
)
|
|
|
|
def hl_filter_contains(self, queryset, name, value):
|
|
|
|
# first check if it contains
|
|
filter_contains = { name + "__contains": value }
|
|
queryset = queryset.filter(**filter_contains)
|
|
|
|
# then hightlight the result
|
|
search_query = SearchQuery(value, config='french')
|
|
params = { name + "_hl": SearchHeadline(name,
|
|
search_query,
|
|
start_sel="<span class=\"highlight\">",
|
|
stop_sel="</span>",
|
|
config='french')}
|
|
return queryset.annotate(**params)
|
|
|
|
|
|
class Meta:
|
|
model = Event
|
|
fields = ['title', 'location', 'description', 'category', 'tags', 'start_day']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
if not kwargs["request"].user.is_authenticated:
|
|
self.form.fields.pop("status")
|
|
|
|
|
|
def event_search(request, full=False):
|
|
|
|
if full:
|
|
filter = SearchEventFilter(request.GET, queryset=get_event_qs(request).order_by("-start_day"), request=request)
|
|
else:
|
|
filter = SimpleSearchEventFilter(request.GET, queryset=get_event_qs(request).order_by("-start_day"), request=request)
|
|
|
|
|
|
paginator = Paginator(filter.qs, 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/search.html', {'filter': filter,
|
|
'has_results': len(request.GET) != 0 or (len(request.GET) > 1 and "page" in request.GET),
|
|
'paginator_filter': response,
|
|
'full': full})
|
|
|
|
def event_search_full(request):
|
|
return event_search(request, True)
|
|
|
|
|
|
#########################
|
|
## batch importations
|
|
#########################
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.view_batchimportation')
|
|
def imports(request):
|
|
paginator = Paginator(BatchImportation.objects.all().order_by("-created_date"), 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/imports.html', {'paginator_filter': response} )
|
|
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required(['agenda_culturel.add_batchimportation', 'agenda_culturel.run_batchimportation'])
|
|
def add_import(request):
|
|
form = BatchImportationForm()
|
|
|
|
if request.method == 'POST':
|
|
form = BatchImportationForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
result = import_events_from_json.delay(form.data["json"])
|
|
|
|
messages.success(request, _("The import has been run successfully."))
|
|
return HttpResponseRedirect(reverse_lazy("imports"))
|
|
|
|
return render(request, 'agenda_culturel/batchimportation_form.html', {"form": form})
|
|
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required(['agenda_culturel.view_batchimportation', 'agenda_culturel.run_batchimportation'])
|
|
def cancel_import(request, pk):
|
|
import_process = get_object_or_404(BatchImportation, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
celery_app.control.revoke(import_process.celery_id)
|
|
|
|
import_process.status = BatchImportation.STATUS.CANCELED
|
|
import_process.save(update_fields=["status"])
|
|
|
|
messages.success(request, _("The import has been canceled."))
|
|
return HttpResponseRedirect(reverse_lazy("imports"))
|
|
else:
|
|
cancel_url = reverse_lazy("imports")
|
|
return render(request, 'agenda_culturel/cancel_import_confirm.html', {"object": import_process, "cancel_url": cancel_url})
|
|
|
|
#########################
|
|
## recurrent importations
|
|
#########################
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.view_recurrentimport')
|
|
def recurrent_imports(request):
|
|
paginator = Paginator(RecurrentImport.objects.all().order_by("-pk"), 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/rimports.html', {'paginator_filter': response} )
|
|
|
|
|
|
class RecurrentImportCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
model = RecurrentImport
|
|
permission_required = ("agenda_culturel.add_recurrentimport")
|
|
success_url = reverse_lazy('recurrent_imports')
|
|
form_class = RecurrentImportForm
|
|
|
|
|
|
class RecurrentImportUpdateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
|
|
model = RecurrentImport
|
|
permission_required = ("agenda_culturel.change_recurrentimport")
|
|
form_class = RecurrentImportForm
|
|
success_message = _('The recurrent import has been successfully modified.')
|
|
|
|
|
|
class RecurrentImportDeleteView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, DeleteView):
|
|
model = RecurrentImport
|
|
permission_required = ("agenda_culturel.delete_recurrentimport")
|
|
success_url = reverse_lazy('recurrent_imports')
|
|
success_message = _('The recurrent import has been successfully deleted.')
|
|
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required(['agenda_culturel.view_recurrentimport', 'agenda_culturel.view_batchimportation'])
|
|
def view_rimport(request, pk):
|
|
obj = get_object_or_404(RecurrentImport, pk=pk)
|
|
paginator = Paginator(BatchImportation.objects.filter(recurrentImport=pk).order_by("-created_date"), 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/page-rimport.html', {'paginator_filter': response, 'object': obj} )
|
|
|
|
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required(['agenda_culturel.view_recurrentimport', 'agenda_culturel.run_recurrentimport'])
|
|
def run_rimport(request, pk):
|
|
rimport = get_object_or_404(RecurrentImport, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
|
|
# run recurrent import
|
|
result = run_recurrent_import.delay(pk)
|
|
|
|
messages.success(request, _("The import has been launched."))
|
|
return HttpResponseRedirect(reverse_lazy("view_rimport", args=[pk]))
|
|
else:
|
|
return render(request, 'agenda_culturel/run_rimport_confirm.html', {"object": rimport })
|
|
|
|
#########################
|
|
## duplicated events
|
|
#########################
|
|
|
|
|
|
class DuplicatedEventsDetailView(LoginRequiredMixin, DetailView):
|
|
model = DuplicatedEvents
|
|
template_name = "agenda_culturel/fix_duplicate.html"
|
|
|
|
|
|
@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_id(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] 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(events[selected], f["key"])
|
|
|
|
for specific_tag in ["uuids", "import_sources"]:
|
|
new_event_data[specific_tag] = sum([x for x in [getattr(e, specific_tag) for e in events] if x is not None], [])
|
|
|
|
# create a new event that merge the selected events
|
|
new_event = Event(**new_event_data)
|
|
new_event.set_skip_duplicate_check()
|
|
new_event.save()
|
|
|
|
# move the old ones in trash
|
|
for e in events:
|
|
e.status = Event.STATUS.TRASH
|
|
Event.objects.bulk_update(events, fields=["status"])
|
|
|
|
messages.info(request, _("The merge 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, pk=pk)
|
|
form = FixDuplicates(nb_events=edup.nb_duplicated())
|
|
|
|
if request.method == 'POST':
|
|
form = FixDuplicates(request.POST, nb_events=edup.nb_duplicated())
|
|
|
|
|
|
if form.is_valid():
|
|
if form.is_action_no_duplicates():
|
|
events = edup.get_duplicated()
|
|
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."))
|
|
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():
|
|
selected = form.get_selected_event(edup)
|
|
not_selected = [e for e in edup.get_duplicated() if e != selected]
|
|
nb = len(not_selected)
|
|
for e in not_selected:
|
|
e.status = Event.STATUS.TRASH
|
|
Event.objects.bulk_update(not_selected, fields=["status"])
|
|
url = selected.get_absolute_url()
|
|
edup.delete()
|
|
if nb == 1:
|
|
messages.success(request, _("The selected event has been retained, while the other has been moved to the recycle bin."))
|
|
else:
|
|
messages.success(request, _("The selected event has been retained, while the others have been moved to the recycle bin."))
|
|
return HttpResponseRedirect(url)
|
|
elif form.is_action_remove():
|
|
event = form.get_selected_event(edup)
|
|
event.possibly_duplicated = None
|
|
event.save()
|
|
messages.success(request, _("The event has been withdrawn from the group and made independent."))
|
|
if edup.nb_duplicated() == 1:
|
|
return HttpResponseRedirect(event.get_absolute_url())
|
|
else:
|
|
form = FixDuplicates(nb_events=edup.nb_duplicated())
|
|
else:
|
|
return HttpResponseRedirect(reverse_lazy("merge_duplicate", args=[edup.pk]))
|
|
|
|
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):
|
|
paginator = Paginator(DuplicatedEvents.objects.all(), 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/duplicates.html', {'filter': filter, 'paginator_filter': response} )
|
|
|
|
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.possibly_duplicated is None or event.possibly_duplicated != e.possibly_duplicated)]
|
|
|
|
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_possibly_duplicated(selected)
|
|
event.save()
|
|
if request.user.is_authenticated:
|
|
messages.success(request, _("The event was successfully duplicated."))
|
|
return HttpResponseRedirect(reverse_lazy("view_duplicate", args=[event.possibly_duplicated.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})
|
|
|
|
|
|
|
|
#########################
|
|
## categorisation rules
|
|
#########################
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.view_categorisationrule')
|
|
def categorisation_rules(request):
|
|
paginator = Paginator(CategorisationRule.objects.all().order_by("weight", "pk"), 10)
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
response = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
response = paginator.page(1)
|
|
except EmptyPage:
|
|
response = paginator.page(paginator.num_pages)
|
|
|
|
return render(request, 'agenda_culturel/categorisation_rules.html', {'paginator_filter': response} )
|
|
|
|
class CategorisationRuleCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
model = CategorisationRule
|
|
permission_required = ("agenda_culturel.add_categorisationrule")
|
|
success_url = reverse_lazy('categorisation_rules')
|
|
form_class = CategorisationRuleImportForm
|
|
|
|
|
|
class CategorisationRuleUpdateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
|
|
model = CategorisationRule
|
|
permission_required = ("agenda_culturel.change_categorisationrule")
|
|
form_class = CategorisationRuleImportForm
|
|
success_url = reverse_lazy('categorisation_rules')
|
|
success_message = _('The categorisation rule has been successfully modified.')
|
|
|
|
|
|
class CategorisationRuleDeleteView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, DeleteView):
|
|
model = CategorisationRule
|
|
permission_required = ("agenda_culturel.delete_categorisationrule")
|
|
success_url = reverse_lazy('categorisation_rules')
|
|
success_message = _('The categorisation rule has been successfully deleted.')
|
|
|
|
@login_required(login_url="/accounts/login/")
|
|
@permission_required('agenda_culturel.apply_categorisationrules')
|
|
def apply_categorisation_rules(request):
|
|
|
|
if request.method == 'POST':
|
|
form = CategorisationForm(request.POST)
|
|
if form.is_valid():
|
|
nb = 0
|
|
for epk, c in form.get_validated():
|
|
e = Event.objects.get(pk=epk)
|
|
logger.warning("cat " + c)
|
|
cat = Category.objects.get(name=c)
|
|
e.category = cat
|
|
e.save()
|
|
nb += 1
|
|
|
|
if nb != 0:
|
|
if nb == 1:
|
|
messages.success(request, _("The rules were successfully applied and 1 event was categorised."))
|
|
else:
|
|
messages.success(request, _("The rules were successfully applied and {} events were categorised.").format(nb))
|
|
else:
|
|
messages.info(request, _("The rules were successfully applied and no events were categorised."))
|
|
|
|
return HttpResponseRedirect(reverse_lazy("categorisation_rules"))
|
|
else:
|
|
return render(request, 'agenda_culturel/categorise_events_form.html', context={'form': form})
|
|
else:
|
|
# first we check if events are not correctly categorised
|
|
to_categorise = []
|
|
for e in Event.objects.exclude(category=Category.get_default_category_id()):
|
|
c = CategorisationRule.match_rules(e)
|
|
if c and c != e.category:
|
|
to_categorise.append((e, c))
|
|
|
|
|
|
# then we apply rules on events without category
|
|
nb = 0
|
|
for e in Event.objects.filter(category=Category.get_default_category_id()):
|
|
success = CategorisationRule.apply_rules(e)
|
|
if success:
|
|
nb += 1
|
|
e.save()
|
|
|
|
# set messages
|
|
if nb != 0:
|
|
if nb == 1:
|
|
messages.success(request, _("The rules were successfully applied and 1 event was categorised."))
|
|
else:
|
|
messages.success(request, _("The rules were successfully applied and {} events were categorised.").format(nb))
|
|
else:
|
|
messages.info(request, _("The rules were successfully applied and no events were categorised."))
|
|
|
|
if len(to_categorise) != 0:
|
|
form = CategorisationForm(events=to_categorise)
|
|
return render(request, 'agenda_culturel/categorise_events_form.html', context={'form': form,
|
|
'events': dict((e.pk, e) for e, c in to_categorise),
|
|
'categories': dict((e.pk, c) for e, c in to_categorise)})
|
|
else:
|
|
return HttpResponseRedirect(reverse_lazy("categorisation_rules"))
|
|
|
|
|
|
#########################
|
|
## Moderation Q&A
|
|
#########################
|
|
|
|
|
|
class ModerationQuestionListView(PermissionRequiredMixin, ListView):
|
|
model = ModerationQuestion
|
|
paginate_by = 10
|
|
permission_required = ("agenda_culturel.view_moderationquestion")
|
|
|
|
class ModerationQuestionCreateView(SuccessMessageMixin, PermissionRequiredMixin, CreateView):
|
|
model = ModerationQuestion
|
|
permission_required = ("agenda_culturel.add_moderationquestion")
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy('view_mquestion', kwargs={'pk': self.object.pk})
|
|
form_class = ModerationQuestionForm
|
|
success_message = _('The moderation question has been created with success.')
|
|
|
|
|
|
class ModerationQuestionDetailView(PermissionRequiredMixin, DetailView):
|
|
model = ModerationQuestion
|
|
permission_required = ("agenda_culturel.view_moderationquestion", "agenda_culturel.view_moderationanswer")
|
|
|
|
|
|
class ModerationQuestionUpdateView(PermissionRequiredMixin, UpdateView):
|
|
model = ModerationQuestion
|
|
fields = ['question']
|
|
permission_required = ("agenda_culturel.change_moderationquestion")
|
|
|
|
class ModerationQuestionDeleteView(PermissionRequiredMixin, DeleteView):
|
|
model = ModerationQuestion
|
|
permission_required = ("agenda_culturel.delete_moderationquestion")
|
|
success_url = reverse_lazy('view_mquestions')
|
|
|
|
|
|
class ModerationAnswerCreateView(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
|
|
model = ModerationAnswer
|
|
permission_required = ("agenda_culturel.add_answerquestion")
|
|
form_class = ModerationAnswerForm
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['question'] = get_object_or_404(ModerationQuestion, pk=self.kwargs['qpk'])
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
form.instance.question = ModerationQuestion.objects.get(pk=self.kwargs['qpk'])
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy('view_mquestion', kwargs={'pk': self.kwargs['qpk']})
|
|
|
|
|
|
class ModerationAnswerUpdateView(PermissionRequiredMixin, UpdateView):
|
|
model = ModerationAnswer
|
|
fields = ['answer', 'adds_tags', 'removes_tags']
|
|
permission_required = ("agenda_culturel.change_answerquestion")
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['question'] = get_object_or_404(ModerationQuestion, pk=self.kwargs['qpk'])
|
|
return context
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy('view_mquestion', kwargs={'pk': self.kwargs['qpk']})
|
|
|
|
class ModerationAnswerDeleteView(PermissionRequiredMixin, DeleteView):
|
|
model = ModerationAnswer
|
|
permission_required = ("agenda_culturel.delete_answerquestion")
|
|
|
|
|
|
#########################
|
|
## Places
|
|
#########################
|
|
|
|
class PlaceListView(ListView):
|
|
model = Place
|
|
paginate_by = 10
|
|
ordering = ['-pk']
|
|
|
|
|
|
class PlaceDetailView(DetailView):
|
|
model = Place
|
|
|
|
class UpdatePlaces:
|
|
def form_valid(self, form):
|
|
result = super().form_valid(form)
|
|
p = form.instance
|
|
|
|
if not hasattr(self, "nb_applied"):
|
|
self.nb_applied = 0
|
|
|
|
# if required, find all matching events
|
|
if form.apply():
|
|
self.nb_applied += p.associate_matching_events()
|
|
|
|
if self.nb_applied > 1:
|
|
messages.success(self.request, _("{} events have been updated.").format(self.nb_applied))
|
|
elif self.nb_applied == 1:
|
|
messages.success(self.request, _("1 event has been updated."))
|
|
else:
|
|
messages.info(self.request, _("No events have been modified."))
|
|
return result
|
|
|
|
|
|
|
|
class PlaceUpdateView(UpdatePlaces, PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
|
|
model = Place
|
|
permission_required = ("agenda_culturel.change_place")
|
|
success_message = _('The place has been successfully updated.')
|
|
form_class = PlaceForm
|
|
|
|
|
|
class PlaceCreateView(UpdatePlaces, PermissionRequiredMixin, SuccessMessageMixin, CreateView):
|
|
model = Place
|
|
permission_required = ("agenda_culturel.add_place")
|
|
success_message = _('The place has been successfully created.')
|
|
form_class = PlaceForm
|
|
|
|
|
|
class PlaceDeleteView(PermissionRequiredMixin, DeleteView):
|
|
model = Place
|
|
permission_required = ("agenda_culturel.delete_place")
|
|
success_url = reverse_lazy('view_places')
|
|
|
|
class UnknownPlacesListView(PermissionRequiredMixin, ListView):
|
|
model = Event
|
|
permission_required = ("agenda_culturel.add_place")
|
|
paginate_by = 10
|
|
template_name = 'agenda_culturel/place_unknown_list.html'
|
|
queryset = Event.objects.filter(exact_location__isnull=True)
|
|
|
|
def fix_unknown_places(request):
|
|
# get all places
|
|
places = Place.objects.all()
|
|
# get all events without exact location
|
|
u_events = Event.objects.filter(exact_location__isnull=True)
|
|
|
|
to_be_updated = []
|
|
# try to find matches
|
|
for ue in u_events:
|
|
for p in places:
|
|
if p.match(ue):
|
|
ue.exact_location = p
|
|
to_be_updated.append(ue)
|
|
continue
|
|
# update events with a location
|
|
Event.objects.bulk_update(to_be_updated, fields=["exact_location"])
|
|
|
|
# create a success message
|
|
nb = len(to_be_updated)
|
|
if nb > 1:
|
|
messages.success(request, _("{} events have been updated.").format(nb))
|
|
elif nb == 1:
|
|
messages.success(request, _("1 event has been updated."))
|
|
else:
|
|
messages.info(request, _("No events have been modified."))
|
|
|
|
# come back to the list of places
|
|
return HttpResponseRedirect(reverse_lazy("view_unknown_places"))
|
|
|
|
|
|
class UnknownPlaceAddView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
|
|
model = Event
|
|
permission_required = ("agenda_culturel.change_place", "agenda_culturel.change_event")
|
|
form_class = EventAddPlaceForm
|
|
template_name = 'agenda_culturel/place_unknown_form.html'
|
|
|
|
def form_valid(self, form):
|
|
|
|
self.modified_event = form.cleaned_data.get('place')
|
|
result = super().form_valid(form)
|
|
|
|
if form.cleaned_data.get('place'):
|
|
messages.success(self.request, _("The selected place has been assigned to the event."))
|
|
if form.cleaned_data.get("add_alias"):
|
|
messages.success(self.request, _("A new alias has been added to the selected place."))
|
|
|
|
nb_applied = form.cleaned_data.get('place').associate_matching_events()
|
|
|
|
if nb_applied > 1:
|
|
messages.success(self.request, _("{} events have been updated.").format(nb_applied))
|
|
elif nb_applied == 1:
|
|
messages.success(self.request, _("1 event has been updated."))
|
|
else:
|
|
messages.info(self.request, _("No events have been modified."))
|
|
|
|
return result
|
|
|
|
def get_success_url(self):
|
|
if self.modified_event:
|
|
return reverse_lazy('view_unknown_places')
|
|
else:
|
|
return reverse_lazy('add_place_from_event', args=[self.object.pk])
|
|
|
|
|
|
class PlaceFromEventCreateView(PlaceCreateView):
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context["event"] = self.event
|
|
return context
|
|
|
|
def get_initial(self, *args, **kwargs):
|
|
initial = super().get_initial(**kwargs)
|
|
self.event = get_object_or_404(Event, pk=self.kwargs['pk'])
|
|
if self.event.location:
|
|
initial['aliases'] = [self.event.location]
|
|
return initial
|
|
|