Refactor exam_take function to use a canonical list of questions for consistent indexing and improved error handling for question navigation

This commit is contained in:
Ross
2025-11-10 21:18:58 +00:00
parent 922ca5053f
commit 9cf7ad6da7
2 changed files with 244 additions and 168 deletions
+17 -10
View File
@@ -188,7 +188,16 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
)
def exam_take(request, pk: int, sk: int, cid: str| None = None, passcode: str| None = None):
def exam_take(request, pk: int, sk: int, cid: str | None = None, passcode: str | None = None):
"""Display and handle answers for a single question in a physics exam.
Behavior and invariants:
- Uses a single canonical list of questions (from `exam.get_questions()`) for
selection, navigation and sizing so indexes cannot drift.
- Validates the incoming question index and raises 404 for invalid values.
- Supports candidate (cid) and logged-in user answers.
"""
exam = get_object_or_404(Exam, pk=pk)
if not exam.active:
@@ -198,25 +207,23 @@ def exam_take(request, pk: int, sk: int, cid: str| None = None, passcode: str| N
cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
# Use a single, canonical list of questions for all indexing/navigation
# operations to avoid mismatches between different querysets or orderings.
# Canonical questions list for consistent indexing/navigation
questions = list(exam.get_questions())
# Validate sk and select the current question
# Normalize and validate provided index
try:
sk = int(sk)
index = int(sk)
except Exception:
raise Http404("Invalid question index")
if sk < 0 or sk >= len(questions):
if index < 0 or index >= len(questions):
raise Http404("Question not found in exam")
question = questions[sk]
question = questions[index]
exam_length = len(questions)
# Since we're using the canonical list, the positional index is sk.
pos = sk
# local numeric position equals the validated index
pos = index
if cid is not None:
answer = question.cid_user_answers.filter(cid=cid, exam=exam).first()