Compare commits
13
Commits
9bf68cd136
...
dc4cf0c3a2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc4cf0c3a2 | ||
|
|
99b951b32b | ||
|
|
c2c8ec5b13 | ||
|
|
6d5303cd0d | ||
|
|
f6b990a00a | ||
|
|
3c0deec140 | ||
|
|
e3241b503d | ||
|
|
04174484b1 | ||
|
|
168a4126d3 | ||
|
|
a0850c0030 | ||
|
|
a882a3592b | ||
|
|
8074b56a80 | ||
|
|
2e79df1eae |
+4
-2
@@ -783,10 +783,12 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin):
|
||||
if self.start_date >= timezone.now() or (
|
||||
self.end_date is not None and self.end_date <= timezone.now()
|
||||
):
|
||||
raise Http404("Exam not found")
|
||||
# Raise with an explanatory message so the frontend can
|
||||
# surface the reason to the end user.
|
||||
raise Http404("Exam not currently available (outside allowed dates)")
|
||||
# If it is not active no one can take
|
||||
elif active_only and not self.active:
|
||||
raise Http404("Exam not found")
|
||||
raise Http404("Exam currently inactive")
|
||||
|
||||
# If candidates only check they have access
|
||||
if self.candidates_only:
|
||||
|
||||
+1
-1
@@ -455,7 +455,7 @@ def generic_exam_urls(generic_exam_view: GenericExamViews):
|
||||
name="exam_user_bulk_edit",
|
||||
),
|
||||
path(
|
||||
"exam/<int:pk>/scores",
|
||||
"exam/<int:pk>/scores/all",
|
||||
generic_exam_view.exam_scores_all,
|
||||
name="exam_scores_all",
|
||||
),
|
||||
|
||||
+2
-1
@@ -3576,7 +3576,7 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
|
||||
# Load questions; prefetch 'answers' for apps that use them to avoid repeated DB hits
|
||||
questions_qs = exam.get_questions()
|
||||
if self.app_name not in ("physics",):
|
||||
if self.app_name not in ("physics", "sbas"):
|
||||
questions_qs = questions_qs.prefetch_related("answers")
|
||||
|
||||
# Materialize questions list for iteration
|
||||
@@ -3694,6 +3694,7 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
#"cid_user_exam": cid_user_exam,
|
||||
}
|
||||
|
||||
template_context["normalised_score"] = None
|
||||
if self.normalise_score is not None:
|
||||
normalised_score = self.normalise_score(total_score)
|
||||
template_context["normalised_score"] = normalised_score
|
||||
|
||||
+4
-1
@@ -686,7 +686,10 @@ def stats(request):
|
||||
|
||||
# HTTP Error 400
|
||||
def page_not_found(request, exception):
|
||||
response = render(request, "404.html")
|
||||
# Provide the exception message (reason) to the template so callers
|
||||
# can show a user-friendly explanation when available.
|
||||
context = {"reason": str(exception) if exception is not None else "Not found"}
|
||||
response = render(request, "404.html", context=context)
|
||||
|
||||
response.status_code = 404
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h2>Start exam: {{exam}}</h2>
|
||||
<h2>Start exam: {{ exam }}</h2>
|
||||
|
||||
{% if exam.time_limit %}
|
||||
This exam has a time limit of {{ exam.get_time_limit }}. The time will start when you click the Start Exam button below.<br/>
|
||||
@@ -44,7 +44,10 @@
|
||||
let passcode = $("#passcode-box").val();
|
||||
|
||||
if (Number.isInteger(parseInt(cid))) {
|
||||
window.location.replace("{% url 'sbas:exam_take' pk=exam.pk sk=0 cid='0000000' passcode='ZZZZZZ' %}".replace("0000000", cid).replace("ZZZZZZ", passcode));
|
||||
// reverse a URL with safe placeholders and replace them client-side
|
||||
const template = "{% url 'sbas:exam_take' pk=exam.pk sk=0 cid=0 passcode='0' %}"; // e.g. /sbas/exam/1/0/0/0/take
|
||||
const url = template.replace('/0/0/take', `/${cid}/${passcode}/take`);
|
||||
window.location.replace(url);
|
||||
} else {
|
||||
alert("Please enter a valid Candidate ID (CID).")
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
|
||||
<details class="help-text pt-3">
|
||||
<summary><i class="bi bi-info-circle"></i> Help</summary>
|
||||
<p>Each question contains a list of 5 different statements. One of these is the single BEST answer.</p>
|
||||
<p>Click on the correct statement to select it. Once selected it will be highlighted. </p>
|
||||
<p>Your answers are saved when navigating between questions (or if the save button is clicked on the final question). An overview of all the questions can be seen by clicking on the overview button.</p>
|
||||
<p>Results are also available on the results page
|
||||
<a target="_blank" href="
|
||||
{% if cid %}
|
||||
{% url 'sbas:exam_scores_cid_user' pk=exam.pk cid=cid passcode=passcode %}
|
||||
{% else %}
|
||||
{% url 'sbas:exam_scores_user' pk=exam.pk %}
|
||||
{% endif %}
|
||||
">here</a>.</p>
|
||||
</details>
|
||||
<details class="help-text pt-3">
|
||||
<summary><i class="bi bi-info-circle"></i> Help</summary>
|
||||
<p>Each question contains a list of 5 different statements. One of these is the single BEST answer.</p>
|
||||
<p>Click on the correct statement to select it. Once selected it will be highlighted. </p>
|
||||
<p>Your answers are saved when navigating between questions (or if the save button is clicked on the final question). An overview of all the questions can be seen by clicking on the overview button.</p>
|
||||
{% if cid %}
|
||||
{% url 'sbas:exam_scores_cid_user' pk=exam.pk cid=cid passcode=passcode as scores_url %}
|
||||
{% else %}
|
||||
{% url 'sbas:exam_scores_user' pk=exam.pk as scores_url %}
|
||||
{% endif %}
|
||||
<p>Results are also available on the results page <a target="_blank" href="{{ scores_url }}">here</a>.</p>
|
||||
</details>
|
||||
@@ -134,16 +134,6 @@ urlpatterns = [
|
||||
),
|
||||
path("question/<int:pk>/toggle_frcr/", views.toggle_frcr_appropriate, name="toggle_frcr"),
|
||||
path("category/merge/", views.merge_category, name="merge_category"),
|
||||
#path(
|
||||
# "exam/<int:pk>/scores/<int:cid>/<str:passcode>/",
|
||||
# views.exam_scores_cid_user,
|
||||
# name="exam_scores_cid_user",
|
||||
#),
|
||||
#path(
|
||||
# "exam/<int:pk>/scores/",
|
||||
# views.exam_scores_cid_user,
|
||||
# name="exam_scores_user",
|
||||
#),
|
||||
]
|
||||
|
||||
urlpatterns.extend(generic_view_urls(views.GenericViews))
|
||||
|
||||
@@ -370,6 +370,7 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
|
||||
|
||||
|
||||
def exam_take(request, pk: int, sk: int, cid: int = None, passcode: str = None):
|
||||
logger.debug(f"Taking exam pk={pk} sk={sk} cid={cid} passcode={passcode} user={request.user}")
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
if not exam.active:
|
||||
|
||||
+9
-5
@@ -1,10 +1,14 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="">
|
||||
<h2>404 error</h2>
|
||||
{{ reason }}
|
||||
<div class="">
|
||||
<h2>404 error</h2>
|
||||
{% if reason %}
|
||||
{{ reason }}
|
||||
{% endif %}
|
||||
|
||||
<h3>{{resolved}}</h3>
|
||||
</div>
|
||||
{% if resolved %}
|
||||
<h3>{{ resolved }}</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -32,7 +32,7 @@
|
||||
<h2>Exam: {{ exam }}</h2>
|
||||
<h3>Candidate: {{ cid|default_if_none:request.user.username }}</h3>
|
||||
|
||||
{% if cid_user_exam %}
|
||||
{% comment %} {% if cid_user_exam %}
|
||||
{% if exam.results_supervisor_visible %}
|
||||
Exam results are visible to supervisor.<br/>
|
||||
{% else %}
|
||||
@@ -42,5 +42,5 @@
|
||||
>Toggle</button>
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %} {% endcomment %}
|
||||
Answers:
|
||||
Reference in New Issue
Block a user