Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize the logic of attemping a comp #96

Merged
merged 17 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2545b81
modify the behaviour of quiz_attempt, add quiz availability check
yunho7687 Jan 27, 2025
915dfcb
Add extension time to Student model and update QuizAttempt logic
yunho7687 Jan 28, 2025
93fc0bd
Remove debug print statements from QuizAttempt and User serializers
yunho7687 Jan 28, 2025
fb34d6d
Add dead_line field to QuizAttempt model and update availability logic
yunho7687 Jan 28, 2025
d24f762
Update QuizAttempt model to handle extension time and adjust dead_lin…
yunho7687 Jan 28, 2025
dd034d0
Refactor Quiz serializers to include UserQuizSerializer and update Qu…
yunho7687 Jan 29, 2025
2569706
feat(auth): add custom 'role' field to JWT token, reconnect client-se…
loklokyx Jan 25, 2025
ffa27f7
feat(auth): remove unwanted fields from JWT payload and implement rol…
loklokyx Jan 25, 2025
255b6cd
fix(api): resolve CORS issue and configure auth token for API requests
loklokyx Jan 25, 2025
ebe8fd3
added answer model
thnorton Jan 25, 2025
43588a8
add nested answer creation
thnorton Jan 25, 2025
238aa6c
Refactor question model and serializer: remove answer fields, add sol…
yunho7687 Jan 25, 2025
1f8f717
modify QuestionViewSet to validate answers on create and update
yunho7687 Jan 25, 2025
2f0f587
fix: remove unnecessary blank line in QuestionSerializer
yunho7687 Jan 25, 2025
ba89946
feat: add pagination settings to REST framework configuration
yunho7687 Jan 25, 2025
c3a57a6
reverse change
yunho7687 Jan 25, 2025
edde25a
Add marking action to AdminQuizViewSet for grading quiz attempts; add…
yunho7687 Jan 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 5.1.5 on 2025-01-27 04:05

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("quiz", "0009_quizattempt_team"),
("team", "0003_alter_teammember_student_alter_teammember_team"),
]

operations = [
migrations.AlterField(
model_name="quizattempt",
name="team",
field=models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="quiz_attempts",
to="team.team",
),
),
migrations.AlterField(
model_name="quizattempt",
name="time_finish",
field=models.DateTimeField(blank=True, null=True),
),
]
27 changes: 27 additions & 0 deletions server/api/quiz/migrations/0011_alter_quizattempt_student.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.1.5 on 2025-01-27 14:22

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("quiz", "0010_alter_quizattempt_team_alter_quizattempt_time_finish"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AlterField(
model_name="quizattempt",
name="student",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="quiz_attempts",
to=settings.AUTH_USER_MODEL,
),
),
]
26 changes: 26 additions & 0 deletions server/api/quiz/migrations/0012_alter_quizattempt_student.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.1.5 on 2025-01-27 14:27

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("quiz", "0011_alter_quizattempt_student"),
("users", "0002_school_is_country_school_type_student_attendent_year"),
]

operations = [
migrations.AlterField(
model_name="quizattempt",
name="student",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="quiz_attempts",
to="users.student",
),
),
]
30 changes: 26 additions & 4 deletions server/api/quiz/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from api.team.models import Team
from api.users.models import Student
from api.question.models import Question
from django.utils.timezone import now
from datetime import timedelta


class Quiz(models.Model):
Expand Down Expand Up @@ -87,14 +89,16 @@ class State(models.IntegerChoices):
Student, on_delete=models.CASCADE, related_name="quiz_attempts", default=None, null=True
)
current_page = models.IntegerField()
state = models.IntegerField(choices=State.choices, default=State.UNATTEMPTED)
state = models.IntegerField(
choices=State.choices, default=State.UNATTEMPTED)
time_start = models.DateTimeField(auto_now_add=True)
time_finish = models.DateTimeField(null=True)
time_finish = models.DateTimeField(null=True, blank=True)
time_modified = models.DateTimeField(auto_now=True)
total_marks = models.IntegerField()
team = models.ForeignKey(
Team, on_delete=models.CASCADE, related_name="quiz_attempts", default=None, null=True
Team, on_delete=models.CASCADE, related_name="quiz_attempts", default=None, null=True, blank=True
)
# dead_line = models.DateTimeField(default=None, null=True, blank=True)

def __str__(self):
return f"{self.id} {self.quiz} "
Expand All @@ -104,6 +108,24 @@ def check_all_answer(self):
question_attempt.check_answer()
question_attempt.save()

@property
def is_available(self):
current_time = now()
end_time = self.quiz.open_time_date + \
timedelta(minutes=self.quiz.time_limit) + \
timedelta(minutes=self.quiz.time_window)
end_time = min(end_time, self.time_start +
timedelta(minutes=self.quiz.time_limit))
if self.student.extenstion_time:
end_time = now() + \
timedelta(minutes=self.student.extenstion_time)

is_available = self.quiz.open_time_date <= current_time <= end_time
if not is_available:
self.state = QuizAttempt.State.COMPLETED
self.save()
return is_available


class QuestionAttempt(models.Model):
id = models.AutoField(primary_key=True)
Expand All @@ -117,7 +139,7 @@ class QuestionAttempt(models.Model):
is_correct = models.BooleanField(default=None)

def __str__(self):
return f"{self.id} {self.question_id} {self.quiz_attempt_id}"
return f"{self.id} {self.question} {self.quiz_attempt}"

def check_answer(self):
if self.answer_student == self.question.answer:
Expand Down
20 changes: 20 additions & 0 deletions server/api/quiz/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ class Meta:
fields = '__all__'


class CompQuestionSerializer(serializers.ModelSerializer):
"""
Serializer for the Question model with no answer field.
"""
class Meta:
model = Question
fields = ['id', 'name', 'question_text', 'layout', 'image', 'mark']


class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
Expand Down Expand Up @@ -39,6 +48,14 @@ class Meta:
read_only_fields = ['quiz']


class CompQuizSlotSerializer(serializers.ModelSerializer):
question = CompQuestionSerializer(read_only=True)

class Meta:
model = QuizSlot
fields = '__all__'


class QuizSerializer(serializers.ModelSerializer):

class Meta:
Expand All @@ -53,6 +70,9 @@ class Meta:


class QuizAttemptSerializer(serializers.ModelSerializer):
current_page = serializers.IntegerField(default=0, required=False)
total_marks = serializers.IntegerField(default=0, required=False)

class Meta:
model = QuizAttempt
fields = '__all__'
Expand Down
Loading
Loading