diff --git a/core/middleware.py b/core/middleware.py index 3e76796..3167553 100644 --- a/core/middleware.py +++ b/core/middleware.py @@ -111,7 +111,11 @@ class VisitTrackingMiddleware: # Marquer la conversion si pas encore définie if visit.became_user_at is None: visit.became_user_at = now + # Mettre à jour la page courante et l'horodatage + if visit.path != path: + visit.path = path[:512] + dirty = True visit.last_seen = now dirty = True if dirty: - visit.save(update_fields=['source', 'country', 'user', 'became_user_at', 'last_seen']) + visit.save(update_fields=['source', 'country', 'user', 'became_user_at', 'path', 'last_seen']) diff --git a/home/urls.py b/home/urls.py index 1dbd960..52e2435 100644 --- a/home/urls.py +++ b/home/urls.py @@ -8,4 +8,5 @@ urlpatterns = [ # 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'), + path('dashboard/stats/live-activity/', views.live_activity, name='live_activity'), ] \ No newline at end of file diff --git a/home/views.py b/home/views.py index ebd2cf2..76fba86 100644 --- a/home/views.py +++ b/home/views.py @@ -9,6 +9,7 @@ from courses.models import Course, Lesson from blog.models import Post from progression.models import Progression import json +from django.http import JsonResponse def home(request): courses = Course.objects.order_by('-created_at')[:6] @@ -293,3 +294,44 @@ def stats_charts(request): } return render(request, 'home/stats_charts.html', context) + + +@user_passes_test(lambda u: u.is_superuser) +def live_activity(request): + """Retourne en JSON l'activité récente (5 dernières minutes): + visiteurs et utilisateurs et leur page actuelle. + """ + now = timezone.now() + since = now - timezone.timedelta(minutes=5) + qs = ( + Visit.objects + .filter(last_seen__gte=since) + .order_by('-last_seen') + ) + + data = [] + for v in qs[:200]: + username = None + is_user = False + if v.user_id: + is_user = True + # safe access if user deleted + try: + username = v.user.username + except Exception: + username = 'Utilisateur' + visitor_label = v.visitor_id[:8] + seconds_ago = int((now - v.last_seen).total_seconds()) + data.append({ + 'visitor': visitor_label, + 'is_user': is_user, + 'username': username, + 'path': v.path, + 'last_seen': v.last_seen.isoformat(), + 'seconds_ago': seconds_ago, + 'date': str(v.date), + 'country': v.country, + 'source': v.source, + }) + + return JsonResponse({'now': now.isoformat(), 'items': data}) diff --git a/static/css/app.css b/static/css/app.css index 367520c..a4ddad5 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -2330,6 +2330,16 @@ input[type="text"], input[type="email"], input[type="password"], textarea { filter: brightness(1.05); } +.btn-warning, .button-warning { + background-color: var(--warning); + border-color: var(--warning); + color: var(--warning-contrast); +} + +.btn-warning:hover, .button-warning:hover { + filter: brightness(1.05); +} + /* Tailles */ .btn-sm, .button-sm { padding: 6px 10px; font-size: 0.9rem; } .btn-lg, .button-lg { padding: 12px 20px; font-size: 1.05rem; } diff --git a/templates/home/stats_dashboard.html b/templates/home/stats_dashboard.html index 3dddab3..704ada6 100644 --- a/templates/home/stats_dashboard.html +++ b/templates/home/stats_dashboard.html @@ -20,7 +20,9 @@ {% block content %}