From 1ac625ccbd305a7768533498c923c461f7528a73 Mon Sep 17 00:00:00 2001 From: Stef Date: Sat, 31 May 2025 12:05:53 +0200 Subject: [PATCH] Added login functionality and login required --- app.py | 2 +- app_seed.py | 6 + application/__init__.py | 15 +++ application/auth/forms.py | 9 ++ application/auth/models.py | 19 +++ application/auth/templates/login.html | 85 +++++++++++++ application/auth/views.py | 43 +++++-- application/dashboard/templates/base.html | 145 ++++++++++++---------- application/dashboard/views.py | 5 +- requirements.txt | 1 + 10 files changed, 251 insertions(+), 79 deletions(-) create mode 100644 application/auth/forms.py create mode 100644 application/auth/models.py create mode 100644 application/auth/templates/login.html diff --git a/app.py b/app.py index dc8f7eb..2cd25f2 100644 --- a/app.py +++ b/app.py @@ -12,7 +12,7 @@ app.register_blueprint(dash_blueprint, url_prefix="/dash") # Default app route @app.route("/") def home(): - return redirect(url_for("auth.demo")) + return redirect(url_for("auth.login")) if __name__ == "__main__": diff --git a/app_seed.py b/app_seed.py index 949f954..55c4587 100644 --- a/app_seed.py +++ b/app_seed.py @@ -1,5 +1,6 @@ from application import db, app from application.dashboard.models import AllowedPlate, LoggedItem, datetime +from application.auth.models import User with app.app_context(): AllowedPlate.query.delete() @@ -11,3 +12,8 @@ with app.app_context(): db.session.add(LoggedItem("MUN389", datetime.now(), True)) db.session.add(LoggedItem("MUN389", datetime.now(), False)) db.session.commit() + +with app.app_context(): + User.query.delete() + db.session.add(User(username="admin", password="admin")) + db.session.commit() diff --git a/application/__init__.py b/application/__init__.py index 3b41ab7..7f6faba 100644 --- a/application/__init__.py +++ b/application/__init__.py @@ -1,6 +1,7 @@ from flask import Flask from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy +from flask_login import LoginManager # from authlib.integrations.flask_client import OAuth @@ -16,6 +17,20 @@ db = SQLAlchemy(app) migrate = Migrate(app, db) +# Login manager +from application.auth.models import User + +login_manager = LoginManager() +login_manager.init_app(app) # type: ignore +login_manager.login_view = "auth.login" # type: ignore + + +# Gets all the user data +@login_manager.user_loader # type: ignore +def load_user(user_id): # type: ignore + return User.query.get(int(user_id)) # type: ignore + + # Keycloak """ oauth = OAuth(app=app) diff --git a/application/auth/forms.py b/application/auth/forms.py new file mode 100644 index 0000000..c3f022e --- /dev/null +++ b/application/auth/forms.py @@ -0,0 +1,9 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, PasswordField +from wtforms.validators import DataRequired + + +class login_form(FlaskForm): + username = StringField("Username", validators=[DataRequired()]) + password = PasswordField("Password", validators=[DataRequired()]) + submit = SubmitField(label="Sign in") diff --git a/application/auth/models.py b/application/auth/models.py new file mode 100644 index 0000000..49f45f8 --- /dev/null +++ b/application/auth/models.py @@ -0,0 +1,19 @@ +from application import db +from flask_login import UserMixin +from werkzeug.security import generate_password_hash, check_password_hash + + +# User model +class User(db.Model, UserMixin): + __tablename__ = "user" + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(150), unique=True, nullable=False) + password = db.Column(db.String, nullable=False) + + # Initialize user, prevents red stuff + def __init__(self, username: str, password: str, is_admin: bool = False): + self.username = username + self.password = generate_password_hash(password) + + def check_password(self, password: str): + return check_password_hash(self.password, password=password) diff --git a/application/auth/templates/login.html b/application/auth/templates/login.html new file mode 100644 index 0000000..1f6f76f --- /dev/null +++ b/application/auth/templates/login.html @@ -0,0 +1,85 @@ + + + + + + + + Login + + + + +
+
+ +
+
+
+
+
+ {{form.hidden_tag()}} +
+ + {{form.username(class="form-control rounded-input")}} + + {{form.password(class="form-control rounded-input")}} +
+
+ {{form.submit(class="btn btn-dark rounded-input px-4 mx-auto w-50")}} +
+
+
+
+
+
+ Moving Image +
+ + + + \ No newline at end of file diff --git a/application/auth/views.py b/application/auth/views.py index e85c31d..8c34db8 100644 --- a/application/auth/views.py +++ b/application/auth/views.py @@ -1,23 +1,46 @@ -from flask import Blueprint, session, redirect, url_for, render_template +from flask import Blueprint, redirect, url_for, render_template +from application.auth.forms import login_form +from application.auth.models import User +from flask_login import login_user, login_required, logout_user # from application import keycloak auth_blueprint = Blueprint("auth", __name__, template_folder="templates") -@auth_blueprint.route("/demo") -def demo(): - return render_template("login.html") +# Login as user or admin +@auth_blueprint.route("/login", methods=["GET", "POST"]) +def login(): + loginForm = login_form() + if loginForm.validate_on_submit(): + print("Test2") + username = loginForm.username.data + password = loginForm.password.data + user = User.query.filter_by(username=username).first() + + if user and user.check_password(password=password): + login_user(user) + return redirect(url_for("dash.dashboard")) + return render_template("login.html", form=loginForm) -@auth_blueprint.route("/") -def home(): - user = session.get("user") - if user: - return f'Hello, {user["name"]}' - return redirect(url_for("auth.login")) +@auth_blueprint.route("/logout") +@login_required +def logout(): + logout_user() + return redirect("/") +""" +# Logout +@auth_blueprint.route("/logout") +@login_required +def logout(): + logout_user() + flash("Logged out succesfully") + return redirect(url_for("index")) +""" + """ @auth_blueprint.route("/login") def login(): diff --git a/application/dashboard/templates/base.html b/application/dashboard/templates/base.html index 7c79ea0..b03419c 100644 --- a/application/dashboard/templates/base.html +++ b/application/dashboard/templates/base.html @@ -1,5 +1,6 @@ + @@ -7,57 +8,65 @@ Admin Dashboard + .dark-mode .card, + .dark-mode .table { + background-color: #23272b !important; + color: #e0e0e0 !important; + } + + .dark-mode .table thead, + .dark-mode .table tbody, + .dark-mode .table th, + .dark-mode .table td, + .dark-mode .table tr { + background-color: #23272b !important; + color: #e0e0e0 !important; + border-color: #444 !important; + } + + .dark-mode .card-title, + .dark-mode .display-4, + .dark-mode h5 { + color: #e0e0e0 !important; + } + + .dark-mode input { + background-color: #23272b !important; + color: #e0e0e0 !important; + border: 1px solid #444 !important; + } + + .dark-mode .btn { + background-color: #444 !important; + color: #e0e0e0 !important; + border-color: #666 !important; + } + + .dark-mode .btn:hover { + background-color: #222 !important; + color: #fff !important; + } + + .dark-mode .logout-btn { + background-color: #212529 !important; + color: #fff !important; + border-color: #212529 !important; + } + + .dark-mode .logout-btn:hover { + background-color: #353738 !important; + color: #fff !important; + } + +
@@ -65,7 +74,8 @@ body.dark-mode {
- Logout -
- {%block content%} + {%block content%} - {% endblock %} -
+ {% endblock %} + + if (localStorage.getItem('darkMode') === 'enabled') { + document.body.classList.add('dark-mode'); + } + - + + \ No newline at end of file diff --git a/application/dashboard/views.py b/application/dashboard/views.py index 1fa0ce3..4e37936 100644 --- a/application/dashboard/views.py +++ b/application/dashboard/views.py @@ -2,12 +2,13 @@ from flask import Blueprint, render_template, request, jsonify from application.dashboard.models import AllowedPlate, LoggedItem from application import db from application.dashboard.forms import npForm +from flask_login import login_required dash_blueprint = Blueprint("dash", __name__, template_folder="templates") @dash_blueprint.route("/dashboard") -# @login_required +@login_required def dashboard(): Plates = AllowedPlate.query.all() logs = ( @@ -17,7 +18,7 @@ def dashboard(): @dash_blueprint.route("/add", methods=["GET", "POST"]) -# @login_required +@login_required def add(): Plates = AllowedPlate.query.all() form = npForm() diff --git a/requirements.txt b/requirements.txt index f01eb24..4090e27 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ blinker==1.9.0 click==8.2.1 colorama==0.4.6 Flask==3.1.1 +Flask-Login==0.6.3 Flask-Migrate==4.1.0 Flask-SQLAlchemy==3.1.1 Flask-WTF==1.2.2