def gen_materials(): course_offerings = db.select_columns('course_offerings', ['id', 'course']) # currently adds a presentation and report for each thesis for course in course_offerings: # filtering out any courses not a thesis name = db.select_columns( 'courses', ['name'], ['id'], [course[1]] ) if len(name) == 0: continue name = name[0][0].lower() if 'thesis' not in name: continue # entering 2 materials for each thesis queries = [] queries.append(( 'materials', ['Course Outline', course[0]], ['name', 'course_offering'] )) queries.append(( 'materials', [f'Sample Report {name.title()}', course[0]], ['name', 'course_offering'] )) db.insert_multiple(queries)
def gen_sessions(): ret = [] for year in range(2018, 2019): ret.append([year, 1, datetime.datetime(year, 1, 1, 0, 0, 0).timestamp(), datetime.datetime(year, 6, 30, 23, 59, 59).timestamp() ]) ret.append([year, 2, datetime.datetime(year, 7, 1, 0, 0, 0).timestamp(), datetime.datetime(year, 11, 30, 23, 59, 59).timestamp() ]) for year in range(2019, 2021): ret.append([year, 1, datetime.datetime(year, 2, 18, 0, 0, 0).timestamp(), datetime.datetime(year, 5, 18, 23, 59, 59).timestamp() ]) ret.append([year, 2, datetime.datetime(year, 6, 3, 0, 0, 0).timestamp(), datetime.datetime(year, 8, 31, 23, 59, 59).timestamp() ]) ret.append([year, 3, datetime.datetime(year, 9, 16, 0, 0, 0).timestamp(), datetime.datetime(year, 12, 14, 23, 59, 59).timestamp() ]) query = [] for sess in ret: query.append(('sessions', sess, ['year', 'term', 'start_date', 'end_date'])) db.insert_multiple(query) return ret
def create_course(): db.connect() curr_year = datetime.now().year num_terms = queries.get_terms_per_year(curr_year) course = {'offerings': [False for _ in range(num_terms)]} try: res = get_fields(request.form, ['title', 'code', 'description', 'year'], ['year']) for i in range(num_terms): if str(i + 1) in request.form: course['offerings'][i] = True except ValueError as e: db.close() return e.args[0] course['title'] = res[0] course['code'] = res[1] course['description'] = res[2] if not re.match(config.COURSE_CODE_FORMAT, course['code']): db.close() return error("Invalid course code", 'code') course['year'] = int(res[3]) if curr_year > course['year']: db.close() return error(f"Year must be at least {curr_year}") if True not in course['offerings']: db.close() return error('You must select at least one term offering') sessions = queries.get_course_sessions(course['code']) sessions = filter(lambda s: s[0] == course['year'], sessions) for year, term in sessions: if course['offerings'][term - 1]: db.close() return error(f"{course['code']} already offered in {year} T{term}") db.insert_single('courses', [course['code'], course['title'], course['description']], ['code', 'name', 'description']) res = db.select_columns('courses', ['id'], ['code'], [course['code']]) course['id'] = res[0][0] query = [] for i in range(len(course['offerings'])): if not course['offerings'][i]: continue res = db.select_columns('sessions', ['id'], ['year', 'term'], [course['year'], i + 1]) session_id = res[0][0] query.append(('course_offerings', [course['id'], session_id], ['course', 'session'])) db.insert_multiple(query) db.close() return jsonify({'status': 'ok'})
def gen_submissions(): acc_types = get_all_account_types() request_types = get_all_request_types() students = db.select_columns( 'users', ['id', 'email'], ['account_type'], [acc_types['student']] ) upload_dir = Path(config.STATIC_PATH) / Path(config.FILE_UPLOAD_DIR) upload_dir.mkdir(exist_ok=True) sample_submission = Path('db/sample_submission.pdf') for student in students: tasks = db_queries.get_user_tasks(student[0]) now = datetime.datetime.now().timestamp() queries = [] zid = student[1].split('@')[0] for task in tasks: # if task is in the future, don't create a submission if task[4] > now: deadline_time = datetime.datetime.fromtimestamp(task[4]) now_time = datetime.datetime.fromtimestamp(now) dif = deadline_time - now_time if dif.days > 14: continue number = random.randrange(10) if number > 2: continue stem = Path(str(uuid.uuid4()) + 'sample_submission.pdf') path = upload_dir / stem copyfile(sample_submission, path) sub_name = '{zid}-{task_name}'.format(zid=zid, task_name=task[1]) if 'approval' in task[3]: queries.append(( 'submissions', [student[0], task[0], sub_name, None, 'Here is a lengthy essay', now, request_types['approved']] )) else: queries.append(( 'submissions', [student[0], task[0], sub_name, str(stem), 'Here is a lengthy description', now, request_types['pending mark']] )) db.insert_multiple(queries)
def gen_topics(): with open('db/topics.json') as f: topics = json.load(f) query = [] supervisor_type = db.select_columns('account_types', ['id'], ['name'], ['supervisor'])[0][0] supervisors = db.select_columns('users', ['id'], ['account_type'], [supervisor_type]) # remove any topics with empty areas or descriptions for i in range(len(topics)-1, -1, -1): if len(topics[i]['areas']) == 0: topics.pop(i) elif len(topics[i]['description']) == 0: topics.pop(i) topics_per_sup = math.floor(len(topics)/len(supervisors)) topics_per_sup = min(topics_per_sup, 10) course_ids = db.select_columns('courses', ['id'], ['prereq'], [1]) course_ids = list(map(lambda x: x[0], course_ids)) base_topic_id = 1 for sup in supervisors: for i in range(0, topics_per_sup): t = topics[i+base_topic_id] query.append(( 'topics', [i+base_topic_id, t['name'], sup[0], t['description'], random.randrange(0, 2)], ['id', 'name', 'supervisor', 'description', 'visible'] )) gen_topic_areas(i+base_topic_id, t['areas']) gen_topic_prereqs(i+base_topic_id, course_ids) base_topic_id += topics_per_sup db.insert_multiple(query)
def gen_task_critera(): tasks = db.select_columns('tasks', ['id', 'name', 'marking_method']) for task in tasks: queries = [] if(task[2] == 1): queries.append(( 'task_criteria', [task[0], 'Approval', 100], ['task', 'name', 'max_mark'] )) else: queries.append(( 'task_criteria', [task[0], 'Technical Quality and Completeness', 80], ['task', 'name', 'max_mark'] )) queries.append(( 'task_criteria', [task[0], 'Structure and Presentation', 20], ['task', 'name', 'max_mark'] )) db.insert_multiple(queries)
def create(): course_id = request.args.get('course_offering_id', None, type=int) if request.method == 'GET': if course_id is None: abort(400) db.connect() res = db.select_columns('course_offerings', ['id'], ['id'], [course_id]) if not len(res): db.close() abort(404) file_types = db.select_columns('file_types', ['name']) file_types = list(map(lambda x: x[0], file_types)) allowed_file_types = ','.join(file_types) heading = 'Create Task' default_fields = { 'task-name': '', 'deadline': '', 'task-description': '', 'submission-type': 'text', 'word-limit': '', 'maximum-file-size': '', 'accepted-file-type': '', 'marking-method': 'accept', 'criteria': [], 'task_attachments': [] } # if updating old task then load old task data old_task_id = request.args.get('update', None, type=int) if old_task_id is not None: res = queries.get_past_task_data(old_task_id) if res is not None: res = res[0] heading = 'Edit Task' # basic task details default_fields['task-name'] = res[0] time_format = '%d/%m/%Y %H:%M' due_date = datetime.fromtimestamp(res[1]) default_fields['deadline'] = due_date.strftime(time_format) default_fields['task-description'] = res[2] attachments = db.select_columns('task_attachments', ['path'], ['task'], [old_task_id]) for r in attachments: file = [FileUpload(filename=r[0])] default_fields['task_attachments'] = file # submission method specific if res[3] == 'text submission': default_fields['word-limit'] = res[4] else: default_fields['submission-type'] = 'file' default_fields['maximum-file-size'] = int(res[5]) default_fields['accepted-file-type'] = res[6] # marking method specifics if res[7] == 'requires mark': default_fields['marking-method'] = 'criteria' crit = db.select_columns('task_criteria', ['name, max_mark'], ['task'], [old_task_id]) if crit is not None: default_fields['criteria'] = crit db.close() if default_fields['maximum-file-size'] == '': default_fields['maximum-file-size'] = 5 if default_fields['accepted-file-type'] == '': default_fields['accepted-file-type'] = '.pdf' return render_template('create_task.html', heading=heading, title=heading, file_types=file_types, course_id=course_id, max_file_size=config.MAX_FILE_SIZE, max_word_limit=config.MAX_WORD_LIMIT, accepted_file_types=allowed_file_types, old_task_id=old_task_id, default_fields=default_fields) try: fields = [ 'task-name', 'deadline', 'task-description', 'submission-type', 'word-limit', 'maximum-file-size', 'accepted-file-type', 'marking-method', 'num-criteria', 'course-id', 'file-name', 'old_task_id', 'delete_old_attachment' ] task_name, deadline, task_description, submission_type, \ word_limit, max_file_size, accepted_ftype, marking_method, \ num_criteria, course_id, file_name, old_task_id, \ delete_old_attachment = \ get_fields(request.form, fields, optional=['word-limit', 'file-name'], ints=['maximum-file-size', 'num-criteria', 'word-limit', 'course-id', 'delete_old_attachment']) except ValueError as e: return e.args[0] try: old_task_id = int(old_task_id) except ValueError as e: old_task_id = None try: deadline = datetime.strptime(deadline, '%d/%m/%Y %H:%M').timestamp() except ValueError: return error('Invalid date format for deadline!') if submission_type == 'file': max_size = config.MAX_FILE_SIZE if not (1 <= max_file_size <= max_size): return error( f'Maximum file size must be between 1 and {max_size}!') elif submission_type == 'text': try: word_limit = get_fields(request.form, ['word-limit'], ints=['word-limit'])[0] except ValueError as e: return e.args[0] max_word_limit = config.MAX_WORD_LIMIT if not (1 <= word_limit <= max_word_limit): return error(f'Word limit must be between 1 and {max_word_limit}!') else: return error('Unknown submission type!') if marking_method == 'criteria': if num_criteria < 1: return error('At least one marking criterion is required!') else: criteria = [f'criteria-{i}' for i in range(1, num_criteria + 1)] marks = [f'maximum-mark-{i}' for i in range(1, num_criteria + 1)] try: criteria = get_fields(request.form, criteria) marks = get_fields(request.form, marks, ints=marks) except ValueError as e: return e.args[0] if sum([mark for mark in marks]) != 100: return error('Marks must add to 100!') elif marking_method != 'accept': return error('Unknown marking method!') db.connect() res = db.select_columns('course_offerings', ['id'], ['id'], [course_id]) if not len(res): db.close() return error('Cannot create task for unknown course!') res = db.select_columns('tasks', ['id', 'name'], ['name', 'course_offering'], [task_name, course_id]) if len(res) and res[0][0] != old_task_id: db.close() return error('A task with that name already exists in this course!') # retrieve some foreign keys for insertion res = db.select_columns('file_types', ['id'], ['name'], [accepted_ftype]) if not len(res): db.close() return error('Invalid or unsupported file type!') file_type_id = res[0][0] # upload file if present sent_file = None if len(file_name): try: sent_file = FileUpload(req=request) except KeyError: db.close() return error('Could not find a file to upload') res = db.select_columns('file_types', ['name']) file_types = list(map(lambda x: x[0], res)) if sent_file.get_extention() not in file_types: db.close() accept_files = ', '.join(file_types) return error(f'Accepted file types are: {accept_files}') if sent_file.get_size() > config.MAX_FILE_SIZE: sent_file.remove_file() db.close() return error( f'File exceeds the maximum size of {config.MAX_FILE_SIZE} MB') sent_file.commit() if (len(file_name) and old_task_id is not None) or delete_old_attachment: old = db.select_columns('task_attachments', ['path'], ['task'], [old_task_id]) if old: db.delete_rows('task_attachments', ['task'], [old_task_id]) try: prev_submission = FileUpload(filename=old[0][0]) prev_submission.remove_file() except LookupError: # If the file doesn't exists don't worry as we are deleting # the attachment anyway pass res = db.select_columns('submission_methods', ['id'], ['name'], ['{} submission'.format(submission_type)]) submission_method_id = res[0][0] marking_method = 'approval' if marking_method == 'accept' else 'mark' res = db.select_columns('marking_methods', ['id'], ['name'], ['requires {}'.format(marking_method)]) mark_method_id = res[0][0] # commit task if old_task_id is not None: # update an existing task db.update_rows('tasks', [ task_name, course_id, deadline, task_description, max_file_size, submission_method_id, mark_method_id, word_limit ], [ 'name', 'course_offering', 'deadline', 'description', 'size_limit', 'submission_method', 'marking_method', 'word_limit' ], ['id'], [old_task_id]) else: # add a new task` db.insert_single('tasks', [ task_name, course_id, deadline, task_description, max_file_size, 0, submission_method_id, mark_method_id, word_limit ], [ 'name', 'course_offering', 'deadline', 'description', 'size_limit', 'visible', 'submission_method', 'marking_method', 'word_limit' ]) res = db.select_columns('tasks', ['id'], ['name', 'course_offering'], [task_name, course_id]) task_id = res[0][0] if sent_file: db.insert_single('task_attachments', [task_id, sent_file.get_name()], ['task', 'path']) # delete old entries in other tables if old_task_id is not None: db.delete_rows('submission_types', ['task'], [old_task_id]) res = db.select_columns('task_criteria', ['id'], ['task'], [old_task_id]) for r in res: db.delete_rows('marks', ['criteria'], [r[0]]) db.delete_rows('task_criteria', ['task'], [old_task_id]) # commit accepted file type db.insert_single('submission_types', [file_type_id, task_id], ['file_type', 'task']) # commit marking criteria marking_criteria = [] if marking_method == 'approval': marking_criteria.append( ('task_criteria', [task_id, 'Approval', 100], ['task', 'name', 'max_mark'])) else: for i in range(len(criteria)): marking_criteria.append( ('task_criteria', [task_id, criteria[i], marks[i]], ['task', 'name', 'max_mark'])) db.insert_multiple(marking_criteria) db.close() return jsonify({'status': 'ok'})
def gen_marks(): acc_types = get_all_account_types() students = db.select_columns( 'users', ['id'], ['account_type'], [acc_types['student']] ) request_types = get_all_request_types() for student in students: markers = db_queries.get_user_ass_sup(student[0]) if len(markers) == 0: continue markers = markers[0] if None in markers: continue tasks = db_queries.get_user_tasks(student[0]) for task in tasks: if 'approval' in task[3]: continue now = datetime.datetime.now().timestamp() deadline = task[4] if deadline > now: continue criteria_ids = db.select_columns( 'task_criteria', ['id', 'max_mark'], ['task'], [task[0]] ) queries = [] # create the marks for criteria in criteria_ids: mark = random.randrange(criteria[1]) if(mark/criteria[1] < .5): feedback = "Not of a high enough quality, there's"\ + " a lot of room for improvement." elif(mark/criteria[1] < .7): feedback = "Some parts are of poor quality, and there's"\ + " room for some improvement, but overall a"\ + " decent attempt." else: feedback = "Amazing quality, a few parts could use some"\ + " polishing but great job!" queries.append(( 'marks', [criteria[0], mark, student[0], markers[0], feedback, None] )) mark = random.randrange(criteria[1]) if(mark/criteria[1] < .5): feedback = "Not of a high enough quality, there's"\ + " a lot of room for improvement." elif(mark/criteria[1] < .7): feedback = "Some parts are of poor quality, and there's"\ + " room for some improvement, but overall a"\ + " decent attempt." else: feedback = "Amazing quality, a few parts could use some"\ + " polishing but great job!" queries.append(( 'marks', [criteria[0], mark, student[0], markers[1], feedback, None] )) db.insert_multiple(queries) db.update_rows( 'submissions', [request_types['marked']], ['status'], ['student', 'task'], [student[0], task[0]] )
def gen_users(): with open('db/names.json') as f: names = json.load(f) types = get_all_account_types() password = bcrypt.hashpw('password1'.encode('utf-8'), bcrypt.gensalt()) query = [] timestamp = 946645140 # student users students = [] for i in range(100): zid = 'z{}'.format(str(1000001 + i)) students.append(zid) name = names[i]['name'] query.append(('users', [name, f'{zid}@unsw.edu.au', password, types['student'], '', '', timestamp], ['name', 'email', 'password', 'account_type', 'confirm_code', 'reset_code', 'date_created'])) # public users public = [] for i in range(20): zid = 'z{}'.format(str(4000001 + i)) public.append(zid) name = names[100+i]['name'] query.append(('users', [name, f'{zid}@unsw.edu.au', password, types['public'], '', '', timestamp], ['name', 'email', 'password', 'account_type', 'confirm_code', 'reset_code', 'date_created'])) # supervisor/assessor users supervisors = [] for i in range(10): zid = 'z{}'.format(str(8000001 + i)) supervisors.append(zid) name = names[200+i]['name'] query.append(('users', [name, f'{zid}@unsw.edu.au', password, types['supervisor'], '', '', timestamp], ['name', 'email', 'password', 'account_type', 'confirm_code', 'reset_code', 'date_created'])) # course admin users course_admin = [] for i in range(5): zid = 'z{}'.format(str(9000001 + i)) course_admin.append(zid) name = names[300+i]['name'] query.append(('users', [name, f'{zid}@unsw.edu.au', password, types['course_admin'], '', '', timestamp], ['name', 'email', 'password', 'account_type', 'confirm_code', 'reset_code', 'date_created'])) db.insert_multiple(query)