from typing import List from rest_framework import serializers from django.utils.translation import gettext as _ from labs.models import LabQuizSubmission as DBLabQuizSubmission class LabQuizSubmissionGetSerializer(serializers.ModelSerializer): answers = serializers.SerializerMethodField(method_name="get_answers") class Meta: model = DBLabQuizSubmission fields = ["answers", "created_at", "updated_at"] def get_answers(self, obj): quiz = self.context["lab_quiz"] data = [] for _answer in obj.answers: _data = { "user_answer": _answer["user_answer"], } if quiz.evaluate_immediately: _data["is_correct"] = _answer["is_correct"] if quiz.show_correct_answer: _data["correct_answer"] = _answer["correct_answer"] _data["explanation"] = _answer["explanation"] data.append(_data) return data class LabQuizSubmissionPostSerializer(serializers.Serializer): answers = serializers.ListField( child=serializers.ListField( child=serializers.IntegerField(), ), allow_empty=False, ) def validate_answers(self, answers: List[List[int]]): quiz = self.context["lab_quiz"] if len(answers) != len(quiz.questions): raise serializers.ValidationError( _("The number of answers does not match the number of quiz questions.") ) self.quiz_result = [] self.score = 0 for idx, (user_answer, question) in enumerate(zip(answers, quiz.questions)): user_answer = set(user_answer) option_ids = set() correct_option_ids = set() for option in question["options"]: option_ids.add(option["id"]) if option["correct"]: correct_option_ids.add(option["id"]) if not user_answer.issubset(option_ids): raise serializers.ValidationError( _("Answer [{idx}] options are invalid.").format(idx=idx) ) if user_answer == correct_option_ids: is_correct = True self.score += 1 else: is_correct = False self.quiz_result.append( { "is_correct": is_correct, "user_answer": list(user_answer), "correct_answer": list(correct_option_ids), "explanation": question["explanation"], } ) return answers def validate(self, attrs): quiz = self.context["lab_quiz"] quiz_submission = self.instance if not quiz.allow_repeat_submission and quiz_submission: raise serializers.ValidationError( _( "This quiz has already been submitted before and cannot be submitted again." ) ) return attrs def create(self, validated_data): return DBLabQuizSubmission.objects.create( lab_instance=self.context["lab_instance"], lab_quiz=self.context["lab_quiz"], user=self.context["request"].user, answers=self.quiz_result, score=self.score, ) def update(self, instance, validated_data): instance.answers = self.quiz_result instance.score = self.score instance.save() return instance