Add CID user support in collection history and reset answers functionality

This commit is contained in:
Ross
2025-10-13 11:28:07 +01:00
parent fa08f9cf76
commit 32d8430f94
8 changed files with 222 additions and 58 deletions
@@ -26,6 +26,7 @@
</div>
</div>
<div id="timer-htmx-target" style="display:none;"></div>
<div id="autosubmit-toast-container" style="position:fixed; top:16px; right:16px; z-index:10500;"></div>
</div>
{% endif %}
@@ -412,24 +413,45 @@
$timer.text('0:00');
$progressInner.css('width', '0%');
$progressInner.css('background', '#dc3545');
var $next = $form.find('button[name="next"]');
var $finish = $form.find('button[name="finish"]');
//var $next = $form.find('button[name="next"]');
//var $finish = $form.find('button[name="finish"]');
// Instead of navigating away, submit via fetch with timed_out flag
// Use HTMX to POST the timed_out flag and then lock the UI
var onAfter = function (evt) {
try {
// lock the form UI in-place
$form.find('input, textarea, select, button').prop('disabled', true);
$form.addClass('timed-out-locked');
$('#question-timer').text('Locked');
var resp = null;
try {
var xhr = evt && evt.detail && evt.detail.xhr;
if (xhr && xhr.responseText) {
resp = JSON.parse(xhr.responseText);
}
} catch (e) {
console.debug('No JSON response from timed_out request', e);
}
// hide the progress bar
$('#question-timer-progress, #question-timer-progress-outer, #question-timer-progress-inner').hide();
// ensure inner shows empty state if something relies on it
$('#question-timer-progress-inner').css({ width: '0%', background: '#dc3545' });
// Only disable save buttons to prevent further saves
var $saveBtns = $form.find('button[name="save"], #id_answer');
if ($saveBtns.length) {
$saveBtns.prop('disabled', true);
}
// Visual feedback: set timer to Locked and progress to red
$('#question-timer').text('Locked');
$progressInner.css('background', '#dc3545');
$progressInner.css('width', '0%');
var msg = 'Answer auto-submitted';
if (resp && resp.submitted_at) {
try {
var dt = new Date(resp.submitted_at);
msg += ' at ' + dt.toLocaleTimeString();
} catch (e) {}
}
toastr.info(msg);
} catch (e) {
console.error('Error locking UI after htmx request', e);
console.error('Error handling timed_out htmx response', e);
} finally {
htmx.off('htmx:afterRequest', onAfter);
}
+44 -18
View File
@@ -3,26 +3,52 @@
{% block content %}
<h2>{{collection.name}}</h2>
<h3>Users</h3>
<ul>
{% for userexam in userexams %}
<li id="user-history-{{ userexam.user_user.pk }}">
<b><a href="{% url 'atlas:collection_history_user' collection.pk userexam.user_user.pk %}">{{userexam.get_user_name}}</a><b><br/>
Completed: {{userexam.completed}}<br/>
Started: {{userexam.start_time}}, Ended: {{userexam.end_time}}<br/>
{% if userexams %}
<h3>Users</h3>
<button
hx-post="{% url 'atlas:collection_reset_answers_user' collection.pk userexam.user_user.pk %}"
hx-target="#user-history-{{ userexam.user_user.pk }}"
hx-swap="outerHTML"
hx-confirm="Are you sure you want to delete this user's collection history?"
class="btn btn-danger btn-sm remove-button">
Delete
</button>
</li>
{% endfor %}
</ul>
<ul>
{% for userexam in userexams %}
<li id="user-history-{{ userexam.user_user.pk }}">
<b><a href="{% url 'atlas:collection_history_user' collection.pk userexam.user_user.pk %}">{{userexam.get_user_name}}</a><b><br/>
Completed: {{userexam.completed}}<br/>
Started: {{userexam.start_time}}, Ended: {{userexam.end_time}}<br/>
<button
hx-post="{% url 'atlas:collection_reset_answers_user' collection.pk userexam.user_user.pk %}"
hx-target="#user-history-{{ userexam.user_user.pk }}"
hx-swap="outerHTML"
hx-confirm="Are you sure you want to delete this user's collection history?"
class="btn btn-danger btn-sm remove-button">
Delete
</button>
</li>
{% endfor %}
</ul>
{% endif %}
{% if cidexams %}
<h3>CID Users</h3>
<ul>
{% for cidexam in cidexams %}
<li id="cid-history-{{ cidexam.cid_user.pk }}">
<b><a href="{% url 'atlas:collection_history_ciduser' collection.pk cidexam.cid_user.pk %}">{{cidexam.cid_user}}</a><b><br/>
Completed: {{cidexam.completed}}<br/>
Started: {{cidexam.start_time}}, Ended: {{cidexam.end_time}}<br/>
<button
hx-post="{% url 'atlas:collection_reset_answers_ciduser' collection.pk cidexam.cid_user.pk %}"
hx-target="#cid-history-{{ cidexam.cid_user.pk }}"
hx-swap="outerHTML"
hx-confirm="Are you sure you want to delete this CID user's collection history?"
class="btn btn-danger btn-sm remove-button">
Delete
</button>
</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}
@@ -10,39 +10,53 @@
<li class="case">
<h4>{{forloop.counter}} / Case: {{casedetail.case.title}}</h4>
{{user_answer.started_at}} - {{user_answer.submitted_at}}
{% if request.user.is_superuser and user_answer %}
&nbsp;(<a href="{% url 'admin:atlas_userreportanswer_change' user_answer.pk %}" target="_blank">Edit in admin</a>)
{% endif %}
<br/>
{% if not user_answer %}
<span class="case-not-answered">Case not answered.</span>
{% else %}
<div class="answer-block">
{% for value, user_answer, correct_answer, answer_is_correct, automark in user_answer.get_correct_json_answers %}
{% if not user_answer %}
Not answered
{% else %}
<div class="{% if answer_is_correct %}
correct
{% else %}
incorrect
{% endif %}
{% if automark %}
automark
{% if user_answer.answer %}
{{user_answer.answer}}
{% else %}
{{user_answer.json_answer}}
{% for value, user_answer, correct_answer, answer_is_correct, automark in user_answer.get_correct_json_answers %}
{% if not user_answer %}
Not answered
{% else %}
<div class="{% if answer_is_correct %}
correct
{% else %}
incorrect
{% endif %}
{% if automark %}
automark
{% endif %}
">
<h5>{{value.title}}</h5>
{{value.description}}
<div
>
Answer : {{user_answer}}
{% if not answer_is_correct %}
<br/>Correct answer: {{correct_answer}}
{% endif %}
">
<h5>{{value.title}}</h5>
{{value.description}}
<div
>
Answer : {{user_answer}}
{% if not answer_is_correct %}
<br/>Correct answer: {{correct_answer}}
{% endif %}
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
</div>
{% endif %}