def comment_new(id): post = Post.get_by_id(id) if post is None or post.is_hidden: abort(404) form = CommentForm() if form.is_submitted(): try: if not form.validate(): raise Exception(_('ERROR_INVALID_SUBMISSION')) comment = Comment(user=current_user, post=post) form.populate_obj(comment) comment.save() flash(_('COMMENT_SAVE_SUCESS')) if comment.parent_comment: send_email('reply_comment', comment) else: send_email('comment', post, comment) return redirect(url_for('stamp.show', id=post.id, _anchor='comment-%s' % comment.id)) except Exception as e: flash(e.message, 'error') return render_template('main/stamp/show.html', post=post, form=form)
def comment_new(id): post = Post.get_by_id(id) if post is None or post.is_hidden: abort(404) form = CommentForm() if form.is_submitted(): try: if not form.validate(): raise Exception(_('ERROR_INVALID_SUBMISSION')) comment = Comment(user=current_user, post=post) form.populate_obj(comment) comment.save() flash(_('COMMENT_SAVE_SUCESS')) if comment.parent_comment: send_email('reply_comment', comment) else: send_email('comment', post, comment) return redirect( url_for('stamp.show', id=post.id, _anchor='comment-%s' % comment.id)) except Exception as e: flash(e.message, 'error') return render_template('main/stamp/show.html', post=post, form=form)
def password_reset_request(): form = PasswordResetRequestForm() if form.validate_on_submit(): def accept(t): return PasswordResetRequest.query.filter_by(token=t).first() is None token = random_base64(accept) reset_link = url_for('auth.password_reset', _external=True, token=token) try: send_email( subject="Reset your Asset Tracker Password", sender=form.email.data, recipients=[form.email.data], body="Asset Tracker password reset link: %s\r\n\r\n\ This link will expire in 24 hours" % reset_link, html="Asset Tracker password reset link:<br> <a href=\"%s\">\ %s</a> <br><br>This link will expire in 24 hours" % (reset_link, reset_link) ) entry = PasswordResetRequest( token, User.query.filter_by(email=form.email.data).first() ) db.session.add(entry) db.session.commit() flash("A link to reset your password has been sent to %s" % form.email.data, "success") except Exception, e: if current_app.config.get('DEBUG'): raise e else: flash("Failed to send invite due to a %s error" % e.__class__.__name__, 'danger')
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 signup(): if current_user.is_authenticated: return render_view(url_for('dashboard'), redirect=True, message=_('SESSIONS_MSG_ALREADY_SIGNED_IN')) redirect_to = session.pop('redirect_to', None) if request.values.get('ret'): redirect_to = request.values.get('ret') form = SignUpForm(ret=redirect_to) if form.is_submitted(): try: if not form.validate(): raise Exception(_('ERROR_INVALID_SUBMISSION')) if not verify_captcha(): raise Exception(_('SESSIONS_ERROR_UNFINISHED_CHALLENGE_LBL')) # Create user from the form user = User.create() form.populate_obj(user) user.set_password(form.password.data) user.last_seen = datetime.datetime.utcnow() user.last_login = datetime.datetime.utcnow() # store the user user.save() # Login User login_user(user) redirect_to = form.back_link.data if not redirect_to: redirect_to = url_for('dashboard') # send registration email send_email('registration', user) return render_view(redirect_to, redirect=True, message=_('SESSIONS_MSG_SIGNUP_COMPLETED')) except Exception as e: flash(e.message, 'error') return render_view('admin/sessions/signup.html', form=form)
def invite_user(): form = InviteForm() # users can only add users one privilege level below them form.role.choices = [(role.id, role.title) for role in Role.query.all() if role.level > current_user.roles[0].level] if form.validate_on_submit(): # the method is POST and the form is valid token = random_base64(lambda t: Invitation.get(t) is None) invitation = Invitation( token, form.email.data, Role.get_by_id(form.role.data), current_user ) # invite_link: http://<host>/signup?invite=<token> invite_link = url_for('auth.signup', _external=True, invite=token) # prepare and send invitation email try: send_email( subject="Asset Tracker Invitation", sender=(current_user.name, current_user.email), recipients=[form.email.data], body="You've been invited to join Asset Tracker. Follow \ this link to sign up: %s" % invite_link, html="You've been invited to join Asset Tracker. Follow \ this link to sign up:<br> <a href=\"%s\">%s</a>" % \ (invite_link, invite_link) ) db.session.add(invitation) db.session.commit() flash("Invitation sent to %s" % form.email.data, 'success') except Exception, e: if current_app.config.get('DEBUG'): raise e else: flash("Failed to send invite due to a %s error" % e.__class__.__name__, 'danger') return render_template('auth/invite.html', form=form) return redirect(url_for('index'))
def reset_request(): try: fields = ['email_reset'] email = get_fields(request.form, fields) email = email[0] except ValueError as e: return e.args[0] if not re.match(config.EMAIL_FORMAT, email): return error(f'Invalid email format!<br>{config.EMAIL_FORMAT_ERROR}') db.connect() res = db.select_columns('users', ['name', 'id'], ['email'], [email]) if len(res) == 0: db.close() return jsonify({'status': 'ok'}) reset_id = str(uuid.uuid1()) db.update_rows('users', [reset_id], ['reset_code'], ['id'], [res[0][1]]) reset_link = url_for('.reset', user=res[0][1], resetID=reset_id, _external=True) send_email( to=email, name=res[0][0], subject='Reset Password', messages=[ 'You have submitted a request ' + 'to reset your password on TMS.', f'Your account is {email}.', f'Click <a href="{reset_link}">here</a>' + ' to reset your password.' ]) db.close() return jsonify({'status': 'ok'})
def forgot_password(): if current_user.is_authenticated: return render_view(url_for('latest'), redirect=True, message=_('SESSIONS_MSG_ALREADY_SIGNED_IN')) form = ForgotPasswordForm() if form.is_submitted(): try: if not form.validate(): raise Exception(_('ERROR_INVALID_SUBMISSION')) if not verify_captcha(): raise Exception(_('SESSIONS_ERROR_UNFINISHED_CHALLENGE_LBL')) email = form.email.data user = User.find_by_email(email) if not user: raise Exception(_('SESSIONS_ERROR_MAIL_NOT_FOUND', email=email)) user.generate_reset_password() flash(_('SESSIONS_PASSWORD_RESET', email=email)) # send reset password email send_email('reset_password', user) return render_view(url_for('sessions.forgot_password'), redirect=True) except Exception as e: flash(e.message, 'error') return render_view('admin/sessions/forgot_password.html', form=form)
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 mark_task(): if request.method == 'GET': task_id = request.args.get('task', None, type=int) student_id = request.args.get('student', None, type=int) if task_id is None or student_id is None: abort(400) db.connect() if session['id'] not in get_students_staff(student_id): db.close() abort(403) task = build_task(task_id) if not task: db.close() abort(404) res = db.select_columns('users', ['name', 'email'], ['id'], [student_id]) if not res: db.close() abort(404) student = {'id': student_id, 'name': res[0][0], 'email': res[0][1]} task_criteria = db.select_columns('task_criteria', ['id', 'task', 'name', 'max_mark'], ['task'], [task_id]) submission = build_student_submission(student_id, task_id) marked_feedback = [] for criteria in task_criteria: marked_feedback.append( db.select_columns('marks', ['mark', 'feedback'], ['criteria', 'student', 'marker'], [criteria[0], student_id, session['id']])) task_criteria_id = [] for criteria in task_criteria: task_criteria_id.append(criteria[0]) task_max = [] for criteria in task_criteria: task_max.append(criteria[3]) check_if_assessor = db.select_columns('student_topic', ['student'], ['assessor', 'student'], [session['id'], student_id]) is_assessor = False if check_if_assessor: is_assessor = True db.close() heading = f"{task['course_name']} - {task['name']}" return render_template('task_base.html', topic_request_text=config.TOPIC_REQUEST_TEXT, heading=heading, title=task['name'], taskCriteria=task_criteria, student=student, submission=submission, studentId=student_id, taskCriteriaId=task_criteria_id, taskMax=task_max, markedFeedback=marked_feedback, task=task, marker=True, isAssessor=is_assessor) data = json.loads(request.data) marks = data['marks'] feedback = data['feedback'] task_id = data['taskId'] student_id = data['studentId'] task_criteria = data['taskCriteria'] task_max = data['taskMax'] db.connect() if session['id'] not in get_students_staff(student_id): db.close() abort(403) try: check = data['approveCheck'] if (not check): res = db.select_columns('request_statuses', ['id'], ['name'], ['rejected']) db.update_rows('submissions', [res[0][0]], ['status'], ['student', 'task'], [student_id, task_id]) else: res = db.select_columns('request_statuses', ['id'], ['name'], ['approved']) db.update_rows('submissions', [res[0][0]], ['status'], ['student', 'task'], [student_id, task_id]) marks = [100] if feedback[0] == '': feedback = [None] except KeyError: pass for i in range(len(marks)): try: val = int(marks[i]) if val < 0 or val > 100: db.close() return error('Marks must be between 0-100') if val > task_max[i]: db.close() return error(f'Mark {val} exceeds max mark of {task_max[i]}') except ValueError: db.close() return error('Please enter an integer value for marks') for f in feedback: if f == '': db.close() return error('Please enter some feedback') for i in range(len(marks)): try: db.insert_single('marks', [ task_criteria[i], student_id, session['id'], marks[i], feedback[i] ], ['criteria', 'student', 'marker', 'mark', 'feedback']) except sqlite3.IntegrityError: db.update_rows('marks', [marks[i], feedback[i]], ['mark', 'feedback'], ['criteria', 'student', 'marker'], [task_criteria[i], student_id, session['id']]) marked_method = db.select_columns('marking_methods', ['id'], ['name'], ["requires mark"])[0][0] is_mark_type = len( db.select_columns('tasks', ['id'], ['id', 'marking_method'], [task_id, marked_method])) if is_mark_type: new_sub_status = "pending mark" if queries.is_fully_marked(student_id, task_id): new_sub_status = "marked" elif queries.is_partially_marked(student_id, task_id): new_sub_status = "partially marked" status_id = db.select_columns('request_statuses', ['id'], ['name'], [new_sub_status])[0][0] db.update_rows('submissions', [status_id], ['status'], ['student', 'task'], [student_id, task_id]) # send email student = db.select_columns('users', ['name', 'email'], ['id'], [student_id])[0] task_name = db.select_columns('tasks', ['name'], ['id'], [task_id])[0][0] marker = session['name'] subject = f'Marks Entered for Task "{task_name}"' msg1 = f'Your submission for task "{task_name}"' + \ f' has just been marked by {marker}.' view_link = url_for('.view_task', task=task_id, _external=True) msg2 = f'You can view your marks and feedback ' + \ f'<a href="{view_link}">here</a>.' send_email(to=student[1], name=student[0], subject=subject, messages=[msg1, msg2]) db.close() return jsonify({'status': 'ok'})
def register(): if request.method == 'GET': return render_template('register.html', title='Register', hide_navbar=True) try: fields = ['email', 'password', 'confirm-password'] email, password, confirm = get_fields(request.form, fields) except ValueError as e: return e.args[0] if not re.match(config.EMAIL_FORMAT, email): return error( f'Invalid email format!<br>{config.EMAIL_FORMAT_ERROR}', 'email') db.connect() res = db.select_columns('users', ['email', 'date_created', 'confirm_code'], ['email'], [email]) now = datetime.now().timestamp() if len(res): if res[0][2] != '' and res[0][1] + config.ACCOUNT_EXPIRY < now: # expire unactivated accounts every 24 hours db.delete_rows('users', ['email'], [email]) else: db.close() return error('This email has already been registered!', 'email') if len(password) < 8: msg = 'Password must be at least 8 characters long!' db.close() return error(msg, 'password') if password != confirm: db.close() return error('Passwords do not match!', 'confirm-password') hashed_pass = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) name = email.split('@')[0] # get the id for a public account acc_type = db.select_columns('account_types', ['id'], ['name'], ['public']) confirm_code = uuid.uuid1() activation_link = url_for('.confirm', user=name, confirm_code=confirm_code, _external=True) send_email(to=email, name=email, subject='Confirm Account Registration', messages=[ 'You recently registered for an account on TMS.', 'To activiate your account, click ' + f'<a href="{activation_link}">here</a>.', 'This link will expire in 24 hours.' ]) db.insert_single( 'users', [name, hashed_pass, email, acc_type[0][0], str(confirm_code), now], ['name', 'password', 'email', 'account_type', 'confirm_code', 'date_created'] ) db.close() return jsonify({'status': 'ok'})