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.
 
 

257 lines
10 KiB

from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field, OpenApiTypes
from apps.lms.models import (
Course,
CourseModule,
Lesson,
QuizQuestion,
CourseEnrollment,
LessonProgress,
DigitalCertificate,
)
class QuizQuestionStudentSerializer(serializers.ModelSerializer):
class Meta:
model = QuizQuestion
fields = ['id', 'question_text', 'options', 'order']
class QuizQuestionAdminSerializer(serializers.ModelSerializer):
class Meta:
model = QuizQuestion
fields = ['id', 'question_text', 'options', 'correct_option_index', 'explanation', 'order']
class LessonListSerializer(serializers.ModelSerializer):
is_completed = serializers.SerializerMethodField()
class Meta:
model = Lesson
fields = [
'id', 'title', 'slug', 'lesson_type',
'duration_minutes', 'order', 'is_preview',
'is_completed',
]
@extend_schema_field(OpenApiTypes.BOOL)
def get_is_completed(self, obj) -> bool:
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
return LessonProgress.objects.filter(
user=request.user,
lesson=obj,
is_completed=True
).exists()
return False
class LessonDetailSerializer(serializers.ModelSerializer):
quiz_questions = serializers.SerializerMethodField()
is_completed = serializers.SerializerMethodField()
quiz_score = serializers.SerializerMethodField()
class Meta:
model = Lesson
fields = [
'id', 'title', 'slug', 'lesson_type',
'duration_minutes', 'video_url', 'content',
'slides_attachment', 'order', 'is_preview',
'quiz_questions', 'is_completed', 'quiz_score',
]
@extend_schema_field(QuizQuestionStudentSerializer(many=True))
def get_quiz_questions(self, obj):
questions = obj.quiz_questions.all().order_by('order', 'id')
request = self.context.get('request')
if request and request.user and request.user.is_authenticated and (request.user.is_staff or getattr(request.user, 'is_super_admin', False)):
return QuizQuestionAdminSerializer(questions, many=True).data
return QuizQuestionStudentSerializer(questions, many=True).data
@extend_schema_field(OpenApiTypes.BOOL)
def get_is_completed(self, obj) -> bool:
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
progress = LessonProgress.objects.filter(user=request.user, lesson=obj).first()
return progress.is_completed if progress else False
return False
@extend_schema_field(OpenApiTypes.FLOAT)
def get_quiz_score(self, obj):
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
progress = LessonProgress.objects.filter(user=request.user, lesson=obj).first()
return progress.quiz_score if progress else None
return None
class CourseModuleSerializer(serializers.ModelSerializer):
lessons = LessonListSerializer(many=True, read_only=True)
class Meta:
model = CourseModule
fields = ['id', 'title', 'description', 'order', 'lessons']
class CourseListSerializer(serializers.ModelSerializer):
total_lessons = serializers.IntegerField(source='total_lessons_count', read_only=True)
total_students = serializers.IntegerField(source='total_students_count', read_only=True)
is_enrolled = serializers.SerializerMethodField()
progress_percentage = serializers.SerializerMethodField()
class Meta:
model = Course
fields = [
'id', 'title', 'slug', 'category', 'language',
'level', 'cover_image', 'instructor_name',
'instructor_title', 'instructor_avatar',
'organization_name', 'duration_hours', 'rating',
'reviews_count', 'is_featured', 'total_lessons',
'total_students', 'is_enrolled', 'progress_percentage',
'created_at',
]
@extend_schema_field(OpenApiTypes.BOOL)
def get_is_enrolled(self, obj) -> bool:
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
return CourseEnrollment.objects.filter(user=request.user, course=obj).exists()
return False
@extend_schema_field(OpenApiTypes.INT)
def get_progress_percentage(self, obj) -> int:
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
enrollment = CourseEnrollment.objects.filter(user=request.user, course=obj).first()
return enrollment.progress_percentage if enrollment else 0
return 0
class CourseDetailSerializer(serializers.ModelSerializer):
modules = CourseModuleSerializer(many=True, read_only=True)
total_lessons = serializers.IntegerField(source='total_lessons_count', read_only=True)
total_students = serializers.IntegerField(source='total_students_count', read_only=True)
is_enrolled = serializers.SerializerMethodField()
progress_percentage = serializers.SerializerMethodField()
certificate_code = serializers.SerializerMethodField()
class Meta:
model = Course
fields = [
'id', 'title', 'slug', 'category', 'language',
'level', 'cover_image', 'instructor_name',
'instructor_title', 'instructor_avatar',
'institution', 'organization_name', 'description',
'duration_hours', 'rating', 'reviews_count',
'is_published', 'is_featured', 'modules',
'total_lessons', 'total_students',
'is_enrolled', 'progress_percentage', 'certificate_code',
'created_at', 'updated_at',
]
@extend_schema_field(OpenApiTypes.BOOL)
def get_is_enrolled(self, obj) -> bool:
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
return CourseEnrollment.objects.filter(user=request.user, course=obj).exists()
return False
@extend_schema_field(OpenApiTypes.INT)
def get_progress_percentage(self, obj) -> int:
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
enrollment = CourseEnrollment.objects.filter(user=request.user, course=obj).first()
return enrollment.progress_percentage if enrollment else 0
return 0
@extend_schema_field(OpenApiTypes.STR)
def get_certificate_code(self, obj):
request = self.context.get('request')
if request and request.user and request.user.is_authenticated:
cert = DigitalCertificate.objects.filter(user=request.user, course=obj).first()
return cert.certificate_code if cert else None
return None
class CourseCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = [
'id', 'title', 'category', 'language', 'level',
'cover_image', 'instructor_name', 'instructor_title',
'instructor_avatar', 'institution', 'organization_name',
'description', 'duration_hours', 'is_published', 'is_featured',
]
class SingleQuizAnswerSerializer(serializers.Serializer):
question_id = serializers.IntegerField()
selected_option = serializers.IntegerField()
class QuizSubmitRequestSerializer(serializers.Serializer):
answers = SingleQuizAnswerSerializer(many=True)
class QuizQuestionResultItemSerializer(serializers.Serializer):
question_id = serializers.IntegerField()
is_correct = serializers.BooleanField()
selected_option = serializers.IntegerField()
correct_option = serializers.IntegerField()
explanation = serializers.CharField(allow_blank=True, allow_null=True)
class QuizResultSerializer(serializers.Serializer):
score = serializers.FloatField(help_text="Percentage score achieved (0-100)")
passed = serializers.BooleanField(help_text="True if score >= 70%")
total_questions = serializers.IntegerField()
correct_count = serializers.IntegerField()
question_results = QuizQuestionResultItemSerializer(many=True)
is_lesson_completed = serializers.BooleanField()
course_progress_percentage = serializers.IntegerField()
certificate_code = serializers.CharField(allow_null=True, required=False)
class LessonCompleteResponseSerializer(serializers.Serializer):
message = serializers.CharField()
lesson_id = serializers.IntegerField()
is_completed = serializers.BooleanField()
course_progress_percentage = serializers.IntegerField()
certificate_code = serializers.CharField(allow_null=True, required=False)
class CourseProgressSerializer(serializers.Serializer):
course_id = serializers.IntegerField()
course_title = serializers.CharField()
progress_percentage = serializers.IntegerField()
completed_lessons_count = serializers.IntegerField()
total_lessons_count = serializers.IntegerField()
is_completed = serializers.BooleanField()
certificate_code = serializers.CharField(allow_null=True)
class DigitalCertificateSerializer(serializers.ModelSerializer):
course_title = serializers.CharField(source='course.title', read_only=True)
course_slug = serializers.CharField(source='course.slug', read_only=True)
recipient_name = serializers.CharField(source='user.get_full_name', read_only=True)
organization = serializers.CharField(source='course.organization_name', read_only=True)
class Meta:
model = DigitalCertificate
fields = [
'id', 'certificate_code', 'uuid',
'recipient_name', 'course_title', 'course_slug',
'organization', 'issue_date', 'final_score',
'certificate_file', 'is_revoked', 'created_at',
]
class PublicCertificateVerifySerializer(serializers.Serializer):
certificate_code = serializers.CharField()
uuid = serializers.UUIDField()
recipient_name = serializers.CharField()
course_title = serializers.CharField()
organization = serializers.CharField(allow_null=True)
issue_date = serializers.DateField()
final_score = serializers.FloatField()
is_valid = serializers.BooleanField()