92 lines
4.2 KiB
Python
92 lines
4.2 KiB
Python
from ..forms.quiz import StartQuiz
|
|
from ..models import Entry, Test
|
|
from ..tools.forms import send_errors_to_client
|
|
from ..tools.logs import write
|
|
from ..tools.test import redirect_if_started
|
|
|
|
from flask import Blueprint, jsonify, render_template, request, session
|
|
from flask.helpers import abort, flash, redirect, url_for
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
from datetime import datetime
|
|
|
|
quiz = Blueprint(
|
|
name='quiz',
|
|
import_name=__name__,
|
|
template_folder='templates',
|
|
static_folder='static',
|
|
static_url_path='/quiz/static'
|
|
)
|
|
|
|
@quiz.route('/')
|
|
@quiz.route('/home/')
|
|
@redirect_if_started
|
|
def _home():
|
|
return render_template('/quiz/index.html')
|
|
|
|
@quiz.route('/instructions/')
|
|
def _instructions():
|
|
return render_template('/quiz/instructions.html')
|
|
|
|
@quiz.route('/start/', methods=['GET', 'POST'])
|
|
def _start():
|
|
form = StartQuiz()
|
|
if request.method == 'POST':
|
|
if form.validate_on_submit():
|
|
entry = Entry()
|
|
entry.set_first_name(request.form.get('first_name'))
|
|
entry.set_surname(request.form.get('surname'))
|
|
entry.set_club(request.form.get('club'))
|
|
entry.set_email(request.form.get('email'))
|
|
code = request.form.get('test_code').replace('—', '').lower()
|
|
try: test = Test.query.filter_by(code=code).first()
|
|
except (SQLAlchemyError, ConnectionError) as exception:
|
|
write('system.log', f'Database error when processing request \'{request.url}\': {exception}')
|
|
return abort(500)
|
|
entry.test = test
|
|
entry.user_code = request.form.get('user_code')
|
|
entry.user_code = None if entry.user_code == '' else entry.user_code.lower()
|
|
if not test: return jsonify({'error': 'The exam code you entered is invalid.'}), 400
|
|
if entry.user_code and entry.user_code not in test.adjustments: return jsonify({'error': f'The user code you entered is not valid.'}), 400
|
|
if test.end_date < datetime.now(): return jsonify({'error': f'The exam code you entered expired on {test["expiry_date"].strftime("%d %b %Y %H:%M")}.'}), 400
|
|
if test.start_date > datetime.now(): return jsonify({'error': f'The exam has not yet opened. Your exam code will be valid from {test["start_date"].strftime("%d %b %Y %H:%M")}.'}), 400
|
|
success, message = entry.ready()
|
|
if success:
|
|
session['id'] = entry.id
|
|
return jsonify({
|
|
'success': 'Received and validated test and/or user code. Redirecting to test client.',
|
|
'id': entry.id
|
|
}), 200
|
|
return jsonify({'error': 'There was an error processing the user test and/or user codes.'}), 400
|
|
return send_errors_to_client(form=form)
|
|
return render_template('/quiz/start_quiz.html', form = form)
|
|
|
|
@quiz.route('/quiz/')
|
|
def _quiz():
|
|
id = session.get('id')
|
|
try:
|
|
if not id or not Entry.query.filter_by(id=id).first():
|
|
flash('Your session was not recognised. Please sign in to the quiz again.', 'error')
|
|
session.pop('id', None)
|
|
return redirect(url_for('quiz._start'))
|
|
except (SQLAlchemyError, ConnectionError) as exception:
|
|
write('system.log', f'Database error when processing request \'{request.url}\': {exception}')
|
|
return abort(500)
|
|
return render_template('/quiz/client.html')
|
|
|
|
@quiz.route('/result/')
|
|
def _result():
|
|
id = session.get('id')
|
|
try: entry = Entry.query.filter_by(id=id).first()
|
|
except (SQLAlchemyError, ConnectionError) as exception:
|
|
write('system.log', f'Database error when processing request \'{request.url}\': {exception}')
|
|
return abort(500)
|
|
if not entry: return abort(404)
|
|
session.pop('id',None)
|
|
score = round(100*entry.result['score']/entry.result['max'])
|
|
tags_low = { tag: tag_result['max'] - tag_result['scored'] for tag, tag_result in entry.result['tags'].items() }
|
|
sorted_low_tags = sorted(tags_low.items(), key=lambda x: x[1], reverse=True)
|
|
tag_output = [ tag[0] for tag in sorted_low_tags[0:3] if tag[1] > 3]
|
|
if not entry.status == 'late':
|
|
entry.notify_result()
|
|
return render_template('/quiz/result.html', entry=entry, score=score, tag_output=tag_output) |