def build_student_submission(student_id, task_id): res = db.select_columns( 'submissions', ['name', 'path', 'text', 'date_modified', 'status'], ['student', 'task'], [student_id, task_id]) # Account for no submission and a text based submission (no path) if not res: return {} submission = { 'name': res[0][0], 'date_modified': timestamp_to_string(res[0][3], True), 'status': { 'id': res[0][4] }, 'file': None, 'text': None } task = build_task(task_id) if 'file' in task['sub_method']['name']: submission['file'] = FileUpload(filename=res[0][1]) else: submission['text'] = res[0][2] res = db.select_columns('request_statuses', ['name'], ['id'], [submission['status']['id']]) submission['status']['name'] = res[0][0] if 'approval' in task['mark_method']['name']: submission['mark_method'] = 'approval' else: submission['mark_method'] = 'mark' return submission
def get_student_statuses(task): res = db.select_columns('enrollments', ['user'], ['course_offering'], [task['offering']]) students = [{'id': r[0]} for r in res] for student in students: res = db.select_columns('users', ['name', 'email'], ['id'], [student['id']]) student['name'] = res[0][0] student['email'] = res[0][1] res = db.select_columns('submissions', ['date_modified', 'status'], ['task', 'student'], [task['id'], student['id']]) submissions = [{'date': r[0], 'status': {'id': r[1]}} for r in res] if not submissions: student['submission_date'] = None student['status'] = {'id': -1, 'name': 'not submitted'} else: # We only support one submission at a time student['submission_date'] = submissions[0]['date'] res = db.select_columns('request_statuses', ['name'], ['id'], [submissions[0]['status']['id']]) submissions[0]['status']['name'] = res[0][0] student['status'] = submissions[0]['status'] return students
def check_delete_topic(): data = json.loads(request.data) topic_id = data['topicId'] db.connect() # checking if a student has been enrolled in topic student_topic = db.select_columns('student_topic', ['student'], ['topic'], [topic_id]) if student_topic: db.close() return error( 'Cannot delete this topic!<br>There are enrolled students') # checking if a there is any pending topic requests pending = 'pending' pending_id = db.select_columns('request_statuses', ['id'], ['name'], [pending]) topic_request = db.select_columns('topic_requests', ['student'], ['topic', 'status'], [topic_id, pending_id[0][0]]) if topic_request: db.close() return error( 'Cannot delete this topic!<br>There are pending topic requests.') db.close() return jsonify({'status': 'ok', "message": "Topic deleted"})
def delete_task(): data = json.loads(request.data) task_id = data['taskId'] db.connect() submissions = db.select_columns('submissions', ['name'], ['task'], [task_id]) if submissions: db.close() return error('Cannot delete this task!' + '<br>Students have already made submissions') task_path = db.select_columns('task_attachments', ['path'], ['task'], [task_id]) if task_path: file_upload = FileUpload(filename=task_path[0][0]) file_upload.remove_file() db.delete_rows('tasks', ['id'], [task_id]) db.delete_rows('task_attachments', ['task'], [task_id]) db.delete_rows('task_criteria', ['task'], [task_id]) db.delete_rows('allowed_files', ['task'], [task_id]) db.delete_rows('submission_types', ['task'], [task_id]) db.close() return jsonify({'status': 'ok', "message": "Task deleted"})
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 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 get_sub_status(user, task): status = 'not submitted' submission = db.select_columns('submissions', ['status'], ['student', 'task'], [user, task]) if len(submission) > 0: status_name = db.select_columns('request_statuses', ['name'], ['id'], [submission[0][0]]) status = status_name[0][0] return status
def view_submission(): student_id = request.args.get('submissions', None, type=int) if student_id is None: abort(400) db.connect() student_info = db.select_columns('users', ['name', 'email'], ['id'], [student_id]) if not len(student_info): db.close() abort(404) # get tasks for this student tasks = [] student_tasks = queries.get_student_submissions(student_id) for task in student_tasks: submit_date_text = timestamp_to_string(task[4], True) file_url = None if task[3]: file_url = FileUpload(filename=task[3]).get_url() status = get_sub_status(student_id, task[0]) if 'approval' in task[2]: tasks.append((task[1], submit_date_text, status, file_url, task[0], student_id)) else: criteria = db.select_columns('task_criteria', ['id', 'max_mark'], ['task'], [task[0]]) staff_mark = 0 total_max_mark = 0 for c in criteria: total_max_mark += c[1] mark = db.select_columns('marks', ['mark'], ['criteria', 'student', 'marker'], [c[0], student_id, session['id']]) if len(mark) != 0: staff_mark += mark[0][0] else: staff_mark = -1 if staff_mark <= 0: staff_mark = '- ' tasks.append((task[1], submit_date_text, str(staff_mark) + '/' + str(total_max_mark), file_url, task[0], student_id)) db.close() zid = student_info[0][1].split('@')[0] heading = f'Submissions - {student_info[0][0]} ({zid})' return render_template('submission_staff.html', heading=heading, title=heading, submissions=tasks)
def get_co_id(ses_id, course_name): course_id = db.select_columns( 'courses', ['id'], ['name'], [course_name] )[0][0] co_id = db.select_columns( 'course_offerings', ['id'], ['course', 'session'], [course_id, ses_id] )[0][0] return co_id
def gen_student_topics(): types = get_all_account_types() # get first supervisor sup_ids = db.select_columns( 'users', ['id'], ['account_type'], [types['supervisor']] ) # # Add students supervisor_0 is supervising # # get possible topics topics = db.select_columns('topics', ['id', 'supervisor'],) # get all students students = db.select_columns('users', ['id'], ['account_type'], [types['student']]) student_ids = [] request_student_ids = [] for student in students: number = random.randrange(10) if number > 2: student_ids.append(student[0]) else: request_student_ids.append(student[0]) gen_topic_requests(request_student_ids) # enroll current and past students students # tot_curr_stu = 3 # student_ids = list(range(0, tot_curr_stu)) # student_ids.extend(list(range(int(len(students)/2), # int(len(students)/2+tot_curr_stu)))) for student_id in student_ids: if len(sup_ids) < 2: break number = random.randrange(len(topics)) topic = topics[number][0] supervisor_id = topics[number][1] number = random.randrange(len(sup_ids)) assessor_id = sup_ids[number][0] while assessor_id == supervisor_id: number = random.randrange(len(sup_ids)) assessor_id = sup_ids[number][0] db.insert_single('student_topic', [student_id, topic, assessor_id], ['student', 'topic', 'assessor'])
def request_new_topic(): if session['acc_type'] != 'student': # only students are allowed to request topics # disallow ALL other users from requesting return error('You must be a student to request a topic!') try: fields = ['topic', 'message'] topic, message = get_fields(request.form, fields) except ValueError as e: return e.args[0] db.connect() res = db.select_columns('topics', ['id', 'name', 'supervisor', 'visible'], ['id'], [topic]) topic_name = res[0][1] supervisor = res[0][2] if not len(res): db.close() return error('No such topic exists!') if not int(res[0][3]): db.close() return error('This topic is not available to request!') res = db.select_columns('request_statuses', ['id'], ['name'], ['pending']) user_id = session['id'] now = datetime.now().timestamp() try: db.insert_single( 'topic_requests', [user_id, topic, res[0][0], now, message], ['student', 'topic', 'status', 'date_created', 'text']) except sqlite3.IntegrityError: db.close() return error('You have already requested this topic!') res = db.select_columns('users', ['name', 'email'], ['id'], [supervisor]) hr_tag = '<hr style="border: 1px dashed;">' send_email(to=res[0][1], name=res[0][0], subject='New Topic Request', messages=[ 'A student has requested a thesis topic on offer by you.', f'The topic is titled "{topic_name}".', f'A message from the student is attached below:{hr_tag}', message.replace('\n', '<br>'), f'{hr_tag}You can approve or reject the topic request ' + f'<a href="{config.SITE_HOME}">here</a>.' ]) db.close() return jsonify({'status': 'ok'})
def gen_topic_areas(topic_id, areas): query = [] for area in areas: area = area.title().replace('Hci', 'HCI').replace('And', 'and') res = db.select_columns('topic_areas', ['name'], ['name'], [area]) if len(res) == 0: db.insert_single( 'topic_areas', [area], ['name'] ) area_id = db.select_columns( 'topic_areas', ['id'], ['name'], [area] )[0][0] db.insert_single( 'topic_to_area', [topic_id, area_id], ['topic', 'topic_area'] )
def submit_text_task(): task_id = request.form.get('task', -1) text = request.form.get('text-submission', -1) db.connect() task = build_task(task_id) res = db.select_columns('enrollments', ['user'], ['user', 'course_offering'], [session['id'], task['offering']]) if not res: db.close() return error("User not enrolled in task's course") if not request.form.get('certify', 'false') == 'true': db.close() return error("You must certify this is all your own work") if datetime.now().timestamp() >= task['deadline']: db.close() return error("Submissions closed!<br>You can no longer submit") mark_method_id = None if task['mark_method']['name'] == 'requires approval': mark_method_id = db.select_columns('request_statuses', ['id'], ['name'], ['pending'])[0][0] elif task['mark_method']['name'] == 'requires mark': mark_method_id = db.select_columns('request_statuses', ['id'], ['name'], ['pending mark'])[0][0] # check if text is too long if (len(text.strip().split(' ')) > task["word_limit"]): db.close() return error(f'Your submission exceeds the word limit') res = db.select_columns('submissions', ['*'], ['student', 'task'], [session['id'], task['id']]) if res: # if there's already a submission, delete it db.delete_rows('submissions', ['student', 'task'], [session['id'], task['id']]) db.insert_single('submissions', [ session['id'], task['id'], task['name'], text, datetime.now().timestamp(), mark_method_id ], ['student', 'task', 'name', 'text', 'date_modified', 'status']) db.close() return jsonify({'status': 'ok'})
def allowed_file_access(filename): ''' Check if a file access should be permitted ''' if 'user' not in session: raise KeyError('Not logged in') if not is_at_least_role(UserRole.STUDENT): # public users shouldn't have access to any file uploads return False if is_at_least_role(UserRole.STAFF): # allow staff to have access to anything return True # students should only have access to files they have submitted # or files in tasks within courses they are part of # or material files within courses they are part of # as long as the task and/or material is marked as visible try: name = FileUpload(filename=filename).get_name() except LookupError as e: if config.DEBUG: print(f'Request file: {e}') abort(404) db.connect() submitted_file = db.select_columns('submissions', ['path'], ['student', 'path'], [session['id'], name]) task_files = queries.get_allowed_task_attachments(session['id']) materials = queries.get_allowed_material_attachments(session['id']) db.close() if submitted_file or (task_files and name in task_files) or \ (materials and name in materials): return True else: return False
def confirm(): confirm_code = request.args.get('confirm_code', '') user = request.args.get('user', '') db.connect() # get the user's confirm code & creation date res = db.select_columns( 'users', ['confirm_code', 'date_created', 'email', 'id'], ['name'], [user] ) expired = False now = datetime.now().timestamp() if len(res) and res[0][1] + config.ACCOUNT_EXPIRY < now: expired = True # expire unactivated accounts every 24 hours db.delete_rows('users', ['name'], [user]) flash('This activation link has expired!<br>' + 'You must register your account again.', 'error') if not expired and len(res) and confirm_code == res[0][0]: # clear confirm code to "mark" account as activated user_id = res[0][3] res = db.select_columns( 'update_account_types', ['id', 'new_name', 'account_type', 'course_offering'], ['email'], [res[0][2]] ) if len(res) > 0: db.update_rows( 'users', ['', res[0][1], res[0][2]], ['confirm_code', 'name', 'account_type'], ['name'], [user] ) if res[0][3] is not None: account_types = get_all_account_types() course_role = 'staff' if account_types['student'] == res[0][2]: course_role = 'student' course_role_id = db.select_columns( 'course_roles', ['id'], ['name'], [course_role] ) enroll_user(user_id, res[0][3], course_role_id[0][0]) db.delete_rows('update_account_types', ['id'], [res[0][0]]) else: db.update_rows('users', [''], ['confirm_code'], ['name'], [user]) flash('Account activated! You can now log in.', 'success') db.close() return redirect(url_for('.login'))
def reset(): if request.method == 'GET': user_id = request.args.get('user', None) reset_id = request.args.get('resetID', None) db.connect() res = db.select_columns('users', ['id'], ['reset_code'], [reset_id]) db.close() if not len(res) or user_id != str(res[0][0]): return redirect(url_for('auth.login')) return render_template('reset_password.html', title='Reset Password', hide_navbar=True, user_id=user_id, reset_id=reset_id) data = json.loads(request.data) user_id = data['user_id'] reset_id = data['reset_id'] new_pass = data['new_pass'] new_confirm = data['new_confirm'] if len(new_pass) < 8: return error('Password must be at least 8 characters long!', 'new-password') if new_pass != new_confirm: return error('Passwords do not match!', 'new-confirm-password') db.connect() reset_id_test = db.select_columns('users', ['reset_code'], ['id'], [user_id])[0][0] hash_pass = bcrypt.hashpw(new_pass.encode('utf-8'), bcrypt.gensalt()) if reset_id == reset_id_test: db.update_rows('users', [hash_pass, ''], ['password', 'reset_code'], ['id'], [user_id]) else: db.close() return error('You are not allowed to change this password!') db.close() return jsonify({'status': 'ok'})
def get_chips(): topic_id = request.args.get('update', None, type=str) if topic_id: topic_id = topic_id.split('-')[2] db.connect() topic_areas = db.select_columns('topic_areas', ['name']) prereqs = db.select_columns('courses', ['code'], ['prereq'], [1]) chips_topic = {} for topic in topic_areas: chips_topic[topic[0]] = None chips_prereqs = {} for prereq in prereqs: chips_prereqs[prereq[0]] = None if topic_id: old_areas = [] old_prereqs = [] areas = queries.get_topic_areas(topic_id) prereqs = queries.get_prereqs_by_topic(topic_id) for area in areas: old_areas.append({'tag': area[0]}) for prereq in prereqs: old_prereqs.append(({'tag': prereq[0]})) db.close() return jsonify({ 'status': 'ok', 'chips_topic': chips_topic, 'chips_prereqs': chips_prereqs, 'old_areas': old_areas, 'old_prereqs': old_prereqs }) else: db.close() return jsonify({ 'status': 'ok', 'chips_topic': chips_topic, 'chips_prereqs': chips_prereqs })
def build_task(task_id): 'Assumes you already have a database connection open' res = db.select_columns('tasks', [ 'deadline', 'marking_method', 'visible', 'course_offering', 'word_limit', 'name', 'description', 'submission_method', 'word_limit', 'size_limit' ], ['id'], [task_id]) if not res: return None task = { 'id': task_id, 'deadline': res[0][0], 'pretty_deadline': timestamp_to_string(res[0][0], True), 'mark_method': { 'id': res[0][1] }, 'sub_method': { 'id': res[0][7] }, 'visible': res[0][2], 'offering': res[0][3], 'word_limit': res[0][4], 'name': res[0][5], 'description': res[0][6], 'text_limit': res[0][8], 'file_limit': res[0][9], 'attachment': None, 'accepted_files': queries.get_tasks_accepted_files(task_id) } res = queries.get_general_task_info(task_id) task['course_name'] = res[0][0] res = db.select_columns('marking_methods', ['name'], ['id'], [task['mark_method']['id']]) task['mark_method']['name'] = res[0][0] res = db.select_columns('submission_methods', ['name'], ['id'], [task['sub_method']['id']]) task['sub_method']['name'] = res[0][0] res = db.select_columns('task_attachments', ['path'], ['task'], [task_id]) if res: task['attachment'] = FileUpload(filename=res[0][0]) return task
def get_sessions(): data = json.loads(request.data) db.connect() res = db.select_columns('course_offerings', ['session'], ['course'], [data]) sessions = [] for co in res: ses_details = db.select_columns('sessions', ['year', 'term'], ['id'], [co[0]])[0] if ses_details[0] < 2019: ses_string = str(ses_details[0])[2:] + 'S' + str(ses_details[1]) else: ses_string = str(ses_details[0])[2:] + 'T' + str(ses_details[1]) sessions.append((ses_string, co[0])) db.close() if len(session) > 0: return jsonify({'status': 'ok', 'data': sessions}) else: return error("Failed to find sessions")
def login(): if 'user' in session: # if already logged in, redirect to home page return redirect(url_for('home.dashboard')) if request.method == 'GET': return render_template('login.html', title='Login', hide_navbar=True) try: email, password = get_fields(request.form, ['email', 'password']) except ValueError as e: return e.args[0] db.connect() res = db.select_columns('users', ['password', 'account_type', 'id', 'name', 'confirm_code'], ['email'], [email]) if not len(res): db.close() return error('Unknown email!', 'email') hashed_password = res[0] if not bcrypt.checkpw(password.encode('utf-8'), hashed_password[0]): db.close() return error('Incorrect password!', 'password') if res[0][4] != '': db.close() return error('You must first confirm your account!') # get the current user's account type acc_type = db.select_columns('account_types', ['name'], ['id'], [res[0][1]])[0][0] session['user'] = email session['name'] = res[0][3] session['id'] = res[0][2] session['acc_type'] = acc_type db.close() return jsonify({'status': 'ok'})
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 update_course_offering(): data = json.loads(request.data) db.connect() course_id = data[0]['value'] session_id = data[1]['value'] res = db.select_columns('course_offerings', ['id'], ['session', 'course'], [session_id, course_id]) db.close() if len(res) > 0: session['current_co'] = res[0][0] return jsonify({'status': 'ok'}) else: return error("Failed to find course offering")
def gen_course_offering(): with open('db/courses.json') as f: for c in json.load(f): res = db.select_columns('courses', ['id'], ['code'], [c['code']]) assert len(res) > 0 course_id = res[0][0] if(c['semester']): # create offerings for thesis A/B in years before 2019 session_ids = db.select_columns_operator('sessions', ['id'], ['year'], ['2019'], '<') for session_id in session_ids: db.insert_single('course_offerings', [course_id, session_id[0]], ['course', 'session']) else: # create offering for thesis A/B/C in years after 2018 session_ids = db_queries.get_session_ids_in_range(2019, 2021) for session_id in session_ids: db.insert_single('course_offerings', [course_id, session_id[0]], ['course', 'session']) session_id = db.select_columns( 'sessions', ['id'], ['year', 'term'], [2019, 1] )[0][0] course_id = db.select_columns( 'courses', ['id'], ['code'], ['COMP4931'] )[0][0] db.insert_single( 'course_offerings', [session_id, course_id], ['session', 'course'] )
def get_chips(): db.connect() topic_area = db.select_columns('topic_areas', ['name']) account_types = get_all_account_types() supervisors = db.select_columns('users', ['name'], ['account_type'], [account_types['supervisor']]) supervisors += db.select_columns('users', ['name'], ['account_type'], [account_types['course_admin']]) chips_topic_area = {} for topic in topic_area: chips_topic_area[topic[0]] = None chips_supervisor = {} for sup in supervisors: chips_supervisor[sup[0]] = None db.close() return jsonify({ 'status': 'ok', 'chipsTopic': chips_topic_area, 'chipsSuper': chips_supervisor })
def check_delete_task(): data = json.loads(request.data) task_id = data['taskId'] db.connect() submissions = db.select_columns('submissions', ['name'], ['task'], [task_id]) db.close() if submissions: msg = 'Cannot delete this task!<br>' \ + 'Students have already made submissions' return error(msg) return jsonify({'status': 'ok', "message": "Task deleted"})
def get_next_course(name): last_char = name[-1] if last_char == 'A': last_char = 'B' else: last_char = 'C' course_name = name[:-1] + last_char res = db.select_columns( 'courses', ['id', 'name', 'code'], ['name'], [course_name] ) if len(res) > 0: return res[0] return []
def gen_task_outline(): tasks = db.select_columns('tasks', ['id'], None, None) upload_dir = Path(config.STATIC_PATH) / Path(config.FILE_UPLOAD_DIR) upload_dir.mkdir(exist_ok=True) sample_attachment = Path('db/sample_attachment.pdf') for task in tasks: stem = Path(str(uuid.uuid4()) + 'sample_attachment.pdf') path = upload_dir / stem copyfile(sample_attachment, path) db.insert_single( 'task_attachments', [task[0], str(stem)], ['task', 'path'] )
def respond_request(): data = get_fields(request.form, ['response', 'student-id', 'topic']) db.connect() req_status = 'approved' if data[0] == 'accept' else 'rejected' if req_status == 'approved': if 'assessor' not in request.form: db.close() return error('You must specify an assessor') db.delete_rows('student_topic', ['student'], [data[1]]) db.insert_single('student_topic', [data[1], data[2], request.form['assessor']], ['student', 'topic', 'assessor']) queries.respond_topic(data[1], data[2], req_status, datetime.now().timestamp()) res = db.select_columns('users', ['email', 'name'], ['id'], [data[1]])[0] student = {'email': res[0], 'name': res[1]} topic = db.select_columns('topics', ['name'], ['id'], [data[2]])[0][0] db.close() send_email(student['email'], student['name'], 'Topic Reply', [f'Your topic request for "{topic}" has been {req_status}.']) return jsonify({'status': 'ok'})
def gen_material_attachments(): materials = db.select_columns('materials', ['id']) upload_dir = Path(config.STATIC_PATH) / Path(config.FILE_UPLOAD_DIR) upload_dir.mkdir(exist_ok=True) sample_material = Path('db/sample_material.pdf') for material in materials: stem = Path(str(uuid.uuid4()) + 'sample_material.pdf') path = upload_dir / stem copyfile(sample_material, path) db.insert_single( 'material_attachments', [material[0], str(stem)], ['material', 'path'] )
def delete_material(): data = json.loads(request.data) material_id = data['materialId'] db.connect() material_path = db.select_columns('material_attachments', ['path'], ['material'], [material_id]) if material_path: file_upload = FileUpload(filename=material_path[0][0]) file_upload.remove_file() db.delete_rows('materials', ['id'], [material_id]) db.delete_rows('material_attachments', ['material'], [material_id]) db.close() return jsonify({'status': 'ok', "message": "Material deleted"})