Added question generating API
This commit is contained in:
		@@ -2,7 +2,10 @@ import os
 | 
				
			|||||||
import pathlib
 | 
					import pathlib
 | 
				
			||||||
from json import dump, loads
 | 
					from json import dump, loads
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from flask.json import jsonify
 | 
				
			||||||
from main import app
 | 
					from main import app
 | 
				
			||||||
 | 
					from random import shuffle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from werkzeug.utils import secure_filename
 | 
					from werkzeug.utils import secure_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,3 +62,35 @@ def store_data_file(file, default:bool=None):
 | 
				
			|||||||
        with open(os.path.join(app.config['DATA_FILE_DIRECTORY'], '.default.txt'), 'w') as _file:
 | 
					        with open(os.path.join(app.config['DATA_FILE_DIRECTORY'], '.default.txt'), 'w') as _file:
 | 
				
			||||||
            _file.write(filename)
 | 
					            _file.write(filename)
 | 
				
			||||||
    return filename
 | 
					    return filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def randomise_list(list:list):
 | 
				
			||||||
 | 
					    _list = list.copy()
 | 
				
			||||||
 | 
					    shuffle(_list)
 | 
				
			||||||
 | 
					    return(_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generate_questions(dataset:dict):
 | 
				
			||||||
 | 
					    questions_list = dataset['questions']
 | 
				
			||||||
 | 
					    output = []
 | 
				
			||||||
 | 
					    for block in randomise_list(questions_list):
 | 
				
			||||||
 | 
					        if block['type'] == 'question':
 | 
				
			||||||
 | 
					            question = {
 | 
				
			||||||
 | 
					                'q_type': 'question',
 | 
				
			||||||
 | 
					                'q_no': block['q_no'],
 | 
				
			||||||
 | 
					                'question_header': '',
 | 
				
			||||||
 | 
					                'text': block['text'],
 | 
				
			||||||
 | 
					                'options': randomise_list(block['options'])
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            output.append(question)
 | 
				
			||||||
 | 
					        if block['type'] == 'block':
 | 
				
			||||||
 | 
					            for key, _question in enumerate(randomise_list(block['questions'])):
 | 
				
			||||||
 | 
					                question = {
 | 
				
			||||||
 | 
					                    'q_type': 'block',
 | 
				
			||||||
 | 
					                    'q_no': _question['q_no'],
 | 
				
			||||||
 | 
					                    'question_header': block['question_header'] if 'question_header' in block else '',
 | 
				
			||||||
 | 
					                    'block_length': len(block['questions']),
 | 
				
			||||||
 | 
					                    'block_q_no': key,
 | 
				
			||||||
 | 
					                    'text': _question['text'],
 | 
				
			||||||
 | 
					                    'options': randomise_list(_question['options'])
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                output.append(question)
 | 
				
			||||||
 | 
					    return output
 | 
				
			||||||
@@ -26,7 +26,8 @@ $('form[name=form-quiz-start]').submit(function(event) {
 | 
				
			|||||||
        data: data,
 | 
					        data: data,
 | 
				
			||||||
        dataType: 'json',
 | 
					        dataType: 'json',
 | 
				
			||||||
        success: function(response) {
 | 
					        success: function(response) {
 | 
				
			||||||
            window.location.href = "/admin/login/";
 | 
					            var _id = response._id
 | 
				
			||||||
 | 
					            window.location.href = `/api/questions/${_id}`;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        error: function(response) {
 | 
					        error: function(response) {
 | 
				
			||||||
            if (typeof response.responseJSON.error === 'string' || response.responseJSON.error instanceof String) {
 | 
					            if (typeof response.responseJSON.error === 'string' || response.responseJSON.error instanceof String) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,13 @@
 | 
				
			|||||||
from flask import Blueprint, render_template, request, redirect, jsonify
 | 
					from flask import Blueprint, render_template, request, redirect, jsonify, session, abort
 | 
				
			||||||
 | 
					from flask.helpers import url_for
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
from uuid import uuid4
 | 
					from uuid import uuid4
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from json import loads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from main import db
 | 
					from main import app, db
 | 
				
			||||||
from common.security import encrypt
 | 
					from common.security import encrypt
 | 
				
			||||||
 | 
					from common.data_tools import generate_questions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
views = Blueprint(
 | 
					views = Blueprint(
 | 
				
			||||||
    'quiz_views',
 | 
					    'quiz_views',
 | 
				
			||||||
@@ -42,17 +46,44 @@ def start():
 | 
				
			|||||||
                'name': encrypt(name),
 | 
					                'name': encrypt(name),
 | 
				
			||||||
                'email': encrypt(email),
 | 
					                'email': encrypt(email),
 | 
				
			||||||
                'club': encrypt(club),
 | 
					                'club': encrypt(club),
 | 
				
			||||||
                'test-code': test_code,
 | 
					                'test_code': test_code,
 | 
				
			||||||
                'user_code': user_code,
 | 
					                'user_code': user_code,
 | 
				
			||||||
                'start_time': datetime.utcnow(),
 | 
					                'start_time': datetime.utcnow(),
 | 
				
			||||||
                'status': 'started'
 | 
					                'status': 'started'
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if db.entries.insert(entry):
 | 
					            if db.entries.insert(entry):
 | 
				
			||||||
                return jsonify({ 'success': f'Exam started at started {entry["start_time"].strftime("%H:%M:%S")}.' })
 | 
					                session['_id'] = entry['_id'] # Change this to return _id via JSON so client can access. Client will not be able to decrypt session cookie.
 | 
				
			||||||
 | 
					                return jsonify({
 | 
				
			||||||
 | 
					                    'success': 'Success! An exam entry was started.',
 | 
				
			||||||
 | 
					                    '_id': entry['_id']
 | 
				
			||||||
 | 
					                }), 200
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            errors = [*form.errors]
 | 
					            errors = [*form.errors]
 | 
				
			||||||
            return jsonify({ 'error': errors}), 400
 | 
					            return jsonify({ 'error': errors}), 400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@views.route('/api/questions/<_id>')
 | 
				
			||||||
 | 
					def fetch_questions(_id):
 | 
				
			||||||
 | 
					    entry = db.entries.find_one({'_id': _id}) 
 | 
				
			||||||
 | 
					    if not entry:
 | 
				
			||||||
 | 
					        return abort(404)
 | 
				
			||||||
 | 
					    test_code = entry['test_code']
 | 
				
			||||||
 | 
					    # user_code = entry['user_code'] Implement functionality for adjustments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test = db.tests.find_one({'test_code' : test_code})
 | 
				
			||||||
 | 
					    dataset = test['dataset']
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    dataset_path = os.path.join(app.config['DATA_FILE_DIRECTORY'], dataset)
 | 
				
			||||||
 | 
					    with open(dataset_path, 'r') as data_file:
 | 
				
			||||||
 | 
					        data = loads(data_file.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    questions = generate_questions(data)
 | 
				
			||||||
 | 
					    time_limit = test['time_limit']
 | 
				
			||||||
 | 
					    return jsonify({
 | 
				
			||||||
 | 
					        'time_limit': time_limit,
 | 
				
			||||||
 | 
					        'questions': questions
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@views.route('/privacy/')
 | 
					@views.route('/privacy/')
 | 
				
			||||||
def privacy():
 | 
					def privacy():
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user