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, Q from django.db.models.functions import TruncDate from apps.account.models import User, LoginHistory from apps.course.models import Course, Participant, CourseLiveSession from apps.course.models.course import extract_text_from_json 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( Q(user_type=User.UserType.STUDENT) | Q(user_type=User.UserType.CLIENT), is_active=True ).count() professors = User.objects.filter(user_type=User.UserType.PROFESSOR, is_active=True).count() active_courses = Course.objects.filter(status__contains=[{"title": 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 (30d sum of successful transactions) revenue_result = TransactionParticipant.objects.filter( status=TransactionParticipant.TransactionStatus.SUCCESS, created_at__gte=thirty_days_ago ).aggregate(total=Sum('price')) revenue_30d = float(revenue_result['total'] or 0.0) # 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_pipeline = {"name": "Courses"} for choice in Course.StatusChoices.values: course_pipeline[choice] = Course.objects.filter(status__contains=[{"title": choice}]).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() title_text = extract_text_from_json(course.title) course_efficacy.append({ "title": title_text[:20] + "..." if len(title_text) > 20 else title_text, "enrolled": enrolled, "completed": completed }) # --------------------------------------------------------- # 3. LISTS & LEADERBOARDS # --------------------------------------------------------- # Top 5 Courses (List) top_courses_list = [ { "id": c.id, "title": extract_text_from_json(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 } })