improve case user answer management (and fix small bug)

This commit is contained in:
Ross
2024-11-18 10:44:27 +00:00
parent 9c69792e87
commit 00323cc6bd
7 changed files with 125 additions and 30 deletions
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-11-18 09:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('atlas', '0063_casecollection_results_supervisor_visible'),
]
operations = [
migrations.AddField(
model_name='casecollection',
name='exam_open_access',
field=models.BooleanField(default=False, help_text='Set to true if you want any registered user to be able to take the exam.'),
),
]
@@ -33,6 +33,7 @@
<p>View as a viva collection <a href='{% url "atlas:collection_viva" collection.pk %}'>here</a> <p>View as a viva collection <a href='{% url "atlas:collection_viva" collection.pk %}'>here</a>
{% else %} {% else %}
<p>This collection will be available to view/take <a href='{{collection.get_take_url}}'>here</a> (when active) <p>This collection will be available to view/take <a href='{{collection.get_take_url}}'>here</a> (when active)
<p>Review collection <a href='{% url "atlas:collection_viva" collection.pk %}'>here</a>
{% endif %} {% endif %}
{% if can_edit %} {% if can_edit %}
@@ -60,6 +61,13 @@
hx-confirm="Are you sure you want to reset all answers? This action cannot be undone." hx-confirm="Are you sure you want to reset all answers? This action cannot be undone."
>Reset all answers</button> >Reset all answers</button>
<button title="This will specific user answers and attempts"
hx-post="{% url 'atlas:collection_reset_answers_user_list' collection.pk %}"
hx-swap="innerHTML"
hx-target="#user-list"
>Reset user answers</button>
<div id="user-list"></div>
</details> </details>
{% endif %} {% endif %}
{% include 'exam_overview_js.html' %} {% include 'exam_overview_js.html' %}
@@ -0,0 +1,10 @@
{% for cid_user_exam in cid_users %}
<button title="This will clear the user answers and attempts"
hx-post="{% url 'atlas:collection_reset_answers_user' collection.pk cid_user_exam.user_user.id %}"
hx-swap="outerHTML"
hx-confirm="Are you sure you want to reset answers for the user? This action cannot be undone."
>{{cid_user_exam.user_user}}</button>
{% endfor %}
+36 -26
View File
@@ -58,12 +58,14 @@
<div class="sticky-top"> <div class="sticky-top">
<h3>Current Case</h3> <h3>Current Case</h3>
<div id="loading-case">Waiting for case to load in linked window.<br/> If you are seeing this message you probably need to open the viewer window and reload the case.</div> <div id="case-details">
<div id="current-case-title">None</div> <div id="loading-case">Waiting for case to load in linked window.<br/> If you are seeing this message you probably need to open the viewer window and reload the case.</div>
<div id="current-case-series"></div> <div id="current-case-title">None</div>
<div id="current-case-history"></div> <div id="current-case-series"></div>
<div id="current-case-discussion"></div> <div id="current-case-history"></div>
<div id="current-case-report"></div> <div id="current-case-discussion"></div>
<div id="current-case-report"></div>
</div>
</div> </div>
<iframe id="viewer" style="width: 100%; height: 500px; border: none"></iframe> <iframe id="viewer" style="width: 100%; height: 500px; border: none"></iframe>
@@ -106,16 +108,16 @@
$('#loading-case').show() $('#loading-case').show()
$("#open-viewer").addClass("flash-button"); $("#open-viewer").addClass("flash-button");
$('#current-case-title').text("Case: "+c.data('title')); $('#current-case-title').html("<span class='title'>Case:</span> "+c.data('title'));
$("#current-case-history").text("History: "+case_details['history']); $("#current-case-history").html("<span class='title'>History:</span> "+case_details['history']);
$("#current-case-discussion").text("Discussion: "+case_details['discussion']); $("#current-case-discussion").html("<span class='title'>Discussion:</span> "+case_details['discussion']);
$("#current-case-report").text("Report: "+case_details['report']); $("#current-case-report").html("<span class='title'>Report:</span> "+case_details['report']);
console.log($(this).data('type')) console.log($(this).data('type'))
if ($(this).data('type') == 'case') { if ($(this).data('type') == 'case') {
$('#current-case-series').text("Series: All"); $('#current-case-series').html("<span class='title'>Series:</span> All");
} else { } else {
$('#current-case-series').text("Series: " + $(this).data('series')); $('#current-case-series').html("<span class='title'>Series:</span> " + $(this).data('series'));
} }
bc.postMessage({"type": "open", "url" : url}); bc.postMessage({"type": "open", "url" : url});
//if (win2 == false || win2.closed) { //if (win2 == false || win2.closed) {
@@ -159,19 +161,27 @@
display: none; display: none;
color: red; color: red;
} }
@keyframes glowing { @keyframes glowing {
0% { 0% {
box-shadow: 0 0 20px #a600ff; box-shadow: 0 0 20px #a600ff;
} }
50% { 50% {
box-shadow: 0 0 40px #52057b; box-shadow: 0 0 40px #52057b;
} }
100% { 100% {
box-shadow: 0 0 20px #a600ff; box-shadow: 0 0 20px #a600ff;
} }
} }
.flash-button { .flash-button {
animation: glowing 1300ms infinite; animation: glowing 1300ms infinite;
} }
#case-details {
padding-bottom: 20px;
}
.title {
font-weight: bold;
}
</style> </style>
{% endblock css %} {% endblock css %}
+10
View File
@@ -148,6 +148,16 @@ urlpatterns = [
views.collection_reset_answers, views.collection_reset_answers,
name="collection_reset_answers", name="collection_reset_answers",
), ),
path(
"collection/<int:exam_id>/reset_answers_user_list",
views.collection_reset_answers_user_list,
name="collection_reset_answers_user_list",
),
path(
"collection/<int:exam_id>/<int:user_id>/reset_answers",
views.collection_reset_answers_user,
name="collection_reset_answers_user",
),
#path( #path(
# "question_schemas_preset", # "question_schemas_preset",
# views.question_schemas_preset, # views.question_schemas_preset,
+38 -1
View File
@@ -1682,7 +1682,12 @@ def collection_take_start(request, pk):
""" """
collection = get_object_or_404(CaseCollection, pk=pk) collection = get_object_or_404(CaseCollection, pk=pk)
valid_user = (collection.check_logged_in_user(request),) valid_user = collection.check_logged_in_user(request)
# for now we only allow registered users....
if not valid_user:
raise PermissionDenied
cid_exam = None cid_exam = None
if collection.collection_type == "REV" or valid_user: if collection.collection_type == "REV" or valid_user:
@@ -2901,6 +2906,38 @@ def collection_question_schemas(request, exam_id: int):
}, },
) )
def collection_reset_answers_user_list(request, exam_id: int):
if request.htmx:
collection = get_object_or_404(CaseCollection, pk=exam_id)
cid_users = collection.cid_users.all()
if cid_users:
return render(request, "atlas/collection_reset_answers_user_list.html", {"collection": collection, "cid_users": cid_users})
else:
return HttpResponse("No user answers.")
else:
raise Http404("Invalid request")
def collection_reset_answers_user(request, exam_id: int, user_id: int):
if request.htmx:
collection = get_object_or_404(CaseCollection, pk=exam_id)
# Select all case details (answers are linked to these)
case_details = collection.casedetail_set.all().prefetch_related()
# Delete all answers
for case in case_details:
user_answers = case.userreportanswer_set.filter(user_id=user_id)
user_answers.delete()
collection.cid_users.filter(user_user_id=user_id).delete()
collection.exam_user_status.filter(cid_user_exam__user_user_id=user_id).delete()
return HttpResponse("Success")
else:
raise Http404("Invalid request")
def collection_reset_answers(request, exam_id: int): def collection_reset_answers(request, exam_id: int):
if request.htmx: if request.htmx:
+4 -2
View File
@@ -613,6 +613,8 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin):
default=False, default=False,
) )
exam_open_access = models.BooleanField(default=False, help_text="Set to true if you want any registered user to be able to take the exam.")
class Meta: class Meta:
abstract = True abstract = True
@@ -718,6 +720,8 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin):
return True return True
if cid is None and user_id is None: if cid is None and user_id is None:
if user.is_anonymous:
return False
if user is not None: if user is not None:
user_id = user.id user_id = user.id
else: else:
@@ -869,8 +873,6 @@ class ExamBase(ExamOrCollectionGenericBase):
default=False, default=False,
) )
exam_open_access = models.BooleanField(default=False, help_text="Set to true if you want any registered user to be able to take the exam.")
# randomise_question_order = models.BooleanField( # randomise_question_order = models.BooleanField(
# help_text="If an exam should randomise the order of questions in RTS.", # help_text="If an exam should randomise the order of questions in RTS.",
# ) # )