diff --git a/app/models/user.py b/app/models/user.py index fd813cc96e0cff9220df2ced7d4a74f8e9eb5446..87cbab53df75a03970cadf413df04cbcc6529fa4 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -29,9 +29,9 @@ class User(UserMixin, db.Model): @classmethod def search_user_by_email(cls, user_email): - user_exist = cls.query.filter_by(email=user_email).first() + email_exist = cls.query.filter_by(email=user_email).first() - return user_exist + return email_exist @classmethod def search_user_by_username(cls, user_name): diff --git a/app/profile/routes.py b/app/profile/routes.py index 223415e105122a98c50398e40f94ea4469449dec..998e407edf045b5174f8ae090d051249134eca77 100644 --- a/app/profile/routes.py +++ b/app/profile/routes.py @@ -51,7 +51,7 @@ def login_post(): if not user or not check_password_hash(user.password, password): flash('Please check your login details and try again.') - return redirect(url_for('profile.login')) + return redirect(url_for('profile.login', error=True)) login_user(user, remember=remember) return redirect(url_for('profile.index')) @@ -94,7 +94,41 @@ def logout(): def login(): if current_user.is_authenticated: return redirect(url_for('profile.index')) - return render_template('profile/login.html') + #Check if login is being sent due to error + error = request.args.get('error') + return render_template('profile/login.html', error=error) + +@bp.route('/password-reset') +def password_reset(): + return render_template('profile/password-reset.html') + +@bp.route('/password-reset', methods=['POST']) +def check_password_reset_1(): + username = request.form.get('username') + email = request.form.get('email') + + #Search to see if username already exists + user_exist = User.search_user_by_username(username) + if user_exist is None: + return flash('Username does not exist') + + email_exist = User.search_user_by_email(email) + if email_exist is None: + return flash('Email does not exist') + + return redirect(url_for('profile.password_reset_2')) + +@bp.route('/password-reset/2FA') +def password_reset_2(): + return render_template('profile/password-reset-2.html') + +@bp.route('/password-reset/2FA', methods=['POST']) +def check_password_reset_2(): + code = request.form.get('2fa-code') + + #Simulate 2FA code being entered + if code == '123456': + pass @login_required @bp.route('/home') diff --git a/app/static/base.css b/app/static/base.css index b19ba9383e24e6bd0875b5971ab4384681074ce2..ad5304833e0fff23bab8004d0638a722f3992c8f 100644 --- a/app/static/base.css +++ b/app/static/base.css @@ -123,6 +123,11 @@ Form styling options text-align: center; } +.clear-hyperlink { + color: inherit; + text-decoration: none; +} + /* HEX codes for colours used through out website don't delete */ /* Colour pallete taken from https://visme.co/blog/website-color-schemes/ diff --git a/app/templates/profile/login.html b/app/templates/profile/login.html index 0f6d9a0b9e706e896ba870ad359b8fe635ec8746..7bc4f19dac973da44d94359eca0886fceec32234 100644 --- a/app/templates/profile/login.html +++ b/app/templates/profile/login.html @@ -1,23 +1,29 @@ {% extends 'base.html' %} {% block content %} <div class="column is-4 is-offset-4"> + +{% if get_flashed_messages() %} +<div class="alert alert-danger" role="alert"> + Invalid username/email and or password. Please try again or + <a href="{{ url_for('profile.password_reset') }}">reset your password here</a>. +</div> +{% endif %} <div id="login-box" class="form_box_30" style="margin-top: 30px;"> <div class="profile_form_background"> <h2 class="form_header">Login</h2> <form method="POST" action="{{ url_for('profile.login_post') }}"> - {{ csrf_token() }} + <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <div class="mb-3"> - <label class="form-label" autofocus="">Username</label> + <label class="form-label" autofocus="">Username/Email</label> <input type="text" class="form-control" name="username"> </div> - <div class="mb-3"> - <label class="form-label">Email address</label> - <input type="email" class="form-control" name="email"> - </div> <div class="mb-3"> <label for="exampleInputPassword1" class="form-label">Password</label> <input type="password" class="form-control" name="password"> </div> + <div class="mb-3"> + <a class="clear-hyperlink" href="{{ url_for('profile.login_post') }}">Forgot Password?</a> + </div> <div class="mb-3 form-check"> <input type="checkbox" class="form-check-input" id="remember" name="remember"> <label class="form-check-label" for="remember">Remember me</label> diff --git a/app/templates/profile/password-reset-2.html b/app/templates/profile/password-reset-2.html new file mode 100644 index 0000000000000000000000000000000000000000..b2e8a1bbc9b24ca1a436f97717800bbc7dc965df --- /dev/null +++ b/app/templates/profile/password-reset-2.html @@ -0,0 +1,22 @@ +{% extends 'base.html' %} + +{% block content %} +<div class="form_box_30 background_1"> + {% if get_flashed_messages() %} + <div class="alert alert-danger" role="alert"> + get_flashed_messages() + </div> + {% endif %} + <div class="profile_form_background"> + <h3 class="form_header">2FA Code</h3> + <form method="POST" action="{{ url_for('profile.check_password_reset_2') }}"> + <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> + <div class="mb-3"> + <label class="form-label" for="2fa-code" autofocus="">Enter 2FA Code</label> + <input type="text" id="2fa-code" class="form-control" name="2fa-code" required> + </div> + <button type="submit" class="btn btn-primary">Submit 2FA</button> + </form> + </div> +</div> +{% endblock %} diff --git a/app/templates/profile/password-reset.html b/app/templates/profile/password-reset.html new file mode 100644 index 0000000000000000000000000000000000000000..589fd050adbaee7eb676d5b38a6b3a275eee5c0d --- /dev/null +++ b/app/templates/profile/password-reset.html @@ -0,0 +1,28 @@ +{% extends 'base.html' %} + +{% block content %} +<div class="form_box_30 background_1"> + {% if get_flashed_messages() %} + <div class="alert alert-danger" role="alert"> + get_flashed_messages() + </div> + {% endif %} + <div class="profile_form_background"> + <h3 class="form_header">Password Reset</h3> + <form method="POST" action="{{ url_for('profile.check_password_reset_1') }}"> + <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> + <div class="mb-3"> + <label class="form-label" for="username" autofocus="">Username</label> + <input type="text" id="username" class="form-control" name="username" required> + <small id="username-feedback" class="form-text"></small> + </div> + <div class="mb-3"> + <label class="form-label" for="email">Email address</label> + <input type="email" id="email" class="form-control" name="email" required> + <small id="email-feedback" class="form-text"></small> + </div> + <button type="submit" class="btn btn-primary">Reset Password</button> + </form> + </div> +</div> +{% endblock %}