ajout de pages aux vues generales

This commit is contained in:
SebF 2025-04-14 17:45:29 +02:00
parent 9ec22919f1
commit 650678b1f3
3 changed files with 217 additions and 212 deletions

View File

@ -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/<int:pk>/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:<cat>/", home, name="home_category"),
path(
"cat:<cat>/semaine/<int:year>/<int:week>/",
@ -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/<int:year>/<int:month>/<int:day>/<int:pk>-<extra>",
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/<int:pk>",
MessageUpdateView.as_view(),

View File

@ -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)
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,
},
)

View File

@ -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()