Mise à jour de la version applicative dans VERSION.txt.

This commit is contained in:
mrtoine 2025-12-16 15:03:46 +01:00
parent d20302be0e
commit 18b807bf5a
3 changed files with 65 additions and 85 deletions

View file

@ -11,6 +11,49 @@ from progression.models import Progression
import json
from django.http import JsonResponse
# --------------------
# Helpers Stats Module
# --------------------
def _parse_period(request, default=30, options=None):
"""Parse period parameter 'p' from request and compute date range.
Returns (p, now_dt, start_dt, start_date, end_date)
- now_dt is timezone-aware now
- start_dt is datetime at start of range (inclusive)
- start_date/end_date are date objects for convenient filtering
"""
if options is None:
options = [7, 30, 90, 180]
try:
p = int(request.GET.get('p', default))
except (TypeError, ValueError):
p = default
if p not in options:
p = default
now_dt = timezone.now()
start_dt = now_dt - timezone.timedelta(days=p - 1)
return p, now_dt, start_dt, start_dt.date(), now_dt.date()
def _build_series_for_range(start_date, end_date, qs, date_key='day', count_key='c'):
"""Build a continuous daily series from an aggregated queryset.
qs must yield dicts with date_key (date as string or date) and count_key.
Returns (labels_days, values_counts)
"""
counts = {str(item[date_key]): item[count_key] for item in qs}
days = []
values = []
d = start_date
while d <= end_date:
key = str(d)
days.append(key)
values.append(counts.get(key, 0))
d += timezone.timedelta(days=1)
return days, values
def home(request):
courses = Course.objects.order_by('-created_at')[:6]
return render(request, 'home.html', {'courses': courses})
@ -30,19 +73,13 @@ def stats_dashboard(request):
# Période
period_options = [7, 30, 90, 180]
try:
p = int(request.GET.get('p', 30))
except ValueError:
p = 30
if p not in period_options:
p = 30
now = timezone.now()
start_dt = now - timezone.timedelta(days=p-1) # inclut aujourd'hui
p, now, start_dt, period_start_date, period_end_date = _parse_period(
request, default=30, options=period_options
)
# Utilisateurs
total_users = User.objects.count()
new_users_qs = User.objects.filter(date_joined__date__gte=start_dt.date(), date_joined__date__lte=now.date())
new_users_qs = User.objects.filter(date_joined__date__gte=period_start_date, date_joined__date__lte=period_end_date)
# Séries quotidiennes nouveaux utilisateurs
new_users_by_day = (
new_users_qs
@ -53,7 +90,7 @@ def stats_dashboard(request):
# Activité approximée via Progression mise à jour
active_users_qs = (
Progression.objects.filter(updated_at__date__gte=start_dt.date(), updated_at__date__lte=now.date())
Progression.objects.filter(updated_at__date__gte=period_start_date, updated_at__date__lte=period_end_date)
.values('user').distinct()
)
active_users_count = active_users_qs.count()
@ -62,7 +99,7 @@ def stats_dashboard(request):
total_courses = Course.objects.count()
total_courses_enabled = Course.objects.filter(enable=True).count()
new_courses_by_day = (
Course.objects.filter(created_at__date__gte=start_dt.date(), created_at__date__lte=now.date())
Course.objects.filter(created_at__date__gte=period_start_date, created_at__date__lte=period_end_date)
.extra(select={'day': "date(created_at)"})
.values('day').annotate(c=Count('id'))
)
@ -83,7 +120,7 @@ def stats_dashboard(request):
# Si la table M2M n'a pas de timestamps, on utilisera updated_at de Progression pour l'activité par jour
# donc on refait une série quotidienne d'activité progression
progress_activity_by_day = (
Progression.objects.filter(updated_at__date__gte=start_dt.date(), updated_at__date__lte=now.date())
Progression.objects.filter(updated_at__date__gte=period_start_date, updated_at__date__lte=period_end_date)
.extra(select={'day': "date(updated_at)"})
.values('day').annotate(c=Count('id'))
)
@ -91,7 +128,7 @@ def stats_dashboard(request):
# Blog
total_posts = Post.objects.count()
new_posts_by_day = (
Post.objects.filter(created_at__date__gte=start_dt.date(), created_at__date__lte=now.date())
Post.objects.filter(created_at__date__gte=period_start_date, created_at__date__lte=period_end_date)
.extra(select={'day': "date(created_at)"})
.values('day').annotate(c=Count('id'))
)
@ -101,8 +138,6 @@ def stats_dashboard(request):
technique_disponible = False
# Visites / Trafic
period_start_date = start_dt.date()
period_end_date = now.date()
period_visits = Visit.objects.filter(date__gte=period_start_date, date__lte=period_end_date)
unique_visitors = period_visits.values('visitor_id').distinct().count()
@ -135,16 +170,8 @@ def stats_dashboard(request):
# Helper pour avoir toutes les dates de la période et remplir les trous
def build_series_dict(qs, date_key='day', count_key='c'):
counts = {str(item[date_key]): item[count_key] for item in qs}
days = []
values = []
d = start_dt.date()
while d <= now.date():
key = str(d)
days.append(key)
values.append(counts.get(key, 0))
d += timezone.timedelta(days=1)
return days, values
# Wrapper conservant l'API locale mais utilisant le helper commun
return _build_series_for_range(period_start_date, period_end_date, qs, date_key=date_key, count_key=count_key)
days_users, values_new_users = build_series_dict(new_users_by_day)
days_courses, values_new_courses = build_series_dict(new_courses_by_day)
@ -158,8 +185,8 @@ def stats_dashboard(request):
context = {
'period_options': period_options,
'p': p,
'start_date': start_dt.date(),
'end_date': now.date(),
'start_date': period_start_date,
'end_date': period_end_date,
# KPI
'kpi': {
@ -206,19 +233,11 @@ def stats_dashboard(request):
@cache_page(60 * 15)
def stats_charts(request):
"""Page dédiée aux graphiques (réservée superadmins)."""
# Période
# Période (utilise les mêmes helpers que le dashboard pour harmonisation)
period_options = [7, 30, 90, 180]
try:
p = int(request.GET.get('p', 30))
except ValueError:
p = 30
if p not in period_options:
p = 30
now = timezone.now()
start_dt = now - timezone.timedelta(days=p-1)
period_start_date = start_dt.date()
period_end_date = now.date()
p, _now, _start_dt, period_start_date, period_end_date = _parse_period(
request, default=30, options=period_options
)
# Trafic par jour (visiteurs uniques)
visits_qs = (
@ -255,8 +274,8 @@ def stats_charts(request):
d += timezone.timedelta(days=1)
return days, values
labels, visitors_series = build_series_dict(visits_qs, date_key='date')
_, conversions_series = build_series_dict(conversions_qs, date_key='day')
labels, visitors_series = _build_series_for_range(period_start_date, period_end_date, visits_qs, date_key='date')
_, conversions_series = _build_series_for_range(period_start_date, period_end_date, conversions_qs, date_key='day')
# Sources & Pays (sur la période)
period_visits = Visit.objects.filter(date__gte=period_start_date, date__lte=period_end_date)