diff --git a/benchmark/scripts/flask_app/app.db b/benchmark/scripts/flask_app/app.db new file mode 100644 index 0000000..b705552 Binary files /dev/null and b/benchmark/scripts/flask_app/app.db differ diff --git a/benchmark/scripts/flask_app/app.py b/benchmark/scripts/flask_app/app.py index b4bd78d..41957c3 100644 --- a/benchmark/scripts/flask_app/app.py +++ b/benchmark/scripts/flask_app/app.py @@ -15,17 +15,24 @@ login_manager = LoginManager() @login_manager.user_loader def load_user(user_id): - return User.get(int(user_id)) + return User.query.get(int(user_id)) + + +def make_shell_context(): + return {"db": db, "User": User} def create_app(): - # db.create_all() app = Flask(__name__) bootstrap.init_app(app) # app.register_blueprint(results) app.config.from_object(Config) + db.init_app(app) login_manager.init_app(app) - login_manager.login_view = "login" + login_manager.login_view = "main.login" app.jinja_env.auto_reload = True app.register_blueprint(main) + app.shell_context_processor(make_shell_context) + with app.app_context(): + db.create_all() return app diff --git a/benchmark/scripts/flask_app/config.py b/benchmark/scripts/flask_app/config.py index ca4092b..298c10d 100644 --- a/benchmark/scripts/flask_app/config.py +++ b/benchmark/scripts/flask_app/config.py @@ -10,3 +10,8 @@ class Config(object): FRAMEWORK = os.environ.get("FRAMEWORK") or FRAMEWORKS[0] OUTPUT = os.environ.get("OUTPUT") or "local" # local or docker TEMPLATES_AUTO_RELOAD = True + SECRET_KEY = os.environ.get("SECRET_KEY") or "really-hard-to-guess-key" + SQLALCHEMY_DATABASE_URI = os.environ.get( + "DATABASE_URL" + ) or "sqlite:///" + os.path.join(basedir, "app.db") + SQLALCHEMY_TRACK_MODIFICATIONS = False diff --git a/benchmark/scripts/flask_app/forms.py b/benchmark/scripts/flask_app/forms.py new file mode 100644 index 0000000..93fc6a9 --- /dev/null +++ b/benchmark/scripts/flask_app/forms.py @@ -0,0 +1,22 @@ +from flask_wtf import FlaskForm +from wtforms import ( + StringField, + PasswordField, + BooleanField, + SubmitField, +) +from wtforms.validators import ( + DataRequired, + Length, +) + + +class LoginForm(FlaskForm): + username = StringField( + "Username", validators=[DataRequired(), Length(1, 20)] + ) + password = PasswordField( + "Password", validators=[DataRequired(), Length(4, 150)] + ) + remember_me = BooleanField("Remember me") + submit = SubmitField() diff --git a/benchmark/scripts/flask_app/main.py b/benchmark/scripts/flask_app/main.py index 041c63a..700f1d6 100644 --- a/benchmark/scripts/flask_app/main.py +++ b/benchmark/scripts/flask_app/main.py @@ -1,7 +1,20 @@ import os -from flask import Blueprint, current_app, render_template, url_for +from flask import ( + Blueprint, + current_app, + render_template, + url_for, + flash, + redirect, + request, + abort, +) +from flask_login import login_user, current_user, logout_user, login_required +from werkzeug.urls import url_parse from benchmark.Utils import Files, Folders +from .forms import LoginForm from benchmark.ResultsBase import StubReport +from .models import User main = Blueprint("main", __name__) @@ -34,20 +47,43 @@ def index(): @main.route("/results") +@login_required def results(): - pass + return render_template("results.html") @main.route("/datasets") +@login_required def datasets(): pass @main.route("/config") +@login_required def config(): pass -@main.route("/login") +@main.route("/login", methods=["GET", "POST"]) def login(): - return render_template("login.html") + if current_user.is_authenticated: + return redirect(url_for("main.index")) + form = LoginForm() + if form.validate_on_submit(): + user = User.query.filter_by(username=form.username.data).first() + if user is None or not user.check_password(form.password.data): + flash("Invalid username or password") + return redirect(url_for("main.login")) + login_user(user, remember=form.remember_me.data) + flash("Logged in successfully.") + next_page = request.args.get("next") + if not next_page or url_parse(next_page).netloc != "": + next_page = url_for("main.index") + return redirect(next_page) + return render_template("login.html", title="Sign In", form=form) + + +@main.route("/logout") +def logout(): + logout_user() + return redirect(url_for("main.index")) diff --git a/benchmark/scripts/flask_app/models.py b/benchmark/scripts/flask_app/models.py index 7650128..fe76b96 100644 --- a/benchmark/scripts/flask_app/models.py +++ b/benchmark/scripts/flask_app/models.py @@ -1,6 +1,8 @@ +from hashlib import md5 from flask_sqlalchemy import SQLAlchemy from sqlalchemy import Column, Integer, String from flask_login import UserMixin +from werkzeug.security import generate_password_hash, check_password_hash db = SQLAlchemy() @@ -8,7 +10,20 @@ db = SQLAlchemy() class User(UserMixin, db.Model): id = Column(Integer, primary_key=True) username = Column(String(64), index=True, unique=True) + email = Column(String(120), index=True, unique=True) password_hash = Column(String(128)) def __repr__(self): - return "".format(self.username) + return "".format(self.username, self.email) + + def set_password(self, password): + self.password_hash = generate_password_hash(password) + + def check_password(self, password): + return check_password_hash(self.password_hash, password) + + def avatar(self, size): + digest = md5(self.email.lower().encode("utf-8")).hexdigest() + return "https://www.gravatar.com/avatar/{}?d=identicon&s={}".format( + digest, size + ) diff --git a/benchmark/scripts/flask_app/templates/base.html b/benchmark/scripts/flask_app/templates/base.html index 5ec9ff3..af81b88 100644 --- a/benchmark/scripts/flask_app/templates/base.html +++ b/benchmark/scripts/flask_app/templates/base.html @@ -5,13 +5,20 @@ - {% block styles %} - - {{ bootstrap.load_css() }} - {% endblock %} + {% block styles %}{{ bootstrap.load_css() }}{% endblock %} Benchmark {% endblock %} - {% include "_nav.html" %} + + {% include "_nav.html" %} + {% with messages = get_flashed_messages() %} + {% if messages %} + {% for message in messages %}{% endfor %} + {% endif %} + {% endwith %} +
+ {% block content %}{% endblock %} +
+ {% block jscript %}{{ bootstrap.load_js() }}{% endblock %} diff --git a/benchmark/scripts/flask_app/templates/login.html b/benchmark/scripts/flask_app/templates/login.html new file mode 100644 index 0000000..00b45f3 --- /dev/null +++ b/benchmark/scripts/flask_app/templates/login.html @@ -0,0 +1,6 @@ +{% extends 'base.html' %} +{% from 'bootstrap5/form.html' import render_form %} +{% block content %} +

Login

+ {{ render_form(form) }} +{% endblock content %} diff --git a/benchmark/scripts/flask_app/templates/results.html b/benchmark/scripts/flask_app/templates/results.html new file mode 100644 index 0000000..2be1d76 --- /dev/null +++ b/benchmark/scripts/flask_app/templates/results.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} +{% block content %} +

Home

+

Welcome to the home page!

+{% endblock content %}