From 05ffc692e0d4783cb7aaaeb7751046aae077e863 Mon Sep 17 00:00:00 2001 From: "Ethan Clay (UWE)" <ethan2.clay@live.uwe.ac.uk> Date: Tue, 10 Dec 2024 11:05:11 +0000 Subject: [PATCH] Begin to work on authentication for users --- app/__init__.py | 39 ++++++++++++++++++---------- app/auth/__init__.py | 5 ++++ app/auth/routes.py | 44 ++++++++++++++++++++++++++++++++ app/models/user.py | 6 ++--- app/profile/routes.py | 20 ++++++++++----- app/templates/profile/index.html | 3 ++- 6 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 app/auth/__init__.py create mode 100644 app/auth/routes.py diff --git a/app/__init__.py b/app/__init__.py index df1d438..a8bae28 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,11 +4,13 @@ from flask import Flask from config import Config from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate +from flask_login import LoginManager from dotenv import load_dotenv import os db = SQLAlchemy() migrate = Migrate() +login_manager = LoginManager() def create_app(config_class=Config): app = Flask(__name__) @@ -36,22 +38,31 @@ def create_app(config_class=Config): migrate.init_app(app, db) # Register blueprints and url prefixes - from app.main import bp as main_bp - app.register_blueprint(main_bp) + register_blueprints(app) - from app.bookings import bp as bookings_bp - app.register_blueprint(bookings_bp, url_prefix='/bookings') - - from app.api import bp as api_bp - app.register_blueprint(api_bp, url_prefix='/api') - - from app.admin import bp as admin_bp - app.register_blueprint(admin_bp, url_prefix='/admin') - - from app.profile import bp as profile_bp - app.register_blueprint(profile_bp, url_prefix='/profile') if __name__ == "__main__": app.run(use_reloader=True) + + login_manager.login_view = 'profile.login' + login_manager.init_app(app) + + return app + +@login_manager.user_loader +def load_user(user_id): + from .models import User + return User.query.get(int(user_id)) - return app \ No newline at end of file +def register_blueprints(app): + blueprints = [ + ('auth', None), + ('main', None), + ('bookings', '/bookings'), + ('api', '/api'), + ('admin', '/admin'), + ('profile', '/profile') + ] + for module_name, url_prefix in blueprints: + module = __import__(f'app.{module_name}', fromlist=['bp']) + app.register_blueprint(module.bp, url_prefix=url_prefix) \ No newline at end of file diff --git a/app/auth/__init__.py b/app/auth/__init__.py new file mode 100644 index 0000000..2834ca1 --- /dev/null +++ b/app/auth/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('auth', __name__) + +from app.auth import routes \ No newline at end of file diff --git a/app/auth/routes.py b/app/auth/routes.py new file mode 100644 index 0000000..fa6a1b6 --- /dev/null +++ b/app/auth/routes.py @@ -0,0 +1,44 @@ +#https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login#step-1-installing-packages +from flask import Blueprint, render_template, redirect, url_for, request +from app.auth import bp +from werkzeug.security import generate_password_hash, check_password_hash +from app.models import User +from app import db +from flask_login import login_user + +@bp.route('/signup') +def signup(): + return render_template(url_for('profile.signup')) + +@bp.route('/signup', methods=['POST']) +def signup_post(): + email = request.form.get('email') + username = request.form.get('name') + password = request.form.get('password') + + user = User.query.filter_by(email=email).first() + + if user: + return redirect(url_for('profile.signup')) + + new_user = User(username=username, email=email, password=generate_password_hash(password, method='pbkdf2:sha256'), role_id=2) # Assuming role_id is required and you have a default value or retrieve it from elsewhere + + db.session.add(new_user) + db.session.commit() + + return redirect(url_for('profile.login')) + +@bp.route('/login', methods=['POST']) +def login_post(): + email = request.form.get('email') + password = request.form.get('password') + remember = True if request.form.get('remember') else False # If checkbox for user is ticked + + user = User.query.filter_by(email=email).first() + + 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')) + + login_user(user, remember=remember) + return redirect(url_for('main.profile')) \ No newline at end of file diff --git a/app/models/user.py b/app/models/user.py index c1881bf..8431368 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -1,7 +1,8 @@ from flask import request, jsonify +from flask_login import UserMixin from app import db -class User(db.Model): +class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) @@ -17,16 +18,15 @@ class User(db.Model): new_user = cls(username=username, email=email, password=password, role_id=role_id) db.session.add(new_user) db.session.commit() + return new_user @classmethod def search_user_id(cls, user_id): return cls.query.get(user_id) - @classmethod def search_user_by_email(cls, user_email): - user_exist = cls.query.filter_by(email=user_email).first() return user_exist \ No newline at end of file diff --git a/app/profile/routes.py b/app/profile/routes.py index 2fd51c3..f827e4e 100644 --- a/app/profile/routes.py +++ b/app/profile/routes.py @@ -1,33 +1,39 @@ from flask import render_template, redirect, url_for from app.profile import bp from app.models import User +from flask_login import current_user, login_required @bp.route('/') +@login_required def index(): - return render_template('profile/index.html') + if current_user.is_authenticated: + return render_template('profile/index.html', username=current_user.username) + else: + return redirect(url_for('profile.login')) @bp.route('/login') def login(): return 'Login' -@bp.route('/signup') -def signup(): - return render_template('profile/signup.html') - @bp.route('/signup', methods=['POST']) def signup_post(): + return 'hit POST' email = request.form.get('email') name = request.form.get('name') password = request.form.get('password') if User.search_user_by_email(email): - return redirect(url_for('auth.signup')) + return redirect('signup.html') new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256')) db.session.add(new_user) db.session.commit() - return redirect(url_for('auth.login')) + return redirect('profile/login.html') + +@bp.route('/signup') +def signup(): + return render_template('profile/signup.html') @bp.route('/logout') def logout(): diff --git a/app/templates/profile/index.html b/app/templates/profile/index.html index 7da6f97..f899369 100644 --- a/app/templates/profile/index.html +++ b/app/templates/profile/index.html @@ -2,6 +2,7 @@ # Implements CSS Slider from https://swiffyslider.com/docs/ {% block content %} <div> - <p>Welcome logged in!</p> + <p>Welcome {{username}}!</p> + </div> {% endblock %} \ No newline at end of file -- GitLab