From 650678b1f3a9762b15f4db926c287557a9419f14 Mon Sep 17 00:00:00 2001 From: SebF Date: Mon, 14 Apr 2025 17:45:29 +0200 Subject: [PATCH] ajout de pages aux vues generales --- src/agenda_culturel/urls.py | 20 +- .../views/general_pages_views.py | 211 +++++++++++++++++- src/agenda_culturel/views/oldviews.py | 198 +--------------- 3 files changed, 217 insertions(+), 212 deletions(-) diff --git a/src/agenda_culturel/urls.py b/src/agenda_culturel/urls.py index 28fd6b8..66bd2c3 100644 --- a/src/agenda_culturel/urls.py +++ b/src/agenda_culturel/urls.py @@ -35,15 +35,20 @@ from .views import ( update_duplicate_event, # General pages about, + activite, + delete_cm_spam, + home, import_requirements, mentions_legales, moderation_rules, + statistics, thank_you, # Import batch imports, add_import, cancel_import, update_orphan_events, + view_messages, # Import récurrent RecurrentImportCreateView, RecurrentImportDeleteView, @@ -86,7 +91,6 @@ from .views import ( UnknownPlacesListView, fix_unknown_places, # TODO pas encore trié - home, week_view, month_view, day_view, @@ -94,7 +98,6 @@ from .views import ( export_ical, recent, administration, - activite, clear_cache, export_event_ical, MessageDeleteView, @@ -106,16 +109,13 @@ from .views import ( EventCreateView, event_search, event_search_full, - delete_cm_spam, update_from_source, change_status_event, EventDeleteView, import_event_proxy, import_from_url, import_from_urls, - view_messages, MessageUpdateView, - statistics, UserProfileUpdateView, ) @@ -189,10 +189,15 @@ urlpatterns = [ path("duplicates//fix", fix_duplicate, name="fix_duplicate"), # General pages path("a-propos", about, name="about"), + path("activite/", activite, name="activite"), + path("messages/spams/delete", delete_cm_spam, name="delete_cm_spam"), + path("", home, name="home"), path("besoin-pour-import", import_requirements, name="import_requirements"), path("mentions-legales", mentions_legales, name="mentions_legales"), path("regles-de-moderation", moderation_rules, name="moderation_rules"), + path("statistiques", statistics, name="statistics"), path("merci", thank_you, name="thank_you"), + path("messages", view_messages, name="messages"), # Import batch path("imports/", imports, name="imports"), path("imports/add", add_import, name="add_import"), @@ -350,7 +355,6 @@ urlpatterns = [ name="fix_unknown_places", ), # TODO pas encore trié - path("", home, name="home"), path("cat:/", home, name="home_category"), path( "cat:/semaine///", @@ -407,7 +411,6 @@ urlpatterns = [ path("tags/add", TagCreateView.as_view(), name="add_tag"), path("recent/", recent, name="recent"), path("administration/", administration, name="administration"), - path("activite/", activite, name="activite"), path( "event////-", EventDetailView.as_view(), @@ -464,9 +467,6 @@ urlpatterns = [ path("rechercher", event_search, name="event_search"), path("rechercher/complet/", event_search_full, name="event_search_full"), path("contact", MessageCreateView.as_view(), name="contact"), - path("messages", view_messages, name="messages"), - path("statistiques", statistics, name="statistics"), - path("messages/spams/delete", delete_cm_spam, name="delete_cm_spam"), path( "message/", MessageUpdateView.as_view(), diff --git a/src/agenda_culturel/views/general_pages_views.py b/src/agenda_culturel/views/general_pages_views.py index d6ccbee..0619d0f 100644 --- a/src/agenda_culturel/views/general_pages_views.py +++ b/src/agenda_culturel/views/general_pages_views.py @@ -1,11 +1,26 @@ -from django.db.models import Q +import calendar as _calendar +from datetime import date, timedelta, datetime + +from django.contrib.auth.decorators import login_required, permission_required +from django.core.checks import messages +from django.core.paginator import PageNotAnInteger, EmptyPage +from django.db.models import Count, F +from django.db.models import Q, Min, Max, Avg, StdDev +from django.db.models.functions import TruncMonth, ExtractDay +from django.http import HttpResponseRedirect from django.shortcuts import render from django.urls import reverse_lazy - -from ..models import RecurrentImport - from django.utils.translation import gettext_lazy as _ +from . import Median, week_view, PaginatorFilter +from ..filters import MessagesFilterAdmin +from ..models import RecurrentImport, Event, Message + + +def home(request, cat=None): + return week_view(request, home=True, cat=cat) + + def thank_you(request): return render(request, "agenda_culturel/thank_you.html") @@ -49,4 +64,190 @@ def import_requirements(request): "static_content": "import_requirements", "url_path": reverse_lazy("import_requirements"), } - return render(request, "agenda_culturel/page-single.html", context) \ No newline at end of file + return render(request, "agenda_culturel/page-single.html", context) + + +def statistics(request, pk=None): + if pk is not None: + rimport = RecurrentImport.objects.filter(pk=pk) + source = rimport.values("source").first()["source"] + qs = Event.objects.filter(import_sources__contains=[source]) + else: + rimport = None + qs = Event.objects + + stats = {} + stats_months = {} + first = {} + last = {} + + ev_published = qs.filter( + Q(status=Event.STATUS.PUBLISHED) + & ( + Q(other_versions__isnull=True) + | Q(other_versions__representative=F("pk")) + | Q(other_versions__representative__isnull=True) + ) + ) + + for v in ["start_day", "created_date__date"]: + after = 24 + last[v] = ( + date.today() + if v == "created_date__date" + else date.today() + timedelta(weeks=after) + ) + last[v] = last[v].replace( + day=_calendar.monthrange(last[v].year, last[v].month)[1] + ) + + r = 8 * 30 + if v == "start_day": + r += after * 7 + first[v] = (last[v] - timedelta(days=r)).replace(day=1) + + ev_days = ev_published.annotate(day=F(v)).filter( + Q(day__lte=last[v]) & Q(day__gte=first[v]) + ) + + stats[v] = ev_days.values("day").annotate(total=Count("day")).order_by("day") + + stats_months[v] = ( + ev_days.annotate(month=TruncMonth("day")) + .values("month") + .annotate(total=Count("month")) + .order_by("month") + ) + + nb_by_city = ( + ev_published.annotate(city=F("exact_location__city")) + .filter(city__isnull=False) + .values("city") + .annotate(total=Count("city")) + .order_by("-total") + ) + + limit = datetime.now() + timedelta(days=-30) + + stat_qs = qs.filter(start_day__gte=F("created_date")).annotate( + foresight=ExtractDay(F("start_day") - F("created_date")) + ) + + statsa = stat_qs.filter().aggregate( + minimum=Min("foresight"), + maximum=Max("foresight"), + mean=Avg("foresight"), + median=Median("foresight"), + stdev=StdDev("foresight"), + ) + + statsm = stat_qs.filter(created_date__gte=limit).aggregate( + minimum=Min("foresight"), + maximum=Max("foresight"), + mean=Avg("foresight"), + median=Median("foresight"), + stdev=StdDev("foresight"), + ) + + stats_foresight = [ + [ + _(x), + round(statsa[x], 2) if statsa[x] is not None else "-", + round(statsm[x], 2) if statsm[x] is not None else "-", + ] + for x in statsa + ] + + context = { + "stats_by_startday": stats["start_day"], + "stats_by_creation": stats["created_date__date"], + "stats_months_by_startday": stats_months["start_day"], + "stats_months_by_creation": stats_months["created_date__date"], + "first_by_startday": first["start_day"], + "last_by_startday": last["start_day"], + "first_by_creation": first["created_date__date"], + "last_by_creation": last["created_date__date"], + "nb_by_city": nb_by_city, + "stats_foresight": stats_foresight, + "object": rimport.first() if rimport else None, + } + + if pk is None: + return render(request, "agenda_culturel/statistics.html", context) + else: + return render(request, "agenda_culturel/rimport-statistics.html", context) + + +@login_required(login_url="/accounts/login/") +@permission_required("agenda_culturel.view_event") +def activite(request): + now = date.today() + + days = [now] + while len(days) < 7 or days[-1].weekday() != 0: + days.append(days[-1] + timedelta(days=-1)) + + weeks = [days[-1]] + for w in range(0, 8): + weeks.append(weeks[-1] + timedelta(days=-7)) + + daily_modifications = Event.get_count_modifications([(d, 1) for d in days]) + weekly_modifications = Event.get_count_modifications([(w, 7) for w in weeks]) + + return render( + request, + "agenda_culturel/page-activity.html", + { + "daily_modifications": daily_modifications, + "weekly_modifications": weekly_modifications, + }, + ) + + +@login_required(login_url="/accounts/login/") +@permission_required("agenda_culturel.view_message") +def view_messages(request): + filter = MessagesFilterAdmin( + request.GET, queryset=Message.objects.all().order_by("-date") + ) + paginator = PaginatorFilter(filter, 10, request) + page = request.GET.get("page") + + nb_spams = Message.objects.filter(spam=True).count() + + try: + response = paginator.page(page) + except PageNotAnInteger: + response = paginator.page(1) + except EmptyPage: + response = paginator.page(paginator.num_pages) + + return render( + request, + "agenda_culturel/messages.html", + {"filter": filter, "nb_spams": nb_spams, "paginator_filter": response}, + ) + + +@login_required(login_url="/accounts/login/") +@permission_required("agenda_culturel.view_message") +def delete_cm_spam(request): + if request.method == "POST": + Message.objects.filter(spam=True).delete() + + messages.success(request, _("Spam has been successfully deleted.")) + return HttpResponseRedirect(reverse_lazy("messages")) + else: + nb_msgs = Message.objects.values("spam").annotate(total=Count("spam")) + nb_total = sum([nb["total"] for nb in nb_msgs]) + nb_spams = sum([nb["total"] for nb in nb_msgs if nb["spam"]]) + cancel_url = reverse_lazy("messages") + return render( + request, + "agenda_culturel/delete_spams_confirm.html", + { + "nb_total": nb_total, + "nb_spams": nb_spams, + "cancel_url": cancel_url, + }, + ) diff --git a/src/agenda_culturel/views/oldviews.py b/src/agenda_culturel/views/oldviews.py index 3799dfa..312cc50 100644 --- a/src/agenda_culturel/views/oldviews.py +++ b/src/agenda_culturel/views/oldviews.py @@ -1,4 +1,3 @@ -import calendar as _calendar import hashlib import logging from datetime import date, timedelta @@ -15,11 +14,7 @@ from django.contrib.messages.views import SuccessMessageMixin from django.core.cache import cache from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.db.models import Aggregate, FloatField -from django.db.models import Avg, Max, Min -from django.db.models import Count, F, Func, OuterRef, Q, Subquery -from django.db.models.aggregates import StdDev -from django.db.models.functions import ExtractDay -from django.db.models.functions import TruncMonth +from django.db.models import F, Func, OuterRef, Q, Subquery from django.http import ( HttpResponse, HttpResponseForbidden, @@ -50,7 +45,6 @@ from ..celery import ( from ..filters import ( EventFilter, EventFilterAdmin, - MessagesFilterAdmin, SearchEventFilter, SimpleSearchEventFilter, ) @@ -148,10 +142,6 @@ to_be_translated = [ ] -def home(request, cat=None): - return week_view(request, home=True, cat=cat) - - def month_view(request, year=None, month=None, cat=None): now = date.today() if year is None and month is None: @@ -1011,32 +1001,6 @@ class MessageUpdateView( return kwargs -@login_required(login_url="/accounts/login/") -@permission_required("agenda_culturel.view_event") -def activite(request): - now = date.today() - - days = [now] - while len(days) < 7 or days[-1].weekday() != 0: - days.append(days[-1] + timedelta(days=-1)) - - weeks = [days[-1]] - for w in range(0, 8): - weeks.append(weeks[-1] + timedelta(days=-7)) - - daily_modifications = Event.get_count_modifications([(d, 1) for d in days]) - weekly_modifications = Event.get_count_modifications([(w, 7) for w in weeks]) - - return render( - request, - "agenda_culturel/page-activity.html", - { - "daily_modifications": daily_modifications, - "weekly_modifications": weekly_modifications, - }, - ) - - @login_required(login_url="/accounts/login/") @permission_required("agenda_culturel.view_event") def administration(request): @@ -1145,55 +1109,6 @@ def recent(request): ) -@login_required(login_url="/accounts/login/") -@permission_required("agenda_culturel.view_message") -def view_messages(request): - filter = MessagesFilterAdmin( - request.GET, queryset=Message.objects.all().order_by("-date") - ) - paginator = PaginatorFilter(filter, 10, request) - page = request.GET.get("page") - - nb_spams = Message.objects.filter(spam=True).count() - - try: - response = paginator.page(page) - except PageNotAnInteger: - response = paginator.page(1) - except EmptyPage: - response = paginator.page(paginator.num_pages) - - return render( - request, - "agenda_culturel/messages.html", - {"filter": filter, "nb_spams": nb_spams, "paginator_filter": response}, - ) - - -@login_required(login_url="/accounts/login/") -@permission_required("agenda_culturel.view_message") -def delete_cm_spam(request): - if request.method == "POST": - Message.objects.filter(spam=True).delete() - - messages.success(request, _("Spam has been successfully deleted.")) - return HttpResponseRedirect(reverse_lazy("messages")) - else: - nb_msgs = Message.objects.values("spam").annotate(total=Count("spam")) - nb_total = sum([nb["total"] for nb in nb_msgs]) - nb_spams = sum([nb["total"] for nb in nb_msgs if nb["spam"]]) - cancel_url = reverse_lazy("messages") - return render( - request, - "agenda_culturel/delete_spams_confirm.html", - { - "nb_total": nb_total, - "nb_spams": nb_spams, - "cancel_url": cancel_url, - }, - ) - - def event_search(request, full=False): categories = None tags = None @@ -1289,117 +1204,6 @@ def event_search_full(request): return event_search(request, True) -def statistics(request, pk=None): - if pk is not None: - rimport = RecurrentImport.objects.filter(pk=pk) - source = rimport.values("source").first()["source"] - qs = Event.objects.filter(import_sources__contains=[source]) - else: - rimport = None - qs = Event.objects - - stats = {} - stats_months = {} - first = {} - last = {} - - ev_published = qs.filter( - Q(status=Event.STATUS.PUBLISHED) - & ( - Q(other_versions__isnull=True) - | Q(other_versions__representative=F("pk")) - | Q(other_versions__representative__isnull=True) - ) - ) - - for v in ["start_day", "created_date__date"]: - after = 24 - last[v] = ( - date.today() - if v == "created_date__date" - else date.today() + timedelta(weeks=after) - ) - last[v] = last[v].replace( - day=_calendar.monthrange(last[v].year, last[v].month)[1] - ) - - r = 8 * 30 - if v == "start_day": - r += after * 7 - first[v] = (last[v] - timedelta(days=r)).replace(day=1) - - ev_days = ev_published.annotate(day=F(v)).filter( - Q(day__lte=last[v]) & Q(day__gte=first[v]) - ) - - stats[v] = ev_days.values("day").annotate(total=Count("day")).order_by("day") - - stats_months[v] = ( - ev_days.annotate(month=TruncMonth("day")) - .values("month") - .annotate(total=Count("month")) - .order_by("month") - ) - - nb_by_city = ( - ev_published.annotate(city=F("exact_location__city")) - .filter(city__isnull=False) - .values("city") - .annotate(total=Count("city")) - .order_by("-total") - ) - - limit = datetime.now() + timedelta(days=-30) - - stat_qs = qs.filter(start_day__gte=F("created_date")).annotate( - foresight=ExtractDay(F("start_day") - F("created_date")) - ) - - statsa = stat_qs.filter().aggregate( - minimum=Min("foresight"), - maximum=Max("foresight"), - mean=Avg("foresight"), - median=Median("foresight"), - stdev=StdDev("foresight"), - ) - - statsm = stat_qs.filter(created_date__gte=limit).aggregate( - minimum=Min("foresight"), - maximum=Max("foresight"), - mean=Avg("foresight"), - median=Median("foresight"), - stdev=StdDev("foresight"), - ) - - stats_foresight = [ - [ - _(x), - round(statsa[x], 2) if statsa[x] is not None else "-", - round(statsm[x], 2) if statsm[x] is not None else "-", - ] - for x in statsa - ] - - context = { - "stats_by_startday": stats["start_day"], - "stats_by_creation": stats["created_date__date"], - "stats_months_by_startday": stats_months["start_day"], - "stats_months_by_creation": stats_months["created_date__date"], - "first_by_startday": first["start_day"], - "last_by_startday": last["start_day"], - "first_by_creation": first["created_date__date"], - "last_by_creation": last["created_date__date"], - "nb_by_city": nb_by_city, - "stats_foresight": stats_foresight, - "object": rimport.first() if rimport else None, - } - - if pk is None: - return render(request, "agenda_culturel/statistics.html", context) - else: - return render(request, "agenda_culturel/rimport-statistics.html", context) - - def clear_cache(request): if request.method == "POST": cache.clear()