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.
69 lines
2.5 KiB
69 lines
2.5 KiB
from rest_framework import serializers
|
|
|
|
from apps.course.access import user_has_course_access
|
|
from apps.quiz.models import QuizParticipant, ParticipantAnswer
|
|
|
|
|
|
class ParticipantAnswerSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = ParticipantAnswer
|
|
fields = ['question', 'option_num', 'at_time', 'answer_timing']
|
|
|
|
|
|
|
|
class QuizParticipantSerializer(serializers.ModelSerializer):
|
|
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
|
|
answers = ParticipantAnswerSerializer(many=True)
|
|
|
|
def validate_quiz(self, obj):
|
|
if QuizParticipant.objects.filter(quiz=obj, user=self.context['request'].user).exists():
|
|
raise serializers.ValidationError('you have already participated in the quiz')
|
|
|
|
course = getattr(obj, 'course', None)
|
|
if course and not user_has_course_access(self.context['request'].user, course):
|
|
raise serializers.ValidationError('you do not have access to this quiz')
|
|
|
|
return obj
|
|
|
|
class Meta:
|
|
model = QuizParticipant
|
|
fields = [
|
|
'quiz', 'user', 'started_at', 'ended_at', 'total_timing',
|
|
'question_score', 'timing_score', 'total_score',
|
|
'answers',
|
|
]
|
|
|
|
def create(self, validated_data):
|
|
answers = validated_data.pop('answers', [])
|
|
|
|
quiz = validated_data.get('quiz')
|
|
total_questions = quiz.questions.count()
|
|
correct_count = 0
|
|
questions_map = {q.id: q.correct_answer for q in quiz.questions.all()}
|
|
|
|
for ans in answers:
|
|
# Depending on if ans['question'] is an instance or ID
|
|
q_id = ans.get('question').id if hasattr(ans.get('question'), 'id') else ans.get('question')
|
|
option_num = ans.get('option_num')
|
|
if q_id in questions_map and questions_map[q_id] == option_num:
|
|
correct_count += 1
|
|
|
|
question_score = round((correct_count / total_questions) * 100) if total_questions > 0 else 0
|
|
|
|
validated_data['question_score'] = question_score
|
|
validated_data['timing_score'] = 0
|
|
validated_data['total_score'] = question_score
|
|
|
|
obj = super().create(validated_data)
|
|
answers_objs = []
|
|
for ans in answers:
|
|
answers_objs.append(
|
|
ParticipantAnswer(
|
|
participant=obj,
|
|
**ans,
|
|
)
|
|
)
|
|
|
|
ParticipantAnswer.objects.bulk_create(answers_objs)
|
|
|
|
return obj
|