from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated, IsAdminUser from django.utils import timezone from datetime import timedelta from django.db.models import Count, Sum from django.db.models.functions import TruncDate from apps.account.models import User, LoginHistory from apps.course.models import Course, Participant, CourseLiveSession from apps.quiz.models import QuizParticipant from apps.blog.models import Blog from apps.chat.models import ChatMessage, RoomMessage from apps.transaction.models import TransactionParticipant from apps.certificate.models import Certificate from rest_framework.authentication import TokenAuthentication class AdminDashboardStatsView(APIView): authentication_classes = [TokenAuthentication] permission_classes = [IsAuthenticated, IsAdminUser] def get(self, request): now = timezone.now() thirty_days_ago = now - timedelta(days=30) # --------------------------------------------------------- # 1. CARDS & BASIC STATS # --------------------------------------------------------- active_students = User.objects.filter(groups__name="Student Group", is_active=True).count() professors = User.objects.filter(groups__name="Professor Group", is_active=True).count() active_courses = Course.objects.filter(status=Course.StatusChoices.ONGOING).count() total_blogs = Blog.objects.count() pending_certificates = Certificate.objects.filter(status='pending').count() active_live_sessions = CourseLiveSession.objects.filter(ended_at__isnull=True).count() # Revenue (Mocked for 30d sum) revenue_30d = 12500.00 # Dummy data # Private vs Group Chat Usage chat_types = RoomMessage.objects.values('room_type').annotate(count=Count('id')) chat_type_stats = {item['room_type']: item['count'] for item in chat_types} # --------------------------------------------------------- # 2. CHARTS DATA # --------------------------------------------------------- # Payment Methods (Pie Chart) payment_methods = TransactionParticipant.objects.values('payment_method').annotate(total=Count('id')) payment_method_chart = [ {"name": item['payment_method'], "value": item['total']} for item in payment_methods ] # Transaction Status (Donut Chart) transaction_status = TransactionParticipant.objects.values('status').annotate(total=Count('id')) transaction_chart = [ {"name": item['status'], "value": item['total']} for item in transaction_status ] # Global Student Distribution (Bar Chart) top_countries = LoginHistory.objects.exclude(country__isnull=True).exclude(country="").values('country').annotate( count=Count('id') ).order_by('-count')[:5] country_chart = [{"country": item['country'], "students": item['count']} for item in top_countries] # New User Registrations Trend (Line Chart) registrations = User.objects.filter(date_joined__gte=thirty_days_ago).annotate( date=TruncDate('date_joined') ).values('date').annotate(count=Count('id')).order_by('date') registration_chart = [{"date": item['date'].strftime('%Y-%m-%d'), "users": item['count']} for item in registrations] # Community Chat Volume Trend (Area Chart) chat_volume = ChatMessage.objects.filter(sent_at__gte=thirty_days_ago).annotate( date=TruncDate('sent_at') ).values('date').annotate(count=Count('id')).order_by('date') chat_chart = [{"date": item['date'].strftime('%Y-%m-%d'), "messages": item['count']} for item in chat_volume] # Course Pipeline (Stacked Bar) course_statuses = Course.objects.values('status').annotate(count=Count('id')) course_pipeline = {"name": "Courses"} for status in course_statuses: course_pipeline[status['status']] = status['count'] # Course Efficacy: Completed vs Enrolled (Bar Chart) # We take the top 5 courses, check how many users are enrolled, and how many have at least 1 completed lesson top_courses_qs = Course.objects.annotate(participant_count=Count('participants')).order_by('-participant_count')[:5] course_efficacy = [] for course in top_courses_qs: enrolled = course.participant_count completed = Participant.objects.filter( course=course, student__lesson_completions__course_lesson__course=course ).distinct().count() course_efficacy.append({ "title": course.title[:20] + "..." if len(course.title) > 20 else course.title, "enrolled": enrolled, "completed": completed }) # --------------------------------------------------------- # 3. LISTS & LEADERBOARDS # --------------------------------------------------------- # Top 5 Courses (List) top_courses_list = [ { "id": c.id, "title": c.title, "professor": c.professor.fullname if c.professor else "Unknown", "participants": c.participant_count } for c in top_courses_qs ] # Top 5 Blogs (List) top_blogs = Blog.objects.order_by('-views_count')[:5] top_blogs_list = [ {"id": b.id, "title": b._extract_text_from_json(b.title), "views": b.views_count} for b in top_blogs ] # Top Performing Students (Leaderboard) top_students = QuizParticipant.objects.select_related('user').order_by('-total_score', 'total_timing')[:5] leaderboard = [ {"id": s.user.id, "name": s.user.fullname, "score": s.total_score, "time": s.total_timing} for s in top_students ] return Response({ "cards": { "active_students": active_students, "professors": professors, "active_courses": active_courses, "total_blogs": total_blogs, "revenue_30d": revenue_30d, "pending_certificates": pending_certificates, "active_live_sessions": active_live_sessions, "group_rooms": chat_type_stats.get('group', 0), "private_rooms": chat_type_stats.get('private', 0), }, "charts": { "transactions_status": transaction_chart, "payment_methods": payment_method_chart, "countries": country_chart, "registrations": registration_chart, "chat_volume": chat_chart, "course_pipeline": [course_pipeline], "course_efficacy": course_efficacy }, "lists": { "top_courses": top_courses_list, "top_blogs": top_blogs_list, "leaderboard": leaderboard } })