You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

153 lines
6.9 KiB

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
class AdminDashboardStatsView(APIView):
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
}
})