Ilo/apps/enrollments/api/serializers.py
2026-05-02 20:01:30 +03:30

173 lines
6.1 KiB
Python

from rest_framework import serializers
from apps.courses.api.serializers import (
CategorySerializer,
CourseFAQSerializer,
CourseHighlightSerializer,
LessonReadSerializer,
SectionReadSerializer,
)
from apps.courses.models import Lesson, LessonStatus
from apps.enrollments.models import Enrollment, LessonProgress
class EnrolledCourseSummarySerializer(serializers.Serializer):
"""Used by the my-courses dashboard list. Mirrors the design's MY_COURSES shape."""
id = serializers.IntegerField()
slug = serializers.CharField()
title = serializers.CharField()
tagline = serializers.CharField()
color = serializers.CharField()
cover_image = serializers.SerializerMethodField()
instructor_id = serializers.IntegerField()
instructor_name = serializers.SerializerMethodField()
enrolled_at = serializers.DateTimeField()
completed_at = serializers.DateTimeField(allow_null=True)
progress_percent = serializers.IntegerField()
completed_lessons = serializers.IntegerField()
total_lessons = serializers.IntegerField()
last_lesson_id = serializers.IntegerField(allow_null=True)
last_lesson_title = serializers.CharField(allow_null=True)
next_lesson_id = serializers.IntegerField(allow_null=True)
next_lesson_title = serializers.CharField(allow_null=True)
def get_cover_image(self, obj):
url = obj.get("cover_image_url")
request = self.context.get("request")
if url and request:
return request.build_absolute_uri(url)
return url
def get_instructor_name(self, obj):
return obj.get("instructor_name")
class StudentCourseDetailSerializer(serializers.Serializer):
"""Full course detail for an enrolled student — all published lesson content unlocked."""
id = serializers.IntegerField()
slug = serializers.CharField()
title = serializers.CharField()
tagline = serializers.CharField()
description = serializers.CharField()
level = serializers.CharField()
language = serializers.CharField()
color = serializers.CharField()
cover_image = serializers.SerializerMethodField()
instructor_id = serializers.IntegerField()
instructor_name = serializers.CharField()
category = CategorySerializer(allow_null=True)
highlights = CourseHighlightSerializer(many=True)
faqs = CourseFAQSerializer(many=True)
sections = serializers.SerializerMethodField()
enrollment = serializers.SerializerMethodField()
def get_cover_image(self, obj):
course = obj["course"]
if not course.cover_image:
return None
request = self.context.get("request")
if request:
return request.build_absolute_uri(course.cover_image.url)
return course.cover_image.url
def get_sections(self, obj):
course = obj["course"]
completed_lesson_ids = obj["completed_lesson_ids"]
sections = course.sections.all().prefetch_related(
"lessons"
)
out = []
for sec in sections:
published = [l for l in sec.lessons.all() if l.status == LessonStatus.PUBLISHED]
published.sort(key=lambda l: (l.order, l.id))
out.append({
"id": sec.id,
"title": sec.title,
"order": sec.order,
"lessons": LessonReadSerializer(
published, many=True
).data,
"lessons_completed": [
l.id for l in published if l.id in completed_lesson_ids
],
})
return out
def get_enrollment(self, obj):
e = obj["enrollment"]
return {
"enrolled_at": e.enrolled_at,
"completed_at": e.completed_at,
"progress_percent": e.progress_percent(),
"completed_lessons": e.completed_lessons_count(),
"total_lessons": e.total_lessons_count(),
}
class EnrollResponseSerializer(serializers.Serializer):
enrolled = serializers.BooleanField()
course_id = serializers.IntegerField()
course_slug = serializers.CharField()
enrolled_at = serializers.DateTimeField()
class LessonProgressResponseSerializer(serializers.ModelSerializer):
progress_percent = serializers.SerializerMethodField()
course_completed = serializers.SerializerMethodField()
class Meta:
model = LessonProgress
fields = ["id", "lesson", "completed_at", "progress_percent", "course_completed"]
read_only_fields = fields
def get_progress_percent(self, obj):
return obj.enrollment.progress_percent()
def get_course_completed(self, obj):
return obj.enrollment.is_completed
class InstructorEnrollmentSerializer(serializers.ModelSerializer):
"""Compact list view for the instructor's CRM-style student panel."""
student_id = serializers.IntegerField(source="student.id", read_only=True)
student_name = serializers.CharField(source="student.full_name", read_only=True)
student_phone = serializers.CharField(source="student.phone_number", read_only=True)
student_last_active_at = serializers.DateTimeField(source="student.last_active_at", read_only=True)
progress_percent = serializers.SerializerMethodField()
completed_lessons = serializers.SerializerMethodField()
total_lessons = serializers.SerializerMethodField()
engagement_status = serializers.SerializerMethodField()
class Meta:
model = Enrollment
fields = [
"id",
"student_id",
"student_name",
"student_phone",
"student_last_active_at",
"course_id",
"enrolled_at",
"completed_at",
"progress_percent",
"completed_lessons",
"total_lessons",
"engagement_status",
]
read_only_fields = fields
def get_progress_percent(self, obj):
return obj.progress_percent()
def get_completed_lessons(self, obj):
return obj.completed_lessons_count()
def get_total_lessons(self, obj):
return obj.total_lessons_count()
def get_engagement_status(self, obj):
return obj.engagement_status()