Added server and admin-side time limit adjustments
This commit is contained in:
parent
4902d40787
commit
6855ddfdcb
@ -41,13 +41,14 @@ class Test:
|
||||
return jsonify({'error': f'Could not create exam. An error occurred.'}), 400
|
||||
|
||||
def add_time_adjustment(self, time_adjustment):
|
||||
code = {
|
||||
adjustment = {
|
||||
'_id': uuid4().hex,
|
||||
'user_code': secrets.token_hex(2).upper(),
|
||||
'user_code': secrets.token_hex(3).upper(),
|
||||
'time_adjustment': time_adjustment
|
||||
}
|
||||
if db.tests.find_one_and_update({'_id': self._id}, {'$push': {'time_adjustments': code}},upsert=False):
|
||||
return jsonify({'success': code})
|
||||
if db.tests.find_one_and_update({'_id': self._id}, {'$push': {'time_adjustments': adjustment}},upsert=False):
|
||||
flash(f'Time adjustment for {adjustment["time_adjustment"]} minutes has been added. This can be enabled using the user code {adjustment["user_code"]}.')
|
||||
return jsonify({'success': adjustment})
|
||||
return jsonify({'error': 'Failed to add the time adjustment. An error occurred.'}), 400
|
||||
|
||||
def remove_time_adjustment(self, _id):
|
||||
|
@ -214,11 +214,15 @@ table.dataTable {
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
.result-action-buttons {
|
||||
.result-action-buttons, .test-action {
|
||||
margin: 5px auto;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
/* Fallback for Edge
|
||||
-------------------------------------------------- */
|
||||
@supports (-ms-ime-align: auto) {
|
||||
|
@ -63,22 +63,27 @@ $('form[name=form-upload-questions]').submit(function(event) {
|
||||
});
|
||||
|
||||
// Edit and Delete Test Button Handlers
|
||||
$('.delete-test').click(function(event) {
|
||||
$('.test-action').click(function(event) {
|
||||
|
||||
let _id = $(this).data('_id')
|
||||
let _id = $(this).data('_id');
|
||||
let action = $(this).data('action');
|
||||
|
||||
$.ajax({
|
||||
url: `/admin/tests/delete/`,
|
||||
type: 'POST',
|
||||
data: JSON.stringify({'_id': _id}),
|
||||
contentType: 'application/json',
|
||||
success: function(response) {
|
||||
window.location.href = '/admin/tests/';
|
||||
},
|
||||
error: function(response){
|
||||
error_response(response);
|
||||
},
|
||||
});
|
||||
if (action == 'delete') {
|
||||
$.ajax({
|
||||
url: `/admin/tests/delete/`,
|
||||
type: 'POST',
|
||||
data: JSON.stringify({'_id': _id}),
|
||||
contentType: 'application/json',
|
||||
success: function(response) {
|
||||
window.location.href = '/admin/tests/';
|
||||
},
|
||||
error: function(response){
|
||||
error_response(response);
|
||||
},
|
||||
});
|
||||
} else if (action == 'edit') {
|
||||
window.location.href = `/admin/test/${_id}/`
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
@ -109,11 +114,11 @@ $('.edit-question-dataset').click(function(event) {
|
||||
|
||||
function error_response(response) {
|
||||
|
||||
var alert = $("#alert-box");
|
||||
alert.html('');
|
||||
const $alert = $("#alert-box");
|
||||
$alert.html('');
|
||||
|
||||
if (typeof response.responseJSON.error === 'string' || response.responseJSON.error instanceof String) {
|
||||
alert.html(`
|
||||
$alert.html(`
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill" title="Danger"></i>
|
||||
${response.responseJSON.error}
|
||||
@ -122,7 +127,7 @@ function error_response(response) {
|
||||
`);
|
||||
} else if (response.responseJSON.error instanceof Array) {
|
||||
for (var i = 0; i < response.responseJSON.error.length; i ++) {
|
||||
alert.html(`
|
||||
$alert.html(`
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill" title="Danger"></i>
|
||||
${response.responseJSON.error[i]}
|
||||
@ -131,6 +136,8 @@ function error_response(response) {
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
$alert.focus()
|
||||
}
|
||||
|
||||
// Dismiss Cookie Alert
|
||||
@ -152,13 +159,12 @@ $('#dismiss-cookie-alert').click(function(event){
|
||||
})
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
})
|
||||
|
||||
// Script for Resutlt Actions
|
||||
// Script for Result Actions
|
||||
$('.result-action-buttons').click(function(event){
|
||||
|
||||
var _id = $(this).data('_id')
|
||||
var _id = $(this).data('_id');
|
||||
|
||||
if ($(this).data('result-action') == 'generate') {
|
||||
$.ajax({
|
||||
@ -192,4 +198,32 @@ $('.result-action-buttons').click(function(event){
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Script for Deleting Time Adjustment
|
||||
$('.adjustment-delete').click(function(event){
|
||||
|
||||
var _id = $(this).data('_id');
|
||||
var location = window.location.href;
|
||||
location.replace('#', '')
|
||||
|
||||
console.log(location)
|
||||
|
||||
console.log(_id)
|
||||
$.ajax({
|
||||
url: location + 'delete-adjustment/',
|
||||
type: 'POST',
|
||||
data: JSON.stringify({'_id': _id}),
|
||||
contentType: 'application/json',
|
||||
success: function(response) {
|
||||
window.location.reload();
|
||||
},
|
||||
error: function(response){
|
||||
error_response(response);
|
||||
},
|
||||
});
|
||||
|
||||
event.preventDefault();
|
||||
});
|
@ -1 +1 @@
|
||||
<div id="alert-box"></div>
|
||||
<div id="alert-box" tabindex="-1"></div>
|
180
ref-test/admin/templates/admin/test.html
Normal file
180
ref-test/admin/templates/admin/test.html
Normal file
@ -0,0 +1,180 @@
|
||||
{% extends "admin/components/base.html" %}
|
||||
{% block title %} SKA Referee Test | Edit Exam {% endblock %}
|
||||
{% block content %}
|
||||
<h1>Edit Exam</h1>
|
||||
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Exam Code</h5>
|
||||
</div>
|
||||
<h2>
|
||||
{{ '—'.join([test.test_code[:4], test.test_code[4:8], test.test_code[8:]]) }}
|
||||
</h2>
|
||||
</li>
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Dataset</h5>
|
||||
</div>
|
||||
{{ test.dataset }}
|
||||
</li>
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Created By</h5>
|
||||
</div>
|
||||
{{ test.creator }}
|
||||
</li>
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Date Created</h5>
|
||||
</div>
|
||||
{{ test.date_created.strftime('%d %b %Y') }}
|
||||
</li>
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Expiry Date</h5>
|
||||
</div>
|
||||
{{ test.start_date.strftime('%d %b %Y') }}
|
||||
</li>
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Expiry Date</h5>
|
||||
</div>
|
||||
{{ test.expiry_date.strftime('%d %b %Y') }}
|
||||
</li>
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Time Limit</h5>
|
||||
</div>
|
||||
{% if test.time_limit == None -%}
|
||||
None
|
||||
{% elif test.time_limit == 60 -%}
|
||||
1 hour
|
||||
{% elif test.time_limit == 90 -%}
|
||||
1 hour 30 min
|
||||
{% elif test.time_limit == 120 -%}
|
||||
2 hours
|
||||
{% else -%}
|
||||
{{ test.time_limit }}
|
||||
{% endif %}
|
||||
</li>
|
||||
<div class="accordion" id="test-info-detail">
|
||||
{% if 'entries' in test and test.entries|length > 0 %}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="test-entries">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#test-entries-list" aria-expanded="false" aria-controls="test-entries-list">
|
||||
List Test Entries
|
||||
</button>
|
||||
</h2>
|
||||
<div id="test-entries-list" class="accordion-collapse collapse" aria-labelledby="test-entries" data-bs-parent="#test-info-detail">
|
||||
<div class="accordion-body">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
{% for entry in test.entries %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('admin_views.view_entry', _id=entry) }}" >Entry {{ loop.index }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'time_adjustments' in test and test.time_adjustments|length > 0 %}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="test-adjustments">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#test-adjustments-list" aria-expanded="false" aria-controls="test-adjustments-list">
|
||||
List Time Adjustments
|
||||
</button>
|
||||
</h2>
|
||||
<div id="test-adjustments-list" class="accordion-collapse collapse" aria-labelledby="test-adjustments" data-bs-parent="#test-info-detail">
|
||||
<div class="accordion-body">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
User Code
|
||||
</th>
|
||||
<th>
|
||||
Adjustment (Minutes)
|
||||
</th>
|
||||
<th>
|
||||
Delete
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in test.time_adjustments %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ entry.user_code }}
|
||||
</td>
|
||||
<td>
|
||||
{{ entry.time_adjustment }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="javascript::void(0);" class="btn btn-danger adjustment-delete" title="Delete Adjustment" data-_id="{{ entry._id }}" data-action="delete">
|
||||
<i class="bi bi-slash-circle-fill button-icon"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not test.time_limit == None %}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="test-add-adjustments">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#test-adjustments-add" aria-expanded="false" aria-controls="test-adjustments-add">
|
||||
Add Time Adjustments
|
||||
</button>
|
||||
</h2>
|
||||
<div id="test-adjustments-add" class="accordion-collapse collapse" aria-labelledby="test-add-adjustments" data-bs-parent="#test-info-detail">
|
||||
<div class="accordion-body">
|
||||
<form name="form-add-adjustment" class="form-display form-post" action="{{ url_for(request.endpoint, **request.view_args) }}" data-rel-success="">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-label-group">
|
||||
{{ form.time(class_="form-control", placeholder="Enter Username") }}
|
||||
{{ form.time.label }}
|
||||
</div>
|
||||
<div class="container form-submission-button">
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<button title="Add Time Adjustment" class="btn btn-md btn-success btn-block" type="submit">
|
||||
<i class="bi bi-clock-history button-icon"></i>
|
||||
Add Time Adjustment
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</ul>
|
||||
<div class="row">
|
||||
{% include "admin/components/client-alerts.html" %}
|
||||
</div>
|
||||
<div class="container justify-content-center">
|
||||
<div class="row">
|
||||
<a href="#" class="btn btn-danger test-action" data-action="delete" data-_id="{{ test._id }}">
|
||||
<i class="bi bi-file-earmark-excel-fill button-icon"></i>
|
||||
Delete Exam
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -60,17 +60,19 @@
|
||||
<td class="row-actions">
|
||||
<a
|
||||
href="#"
|
||||
class="btn btn-primary edit-test"
|
||||
class="btn btn-primary test-action"
|
||||
data-_id="{{test._id}}"
|
||||
title="Edit Exam"
|
||||
data-action="edit"
|
||||
>
|
||||
<i class="bi bi-file-earmark-text-fill button-icon"></i>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="btn btn-danger delete-test"
|
||||
class="btn btn-danger test-action"
|
||||
data-_id="{{test._id}}"
|
||||
title="Delete Exam"
|
||||
data-action="delete"
|
||||
>
|
||||
<i class="bi bi-file-earmark-excel-fill button-icon"></i>
|
||||
</button>
|
||||
|
@ -407,10 +407,26 @@ def delete_test():
|
||||
@views.route('/test/<_id>/', methods=['GET','POST'])
|
||||
@admin_account_required
|
||||
@login_required
|
||||
def view_test(_id, filter=''):
|
||||
test = db.tests.find_one({'_id':_id})
|
||||
if not test:
|
||||
return abort(404)
|
||||
def view_test(_id):
|
||||
from .models.forms import AddTimeAdjustment
|
||||
form = AddTimeAdjustment()
|
||||
test = decrypt_find_one(db.tests, {'_id': _id})
|
||||
if request.method == 'GET':
|
||||
if not test:
|
||||
return abort(404)
|
||||
return render_template('/admin/test.html', test = test, form = form)
|
||||
if request.method == 'POST':
|
||||
if form.validate_on_submit():
|
||||
time = request.form.get('time')
|
||||
return Test(_id=_id).add_time_adjustment(time)
|
||||
return jsonify({'error': form.time.errors }), 400
|
||||
|
||||
@views.route('/test/<_id>/delete-adjustment/', methods = ['POST'])
|
||||
@admin_account_required
|
||||
@login_required
|
||||
def delete_adjustment(_id):
|
||||
adjustment_id = request.get_json()['_id']
|
||||
return Test(_id=_id).remove_time_adjustment(adjustment_id)
|
||||
|
||||
@views.route('/results/')
|
||||
@admin_account_required
|
||||
|
Loading…
Reference in New Issue
Block a user