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
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()
|