Add exam review links to navigation in multiple templates
This commit is contained in:
@@ -11,5 +11,6 @@
|
|||||||
<a href="{% url 'anatomy:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
<a href="{% url 'anatomy:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
||||||
<a href="{% url 'anatomy:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
<a href="{% url 'anatomy:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<a href="{% url 'anatomy:exam_review_start' pk=exam.pk %}">Review</a>
|
||||||
{% comment %} <a href="{% url 'anatomy:question_create_exam' pk=exam.pk %}" title="Add a new question directly into the exam.">Add New Question</a> {% endcomment %}
|
{% comment %} <a href="{% url 'anatomy:question_create_exam' pk=exam.pk %}" title="Add a new question directly into the exam.">Add New Question</a> {% endcomment %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@
|
|||||||
{% if collection %}
|
{% if collection %}
|
||||||
{% include "atlas/collection_headers.html" %}
|
{% include "atlas/collection_headers.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if exam %}
|
||||||
|
<a href="{% url 'atlas:exam_review_start' pk=exam.pk %}">Review</a> /
|
||||||
|
{% endif %}
|
||||||
{% comment %} Collection: {{collection.name}}-> <a href="{% url 'atlas:collection_detail' pk=exam.pk %}">Overview</a> /
|
{% comment %} Collection: {{collection.name}}-> <a href="{% url 'atlas:collection_detail' pk=exam.pk %}">Overview</a> /
|
||||||
<a href="{% url 'atlas:collection_mark_overview' exam.pk %}">Mark</a> /
|
<a href="{% url 'atlas:collection_mark_overview' exam.pk %}">Mark</a> /
|
||||||
<a href="{% url 'atlas:collection_scores_cid' exam.pk %}">Scores</a> /
|
<a href="{% url 'atlas:collection_scores_cid' exam.pk %}">Scores</a> /
|
||||||
|
|||||||
@@ -3223,6 +3223,61 @@ class GenericViewBase:
|
|||||||
|
|
||||||
return render(request, "generic/partials/question_reviews_list.html", {"question": question, "reviews": reviews, "app_name": self.app_name})
|
return render(request, "generic/partials/question_reviews_list.html", {"question": question, "reviews": reviews, "app_name": self.app_name})
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def exam_review_start(self, request, pk):
|
||||||
|
"""Start a per-question review for an exam. Redirects to the first question."""
|
||||||
|
# Ensure the user can edit the exam (authors only)
|
||||||
|
if not self.check_user_edit_access(request.user, exam_id=pk):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
exam = get_object_or_404(self.exam_object, pk=pk)
|
||||||
|
|
||||||
|
# Materialise ordered questions
|
||||||
|
questions = list(exam.get_questions())
|
||||||
|
if not questions:
|
||||||
|
return render(request, "generic/exam_review_complete.html", {"exam": exam, "app_name": self.app_name})
|
||||||
|
|
||||||
|
# Render the first question
|
||||||
|
return self.exam_review_question(request, pk, q_index=0)
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def exam_review_question(self, request, pk, q_index=0):
|
||||||
|
"""Render a single question from an exam for review with navigation."""
|
||||||
|
if not self.check_user_edit_access(request.user, exam_id=pk):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
exam = get_object_or_404(self.exam_object, pk=pk)
|
||||||
|
|
||||||
|
questions = list(exam.get_questions())
|
||||||
|
total = len(questions)
|
||||||
|
|
||||||
|
try:
|
||||||
|
q_index = int(q_index)
|
||||||
|
except Exception:
|
||||||
|
q_index = 0
|
||||||
|
|
||||||
|
if q_index < 0 or q_index >= total:
|
||||||
|
# Out of range — render complete
|
||||||
|
return render(request, "generic/exam_review_complete.html", {"exam": exam, "app_name": self.app_name})
|
||||||
|
|
||||||
|
question = questions[q_index]
|
||||||
|
|
||||||
|
prev_index = q_index - 1 if q_index > 0 else None
|
||||||
|
next_index = q_index + 1 if q_index < total - 1 else None
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"exam": exam,
|
||||||
|
"question": question,
|
||||||
|
"q_index": q_index,
|
||||||
|
"total": total,
|
||||||
|
"prev_index": prev_index,
|
||||||
|
"next_index": next_index,
|
||||||
|
"app_name": self.app_name,
|
||||||
|
"can_edit": self.check_user_edit_access(request.user, exam_id=pk),
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "generic/exam_review_question.html", context)
|
||||||
|
|
||||||
def question_review_start(self, request):
|
def question_review_start(self, request):
|
||||||
|
|
||||||
# Prepare category choices if the question model exposes a FK named 'category'
|
# Prepare category choices if the question model exposes a FK named 'category'
|
||||||
|
|||||||
@@ -9,4 +9,5 @@
|
|||||||
<a href="{% url 'longs:exam_scores_all' pk=exam.pk %}">Scores</a> /
|
<a href="{% url 'longs:exam_scores_all' pk=exam.pk %}">Scores</a> /
|
||||||
<a href="{% url 'longs:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
<a href="{% url 'longs:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
||||||
<a href="{% url 'longs:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
<a href="{% url 'longs:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
||||||
|
<a href="{% url 'longs:exam_review_start' pk=exam.pk %}">Review</a> /
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ Exams: {{exam}}-> <a href="{% url 'physics:exam_overview' pk=exam.pk %}">Overvie
|
|||||||
<a href="{% url 'physics:exam_scores_all' pk=exam.pk %}">Scores</a> /
|
<a href="{% url 'physics:exam_scores_all' pk=exam.pk %}">Scores</a> /
|
||||||
<a href="{% url 'physics:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
<a href="{% url 'physics:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
||||||
<a href="{% url 'physics:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
<a href="{% url 'physics:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
||||||
|
<a href="{% url 'physics:exam_review_start' pk=exam.pk %}">Review</a> /
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -12,4 +12,5 @@
|
|||||||
<a href="{% url 'rapids:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
<a href="{% url 'rapids:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'rapids:question_create_exam' pk=exam.pk %}">Add New Question</a>
|
<a href="{% url 'rapids:question_create_exam' pk=exam.pk %}">Add New Question</a>
|
||||||
|
<a href="{% url 'rapids:exam_review_start' pk=exam.pk %}">Review</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -8,4 +8,5 @@
|
|||||||
<a href="{% url 'sbas:exam_scores_all' pk=exam.pk %}">Scores</a> /
|
<a href="{% url 'sbas:exam_scores_all' pk=exam.pk %}">Scores</a> /
|
||||||
<a href="{% url 'sbas:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
<a href="{% url 'sbas:exam_cids' exam_id=exam.pk %}">Candidates</a> /
|
||||||
<a href="{% url 'sbas:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
<a href="{% url 'sbas:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
||||||
|
<a href="{% url 'sbas:exam_review_start' pk=exam.pk %}">Review</a> /
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -12,4 +12,5 @@
|
|||||||
<a href="{% url 'shorts:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
<a href="{% url 'shorts:exam_stats' exam_id=exam.pk %}">Stats</a> /
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'shorts:question_create_exam' pk=exam.pk %}">Add New Question</a>
|
<a href="{% url 'shorts:question_create_exam' pk=exam.pk %}">Add New Question</a>
|
||||||
|
<a href="{% url 'shorts:exam_review_start' pk=exam.pk %}">Review</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user