From 7869abf44138c00bd00f7f825e683f910fa6bb00 Mon Sep 17 00:00:00 2001 From: mrtoine Date: Tue, 16 Dec 2025 10:48:12 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20de=20la=20vue=20`stats=5Fcharts`=20avec?= =?UTF-8?q?=20graphiques=20d=C3=A9taill=C3=A9s=20pour=20les=20superadminis?= =?UTF-8?q?trateurs,=20mise=20=C3=A0=20jour=20des=20templates=20et=20des?= =?UTF-8?q?=20routes=20associ=C3=A9es,=20et=20configuration=20suppl=C3=A9m?= =?UTF-8?q?entaire=20pour=20l'email=20backend.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devart/settings.py | 7 ++- home/urls.py | 1 + home/views.py | 94 +++++++++++++++++++++++++++++ templates/home/stats_dashboard.html | 1 + 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/devart/settings.py b/devart/settings.py index d5b3597..f846daa 100644 --- a/devart/settings.py +++ b/devart/settings.py @@ -207,4 +207,9 @@ def get_git_version(): GIT_VERSION = get_git_version() EMAIL_BACKEND = dotenv.get_key('.env', 'EMAIL_BACKEND') -DEFAULT_FROM_EMAIL = dotenv.get_key('.env', 'EMAIL_HOST_USER') \ No newline at end of file +EMAIL_HOST = dotenv.get_key('.env', 'EMAIL_HOST') +EMAIL_PORT = dotenv.get_key('.env', 'EMAIL_PORT') +EMAIL_USE_TLS = dotenv.get_key('.env', 'EMAIL_USE_TLS') == 'True' +EMAIL_HOST_USER = dotenv.get_key('.env', 'EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = dotenv.get_key('.env', 'EMAIL_HOST_PASSWORD') +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER \ No newline at end of file diff --git a/home/urls.py b/home/urls.py index 80f5069..1dbd960 100644 --- a/home/urls.py +++ b/home/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ path('premium/', views.premium, name='premium'), # Tableau de bord statistiques (réservé superadministrateurs) path('dashboard/stats/', views.stats_dashboard, name='stats_dashboard'), + path('dashboard/stats/charts/', views.stats_charts, name='stats_charts'), ] \ No newline at end of file diff --git a/home/views.py b/home/views.py index 159fb3f..ebd2cf2 100644 --- a/home/views.py +++ b/home/views.py @@ -199,3 +199,97 @@ def stats_dashboard(request): context['labels_json'] = json.dumps(context['series']['days']) return render(request, 'home/stats_dashboard.html', context) + + +@user_passes_test(lambda u: u.is_superuser) +@cache_page(60 * 15) +def stats_charts(request): + """Page dédiée aux graphiques (réservée superadmins).""" + # 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) + period_start_date = start_dt.date() + period_end_date = now.date() + + # Trafic par jour (visiteurs uniques) + visits_qs = ( + Visit.objects + .filter(date__gte=period_start_date, date__lte=period_end_date) + .values('date') + .annotate(c=Count('visitor_id', distinct=True)) + .order_by('date') + ) + + # Conversions par jour (visiteurs devenus utilisateurs) + conversions_qs = ( + Visit.objects + .filter( + became_user_at__isnull=False, + became_user_at__date__gte=period_start_date, + became_user_at__date__lte=period_end_date, + ) + .extra(select={'day': "date(became_user_at)"}) + .values('day') + .annotate(c=Count('visitor_id', distinct=True)) + .order_by('day') + ) + + def build_series_dict(qs, date_key='date', count_key='c'): + counts = {str(item[date_key]): item[count_key] for item in qs} + days = [] + values = [] + d = period_start_date + while d <= period_end_date: + key = str(d) + days.append(key) + values.append(counts.get(key, 0)) + 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') + + # Sources & Pays (sur la période) + period_visits = Visit.objects.filter(date__gte=period_start_date, date__lte=period_end_date) + top_sources_qs = ( + period_visits + .values('source') + .annotate(c=Count('visitor_id', distinct=True)) + .order_by('-c')[:10] + ) + top_countries_qs = ( + period_visits + .exclude(country='') + .values('country') + .annotate(c=Count('visitor_id', distinct=True)) + .order_by('-c')[:10] + ) + + sources_labels = [(row['source'] or 'Direct/Unknown') for row in top_sources_qs] + sources_values = [row['c'] for row in top_sources_qs] + countries_labels = [row['country'] for row in top_countries_qs] + countries_values = [row['c'] for row in top_countries_qs] + + context = { + 'period_options': period_options, + 'p': p, + 'start_date': period_start_date, + 'end_date': period_end_date, + 'labels_json': json.dumps(labels), + 'visitors_series_json': json.dumps(visitors_series), + 'conversions_series_json': json.dumps(conversions_series), + 'sources_labels_json': json.dumps(sources_labels), + 'sources_values_json': json.dumps(sources_values), + 'countries_labels_json': json.dumps(countries_labels), + 'countries_values_json': json.dumps(countries_values), + } + + return render(request, 'home/stats_charts.html', context) diff --git a/templates/home/stats_dashboard.html b/templates/home/stats_dashboard.html index 84a7094..3dddab3 100644 --- a/templates/home/stats_dashboard.html +++ b/templates/home/stats_dashboard.html @@ -20,6 +20,7 @@ {% block content %}

Tableau de bord statistiques

+

→ Voir la page de graphiques