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.
 
 
 
 

139 lines
5.8 KiB

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication
from django.utils import timezone
from datetime import timedelta
from django.db.models import Count, Q
from django.db.models.functions import TruncDate
from apps.account.models import User
from apps.course.models import Course, Participant
from apps.course.models.course import extract_text_from_json
from apps.quiz.models import Quiz, QuizParticipant
from apps.chat.models import ChatMessage, RoomMessage
from apps.api.permissions import IsProfessorUser
class ProfessorDashboardStatsView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated, IsProfessorUser]
def get(self, request):
now = timezone.now()
thirty_days_ago = now - timedelta(days=30)
# ---------------------------------------------------------
# 1. CARDS & BASIC STATS
# ---------------------------------------------------------
# Total courses taught by this professor
courses_count = Course.objects.filter(professor=request.user).count()
# Total unique active students enrolled in this professor's courses
students_count = Participant.objects.filter(
course__professor=request.user,
is_active=True
).values('student').distinct().count()
# Total quizzes created in this professor's courses
quizzes_count = Quiz.objects.filter(course__professor=request.user).count()
# Chat rooms count (group rooms for professor's courses + private chats with professor)
chat_rooms_count = RoomMessage.objects.filter(
Q(course__professor=request.user) |
(Q(room_type=RoomMessage.RoomTypeChoices.PRIVATE) & (Q(initiator=request.user) | Q(recipient=request.user)))
).distinct().count()
# ---------------------------------------------------------
# 2. CHARTS DATA
# ---------------------------------------------------------
# Chat Volume Trend (30 days)
professor_rooms = RoomMessage.objects.filter(
Q(course__professor=request.user) |
(Q(room_type=RoomMessage.RoomTypeChoices.PRIVATE) & (Q(initiator=request.user) | Q(recipient=request.user)))
)
chat_volume = ChatMessage.objects.filter(
room__in=professor_rooms,
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 Efficacy: Completed vs Enrolled (Bar Chart for Top 5 Courses)
top_courses_qs = Course.objects.filter(professor=request.user).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
})
# Quiz Participation statistics (all quizzes of the professor)
quizzes = Quiz.objects.filter(course__professor=request.user)
quizzes_stats = []
for quiz in quizzes:
course = quiz.course
if not course:
continue
total_enrolled = Participant.objects.filter(course=course, is_active=True).count()
participated = QuizParticipant.objects.filter(quiz=quiz).values('user').distinct().count()
not_participated = max(0, total_enrolled - participated)
quizzes_stats.append({
"id": quiz.id,
"title": quiz.title,
"course_title": extract_text_from_json(course.title),
"participated": participated,
"not_participated": not_participated,
})
# ---------------------------------------------------------
# 3. LISTS & LEADERBOARDS
# ---------------------------------------------------------
# Top Courses List
top_courses_list = [
{
"id": c.id,
"title": extract_text_from_json(c.title),
"participants": c.participant_count
} for c in top_courses_qs
]
# Leaderboard (Top 5 Performing Students in professor's quizzes)
top_students = QuizParticipant.objects.filter(
quiz__course__professor=request.user
).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": {
"courses_count": courses_count,
"students_count": students_count,
"quizzes_count": quizzes_count,
"chat_rooms_count": chat_rooms_count,
},
"charts": {
"chat_volume": chat_chart,
"course_efficacy": course_efficacy,
"quizzes_stats": quizzes_stats
},
"lists": {
"top_courses": top_courses_list,
"leaderboard": leaderboard
}
})