import secrets from datetime import datetime from uuid import uuid4 from flask import flash, jsonify import secrets import os from json import dump, loads from main import app, db from common.security import encrypt class Test: def __init__(self, _id=None, start_date=None, expiry_date=None, time_limit=None, creator=None, dataset=None): self._id = _id self.start_date = start_date self.expiry_date = expiry_date self.time_limit = None if time_limit == 'none' or time_limit == '' or time_limit == None else int(time_limit) self.creator = creator self.dataset = dataset def create(self): test = { '_id': self._id, 'date_created': datetime.today(), 'start_date': self.start_date, 'expiry_date': self.expiry_date, 'time_limit': self.time_limit, 'creator': encrypt(self.creator), 'test_code': secrets.token_hex(6).upper(), 'dataset': self.dataset } if db.tests.insert_one(test): dataset_file_path = os.path.join(app.config["DATA_FILE_DIRECTORY"],self.dataset) with open(dataset_file_path, 'r') as dataset_file: data = loads(dataset_file.read()) data['meta']['tests'].append(self._id) with open(dataset_file_path, 'w') as dataset_file: dump(data, dataset_file, indent=2) flash(f'Created a new exam with Exam Code {self.render_test_code(test["test_code"])}.', 'success') return jsonify({'success': test}), 200 return jsonify({'error': f'Could not create exam. An error occurred.'}), 400 def add_time_adjustment(self, time_adjustment): adjustment = { '_id': uuid4().hex, 'user_code': secrets.token_hex(3).upper(), 'time_adjustment': time_adjustment } if db.tests.find_one_and_update({'_id': self._id}, {'$push': {'time_adjustments': adjustment}},upsert=False): flash(f'Time adjustment for {adjustment["time_adjustment"]} minutes has been added. This can be enabled using the user code {adjustment["user_code"]}.') return jsonify({'success': adjustment}) return jsonify({'error': 'Failed to add the time adjustment. An error occurred.'}), 400 def remove_time_adjustment(self, _id): if db.tests.find_one_and_update({'_id': self._id}, {'$pull': {'time_adjustments': {'_id': _id} }}): message = 'Time adjustment has been deleted.' flash(message, 'success') return jsonify({'success': message}) return jsonify({'error': 'Failed to delete the time adjustment. An error occurred.'}), 400 def render_test_code(self, test_code): return '—'.join([test_code[:4], test_code[4:8], test_code[8:]]) def parse_test_code(self, test_code): return test_code.replace('—', '') def delete(self): test = db.tests.find_one({'_id': self._id}) if 'entries' in test: if test['entries']: return jsonify({'error': 'Cannot delete an exam that has entries submitted to it.'}), 400 if self.dataset is None: self.dataset = db.tests.find_one({'_id': self._id})['dataset'] if db.tests.delete_one({'_id': self._id}): dataset_file_path = os.path.join(app.config["DATA_FILE_DIRECTORY"],self.dataset) with open(dataset_file_path, 'r') as dataset_file: data = loads(dataset_file.read()) data['meta']['tests'].remove(self._id) with open(dataset_file_path, 'w') as dataset_file: dump(data, dataset_file, indent=2) message = 'Deleted exam.' flash(message, 'alert') return jsonify({'success': message}), 200 return jsonify({'error': f'Could not create exam. An error occurred.'}), 400 def update(self): test = {} updated = [] if not self.start_date == '' and self.start_date is not None: test['start_date'] = self.start_date updated.append('start date') if not self.expiry_date == '' and self.expiry_date is not None: test['expiry_date'] = self.expiry_date updated.append('expiry date') if not self.time_limit == '' and self.time_limit is not None: test['time_limit'] = int(self.time_limit) updated.append('time limit') output = '' if len(updated) == 0: flash(f'There were no changes requested for your account.', 'alert'), 200 return jsonify({'success': 'There were no changes requested for your account.'}), 200 elif len(updated) == 1: output = updated[0] elif len(updated) == 2: output = ' and '.join(updated) elif len(updated) > 2: output = updated[0] for index in range(1,len(updated)): if index < len(updated) - 2: output = ', '.join([output, updated[index]]) elif index == len(updated) - 2: output = ', and '.join([output, updated[index]]) else: output = ''.join([output, updated[index]]) db.tests.find_one_and_update({'_id': self._id}, {'$set': test}) _output = f'The {output} of the test {"has" if len(updated) == 1 else "have"} been updated.' flash(_output) return jsonify({'success': _output}), 200