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 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(): clubs = [ 'Barrowland Bears Korfball Club', 'Dundee Korfball Club', 'Edinburgh City Korfball Club', 'Edinburgh Mavericks Korfball Club', 'Edinburgh University Korfball Club', 'Glasgow Korfball Club', 'Saint Andrews University Korfball Club', 'Strathclyde University Korfball Club' ] try: entries = Entry.query.all() except Exception as exception: write('system.log', f'Database error when processing request \'{request.url}\': {exception}') return abort(500) for entry in entries: clubs.append(entry.get_club()) clubs = list(set(clubs)) try: clubs.remove('') except: pass 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 Exception as exception: write('system.log', f'Database error when processing request \'{request.url}\': {exception}') return abort(500) if not test: return jsonify({'error': 'The exam code you entered is invalid.'}), 400 entry.test = test entry.dataset = test.dataset entry.user_code = request.form.get('user_code') entry.user_code = None if entry.user_code == '' else entry.user_code.lower() 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, clubs = clubs) @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 Exception 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 Exception 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)