improve surverys

This commit is contained in:
Ross
2026-06-29 09:35:12 +01:00
parent 79ba4db4bf
commit c34dcdfd5e
26 changed files with 911 additions and 39 deletions
@@ -0,0 +1,23 @@
# Generated by Django 6.0.1 on 2026-06-29 08:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('physics', '0019_exam_post_survey_exam_pre_survey'),
]
operations = [
migrations.AddField(
model_name='exam',
name='post_survey_mandatory',
field=models.BooleanField(default=False, help_text='If checked, candidates must complete the post-take survey to view results.'),
),
migrations.AddField(
model_name='exam',
name='pre_survey_mandatory',
field=models.BooleanField(default=False, help_text='If checked, candidates must complete the pre-take survey to start.'),
),
]
@@ -10,6 +10,15 @@
</span>
{% include "exam_clock.html" %}
{% if post_survey_url %}
<div class="alert alert-info d-flex align-items-center justify-content-between my-3" role="alert">
<div>
<strong>Feedback Survey:</strong> We value your feedback! Please take a quick survey about this exam.
</div>
<a href="{{ post_survey_url }}" class="btn btn-sm btn-info text-white">Take Survey</a>
</div>
{% endif %}
<h2>Exam: {{exam}}</h2>
{% if exam.publish_results %}
+64
View File
@@ -138,6 +138,12 @@ def exam_start(request, pk):
if not exam.active:
return exam_inactive(request, context={"exam": exam})
# Check if pre-survey is required and not yet taken
from survey.views import check_survey_interception
response = check_survey_interception(request, exam)
if response:
return response
return render(
request,
"physics/exam_start.html",
@@ -179,6 +185,12 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
exam.check_user_can_take(cid, passcode, request.user)
# Check if pre-survey is required and not yet taken
from survey.views import check_survey_interception
response = check_survey_interception(request, exam, cid, passcode)
if response:
return response
questions = exam.get_questions()
if cid is not None:
@@ -212,6 +224,51 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
# Check if post-survey is mandatory and not yet taken
if exam.post_survey and getattr(exam, "post_survey_mandatory", False) and cid_user_exam.completed:
from survey.models import SurveyResponse
user_param = request.user if request.user.is_authenticated else None
cid_param = int(cid) if cid and str(cid).isdigit() else None
ct = ContentType.objects.get_for_model(exam)
has_responded = SurveyResponse.objects.filter(
survey=exam.post_survey,
user=user_param,
cid=cid_param,
content_type=ct,
object_id=exam.pk,
pre_or_post=SurveyResponse.SurveyContext.POST
).exists()
if not has_responded:
from django.urls import reverse
survey_url = reverse("survey:survey_take", kwargs={"pk": exam.post_survey.pk})
params = f"?pre_or_post=POST&content_type_id={ct.id}&object_id={exam.pk}&next={request.get_full_path()}&mandatory=true"
if cid and passcode:
params += f"&cid={cid}&passcode={passcode}"
return redirect(f"{survey_url}{params}")
post_survey_url = None
if exam.post_survey and not getattr(exam, "post_survey_mandatory", False):
from survey.models import SurveyResponse
user_param = request.user if request.user.is_authenticated else None
cid_param = int(cid) if cid and str(cid).isdigit() else None
ct = ContentType.objects.get_for_model(exam)
has_responded = SurveyResponse.objects.filter(
survey=exam.post_survey,
user=user_param,
cid=cid_param,
content_type=ct,
object_id=exam.pk,
pre_or_post=SurveyResponse.SurveyContext.POST
).exists()
if not has_responded:
session_key = f"skipped_post_survey_{exam.pk}"
if not request.session.get(session_key):
from django.urls import reverse
survey_url = reverse("survey:survey_take", kwargs={"pk": exam.post_survey.pk})
params = f"?pre_or_post=POST&content_type_id={ct.id}&object_id={exam.pk}&next={request.get_full_path()}&mandatory=false&skip_key={session_key}"
if cid and passcode:
params += f"&cid={cid}&passcode={passcode}"
post_survey_url = f"{survey_url}{params}"
return render(
request,
@@ -224,6 +281,7 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
"exam_length": len(questions),
"passcode": passcode,
"cid_user_exam": cid_user_exam,
"post_survey_url": post_survey_url,
},
)
@@ -245,6 +303,12 @@ def exam_take(request, pk: int, sk: int, cid: str | None = None, passcode: str |
exam.check_user_can_take(cid, passcode, request.user)
# Check if pre-survey is required and not yet taken
from survey.views import check_survey_interception
response = check_survey_interception(request, exam, cid, passcode)
if response:
return response
cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
# Canonical questions list for consistent indexing/navigation