Quiz registration form
This commit is contained in:
parent
6cecb49d50
commit
857fa72feb
@ -7,5 +7,5 @@ class StartQuiz(FlaskForm):
|
|||||||
surname = StringField('Surname', validators=[InputRequired(), Length(max=30)])
|
surname = StringField('Surname', validators=[InputRequired(), Length(max=30)])
|
||||||
email = StringField('Email Address', validators=[InputRequired(), Email(message='You must enter a valid email address.'), Length(max=50)])
|
email = StringField('Email Address', validators=[InputRequired(), Email(message='You must enter a valid email address.'), Length(max=50)])
|
||||||
club = StringField('Affiliated Club (Optional)', validators=[Optional(), Length(max=50)])
|
club = StringField('Affiliated Club (Optional)', validators=[Optional(), Length(max=50)])
|
||||||
auth_code = StringField('Exam Code', validators=[InputRequired(), Length(min=14, max=14)])
|
test_code = StringField('Exam Code', validators=[InputRequired(), Length(min=14, max=14)])
|
||||||
user_code = StringField('User Code (Optional)', validators=[Optional(), Length(min=6, max=6)])
|
user_code = StringField('User Code (Optional)', validators=[Optional(), Length(min=6, max=6)])
|
@ -3,7 +3,7 @@ $(document).ready(function() {
|
|||||||
$("body").css("font-family", "opendyslexic3regular")
|
$("body").css("font-family", "opendyslexic3regular")
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.auth-code-input').keyup(function() {
|
$('.test-code-input').keyup(function() {
|
||||||
var input = $(this).val().split("-").join("").split("—").join(""); // remove hyphens and mdashes
|
var input = $(this).val().split("-").join("").split("—").join(""); // remove hyphens and mdashes
|
||||||
if (input.length > 0) {
|
if (input.length > 0) {
|
||||||
input = input.match(new RegExp('.{1,4}', 'g')).join("—");
|
input = input.match(new RegExp('.{1,4}', 'g')).join("—");
|
||||||
@ -11,3 +11,45 @@ $(document).ready(function() {
|
|||||||
$(this).val(input);
|
$(this).val(input);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('form[name=form-quiz-start]').submit(function(event) {
|
||||||
|
|
||||||
|
var $form = $(this);
|
||||||
|
var alert = document.getElementById('alert-box');
|
||||||
|
var data = $form.serialize();
|
||||||
|
|
||||||
|
alert.innerHTML = ''
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: window.location.pathname,
|
||||||
|
type: 'POST',
|
||||||
|
data: data,
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
window.location.href = "/admin/login/";
|
||||||
|
},
|
||||||
|
error: function(response) {
|
||||||
|
if (typeof response.responseJSON.error === 'string' || response.responseJSON.error instanceof String) {
|
||||||
|
alert.innerHTML = alert.innerHTML + `
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill" title="Danger"></i>
|
||||||
|
${response.responseJSON.error}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else if (response.responseJSON.error instanceof Array) {
|
||||||
|
for (var i = 0; i < response.responseJSON.error.length; i ++) {
|
||||||
|
alert.innerHTML = alert.innerHTML + `
|
||||||
|
<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]}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
@ -0,0 +1,25 @@
|
|||||||
|
{% extends "quiz/components/base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Privacy Policy</h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>This web app stores data using cookies. The web site only stores the minimum information it needs to function.</li>
|
||||||
|
<li>Site Administrators</li>
|
||||||
|
<ul>
|
||||||
|
<li>For site administrators, this web site uses encrypted cookies to store data from your log-in session,</li>
|
||||||
|
<li>User information for administrators is encrypted and stored in a secure database, and are expunged when an account is deleted.</li>
|
||||||
|
</ul>
|
||||||
|
<li>Test Candidates</li>
|
||||||
|
<ul>
|
||||||
|
<li>The web site will not be trackin your log in, and all information about your test attempt will be stored on your device until you submit it to the server.</li>
|
||||||
|
<li>Data from your test, including identifying information such as your name and email address, will be recorded by the Scottish Korfball Association in order to oversee the training and qualification of referees.</li>
|
||||||
|
<li>These records will be kept for HOW MANY?? years and will be expunged securely thereafter.</li>
|
||||||
|
<li>All identifying information about candidates will be encrypted and stored in a secure database.</li>
|
||||||
|
</ul>
|
||||||
|
<li>Requests to Delete Data</li>
|
||||||
|
<ul>
|
||||||
|
<li>You can request to have any of your data that is held here deleted by emailing WHOM?</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@ -23,8 +23,8 @@
|
|||||||
{{ form.club.label }}
|
{{ form.club.label }}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-label-group">
|
<div class="form-label-group">
|
||||||
{{ form.auth_code(class_="form-control auth-code-input", placeholder="Enter Exam Code") }}
|
{{ form.test_code(class_="form-control test-code-input", placeholder="Enter Exam Code") }}
|
||||||
{{ form.auth_code.label }}
|
{{ form.test_code.label }}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-label-group">
|
<div class="form-label-group">
|
||||||
{{ form.user_code(class_="form-control", placeholder="Enter User Code") }}
|
{{ form.user_code(class_="form-control", placeholder="Enter User Code") }}
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
from flask import Blueprint, render_template
|
from flask import Blueprint, render_template, request, redirect, jsonify
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from main import db
|
||||||
|
from security import encrypt
|
||||||
|
|
||||||
views = Blueprint(
|
views = Blueprint(
|
||||||
'quiz_views',
|
'quiz_views',
|
||||||
@ -17,20 +22,38 @@ def home():
|
|||||||
def start():
|
def start():
|
||||||
from .forms import StartQuiz
|
from .forms import StartQuiz
|
||||||
form = StartQuiz()
|
form = StartQuiz()
|
||||||
return render_template('/quiz/start-quiz.html', form=form)
|
if request.method == 'GET':
|
||||||
|
return render_template('/quiz/start-quiz.html', form=form)
|
||||||
|
if request.method == 'POST':
|
||||||
|
if form.validate_on_submit():
|
||||||
|
name = {
|
||||||
|
'first_name': request.form.get('first_name'),
|
||||||
|
'surname': request.form.get('surname')
|
||||||
|
}
|
||||||
|
email = request.form.get('email')
|
||||||
|
club = request.form.get('club')
|
||||||
|
test_code = request.form.get('test_code').replace('—', '')
|
||||||
|
user_code = request.form.get('user_code')
|
||||||
|
user_code = None if user_code == '' else user_code
|
||||||
|
if not db.tests.find_one({'test_code': test_code}):
|
||||||
|
return jsonify({'error': 'The exam code you entered is invalid.'}), 400
|
||||||
|
attempt = {
|
||||||
|
'_id': uuid4().hex,
|
||||||
|
'name': encrypt(name),
|
||||||
|
'email': encrypt(email),
|
||||||
|
'club': encrypt(club),
|
||||||
|
'test-code': test_code,
|
||||||
|
'user_code': user_code,
|
||||||
|
'start_time': datetime.utcnow(),
|
||||||
|
'status': 'started'
|
||||||
|
}
|
||||||
|
if db.results.insert(attempt):
|
||||||
|
return jsonify({ 'success': f'Exam started at started {attempt["start_time"].strftime("%H:%M:%S")}.' })
|
||||||
|
else:
|
||||||
|
errors = [*form.errors]
|
||||||
|
return jsonify({ 'error': errors}), 400
|
||||||
|
|
||||||
|
|
||||||
@views.route('/privacy/')
|
@views.route('/privacy/')
|
||||||
def privacy():
|
def privacy():
|
||||||
return f"""<h1>Privacy Policy</h1>
|
return render_template('/quiz/privacy.html')
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Website stores data using cookies.</li>
|
|
||||||
<li>Site Administrators</li>
|
|
||||||
<li>This web site only uses functional cookies to store information on log-in.</li>
|
|
||||||
<li>User information for administrators will be encrypted and stored in a secure database for the purposes of administering this web site, and will be expunged when the user account is deleted.</li>
|
|
||||||
<li>Test Candidate</li>
|
|
||||||
<li>The web site will not be tracking your log in, and all information about your test attempt will be stored on your device until it is submitted to the server.</li>
|
|
||||||
<li>Data from your test as well as identifying information about the candidate will be encrypted and stored in a secure database on the server, and will be retained for a period of HOW MANY? years for the SKA's records.</li>
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
"""
|
|
@ -1,4 +1,4 @@
|
|||||||
from os import path
|
from os import environ, path
|
||||||
from cryptography.fernet import Fernet
|
from cryptography.fernet import Fernet
|
||||||
|
|
||||||
def generate_keyfile():
|
def generate_keyfile():
|
||||||
@ -14,14 +14,25 @@ def load_key():
|
|||||||
def check_keyfile_exists():
|
def check_keyfile_exists():
|
||||||
return path.isfile('./security/.encryption.key')
|
return path.isfile('./security/.encryption.key')
|
||||||
|
|
||||||
def encrypt(input:str):
|
def encrypt(input):
|
||||||
input = input.encode()
|
|
||||||
if not check_keyfile_exists():
|
if not check_keyfile_exists():
|
||||||
generate_keyfile()
|
generate_keyfile()
|
||||||
_encryption_key = load_key()
|
_encryption_key = load_key()
|
||||||
fernet = Fernet(_encryption_key)
|
fernet = Fernet(_encryption_key)
|
||||||
output = fernet.encrypt(input)
|
if type(input) == str:
|
||||||
return output.decode()
|
input = input.encode()
|
||||||
|
output = fernet.encrypt(input)
|
||||||
|
return output.decode()
|
||||||
|
if type(input) == dict:
|
||||||
|
output = {}
|
||||||
|
for key,value in input.items():
|
||||||
|
if type(value) == dict:
|
||||||
|
output[key] = encrypt(value)
|
||||||
|
else:
|
||||||
|
value = value.encode()
|
||||||
|
output[key] = fernet.encrypt(value)
|
||||||
|
output[key] = output[key].decode()
|
||||||
|
return output
|
||||||
|
|
||||||
def decrypt(input):
|
def decrypt(input):
|
||||||
if not check_keyfile_exists():
|
if not check_keyfile_exists():
|
||||||
|
Loading…
Reference in New Issue
Block a user