Quiz registration form

This commit is contained in:
Vivek Santayana 2021-11-25 23:12:20 +00:00
parent 2d0bb883bd
commit c745e3c27c
6 changed files with 125 additions and 24 deletions

View File

@ -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)])

View File

@ -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();
});

View File

@ -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 %}

View File

@ -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") }}

View File

@ -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>
"""

View File

@ -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():