""" Vues pour le tableau de bord d'analytics. """ from django.shortcuts import render from django.contrib.auth.decorators import user_passes_test from django.utils import timezone from django.db.models import Count, Avg, Q, F from django.db.models.functions import TruncDate, TruncHour from datetime import timedelta import json from .models import PageView, UserSession from django.contrib.auth.models import User def superuser_required(view_func): """Décorateur qui vérifie que l'utilisateur est un superadmin.""" decorated_view = user_passes_test( lambda u: u.is_active and u.is_superuser, login_url='admin:login' )(view_func) return decorated_view @superuser_required def dashboard(request): """ Vue principale du tableau de bord d'analytics. Affiche les statistiques d'utilisation de l'application. """ # Période à analyser (par défaut: 30 derniers jours) days = int(request.GET.get('days', 30)) start_date = timezone.now() - timedelta(days=days) # Statistiques générales stats = { 'total_users': User.objects.filter(is_active=True).count(), 'active_users': _get_active_users_count(start_date), 'total_sessions': UserSession.objects.filter(login_time__gte=start_date).count(), 'active_sessions': UserSession.objects.filter(is_active=True).count(), 'total_page_views': PageView.objects.filter(timestamp__gte=start_date).count(), 'avg_response_time': PageView.objects.filter( timestamp__gte=start_date, response_time_ms__isnull=False ).aggregate(avg=Avg('response_time_ms'))['avg'] or 0, } # Calculer les sessions par utilisateur (éviter la division par zéro) stats['sessions_per_user'] = ( round(stats['total_sessions'] / stats['active_users'], 2) if stats['active_users'] > 0 else 0 ) # Pages les plus visitées top_pages = PageView.objects.filter( timestamp__gte=start_date ).values('path').annotate( count=Count('id') ).order_by('-count')[:10] # Utilisateurs les plus actifs top_users = PageView.objects.filter( timestamp__gte=start_date, user__isnull=False ).values('user__username', 'user__id').annotate( views=Count('id'), sessions=Count('session_key', distinct=True) ).order_by('-views')[:10] # Activité par jour daily_activity = PageView.objects.filter( timestamp__gte=start_date ).annotate( date=TruncDate('timestamp') ).values('date').annotate( views=Count('id'), users=Count('user', distinct=True), sessions=Count('session_key', distinct=True) ).order_by('date') # Préparer les données pour les graphiques chart_data = { 'labels': [item['date'].strftime('%d/%m') for item in daily_activity], 'views': [item['views'] for item in daily_activity], 'users': [item['users'] for item in daily_activity], 'sessions': [item['sessions'] for item in daily_activity], } # Activité par heure (dernières 24h) yesterday = timezone.now() - timedelta(days=1) hourly_activity = PageView.objects.filter( timestamp__gte=yesterday ).annotate( hour=TruncHour('timestamp') ).values('hour').annotate( count=Count('id') ).order_by('hour') hourly_chart_data = { 'labels': [item['hour'].strftime('%H:%M') for item in hourly_activity], 'values': [item['count'] for item in hourly_activity], } context = { 'stats': stats, 'top_pages': top_pages, 'top_users': top_users, 'chart_data': json.dumps(chart_data), 'hourly_chart_data': json.dumps(hourly_chart_data), 'days': days, } return render(request, 'analytics/dashboard.html', context) @superuser_required def sessions_list(request): """ Liste détaillée des sessions utilisateurs. """ # Paramètres de filtrage days = int(request.GET.get('days', 30)) user_id = request.GET.get('user') active_only = request.GET.get('active_only', False) start_date = timezone.now() - timedelta(days=days) # Requête de base sessions = UserSession.objects.filter( login_time__gte=start_date ).select_related('user') # Filtres if user_id: sessions = sessions.filter(user_id=user_id) if active_only: sessions = sessions.filter(is_active=True) # Ordre sessions = sessions.order_by('-login_time') # Pagination (simple, 100 par page) sessions = sessions[:100] # Liste des utilisateurs pour le filtre users = User.objects.filter( analytics_sessions__login_time__gte=start_date ).distinct().order_by('username') context = { 'sessions': sessions, 'users': users, 'selected_user_id': user_id, 'active_only': active_only, 'days': days, } return render(request, 'analytics/sessions_list.html', context) @superuser_required def page_views_list(request): """ Liste détaillée des vues de pages. """ # Paramètres de filtrage days = int(request.GET.get('days', 7)) # Par défaut 7 jours car il peut y avoir beaucoup de données user_id = request.GET.get('user') path = request.GET.get('path') start_date = timezone.now() - timedelta(days=days) # Requête de base page_views = PageView.objects.filter( timestamp__gte=start_date ).select_related('user') # Filtres if user_id: page_views = page_views.filter(user_id=user_id) if path: page_views = page_views.filter(path__icontains=path) # Ordre page_views = page_views.order_by('-timestamp') # Pagination (simple, 100 par page) page_views = page_views[:100] # Liste des utilisateurs et chemins pour les filtres users = User.objects.filter( page_views__timestamp__gte=start_date ).distinct().order_by('username') popular_paths = PageView.objects.filter( timestamp__gte=start_date ).values('path').annotate( count=Count('id') ).order_by('-count')[:20] context = { 'page_views': page_views, 'users': users, 'popular_paths': popular_paths, 'selected_user_id': user_id, 'selected_path': path, 'days': days, } return render(request, 'analytics/page_views_list.html', context) def _get_active_users_count(start_date): """ Compte le nombre d'utilisateurs actifs depuis start_date. Un utilisateur est considéré actif s'il a au moins une page view. """ return User.objects.filter( page_views__timestamp__gte=start_date ).distinct().count()