diff options
Diffstat (limited to 'app/modules')
-rw-r--r-- | app/modules/__init__.py | 4 | ||||
-rw-r--r-- | app/modules/auth/forms.py | 34 | ||||
-rw-r--r-- | app/modules/auth/routes.py | 73 | ||||
-rw-r--r-- | app/modules/common.py | 75 |
4 files changed, 186 insertions, 0 deletions
diff --git a/app/modules/__init__.py b/app/modules/__init__.py new file mode 100644 index 0000000..fcd1d43 --- /dev/null +++ b/app/modules/__init__.py @@ -0,0 +1,4 @@ +# -*- mode: python; -*- + +from .common import common +from .auth.routes import auth diff --git a/app/modules/auth/forms.py b/app/modules/auth/forms.py new file mode 100644 index 0000000..a4b4555 --- /dev/null +++ b/app/modules/auth/forms.py @@ -0,0 +1,34 @@ +# -*- mode: python; -*- + + +from flask_wtf import FlaskForm +from wtforms import ( + SubmitField, + HiddenField, + StringField, + PasswordField, + BooleanField, +) +from wtforms.validators import ( + InputRequired, + Length, + ValidationError, +) + + +class LoginForm(FlaskForm): + username = StringField("Username", validators=[InputRequired()]) + password = PasswordField("Password", validators=[InputRequired()]) + remember = BooleanField("Remember") + submit = SubmitField("Login") + + +class RegisterForm(LoginForm): + def validate_invite_code(self, field): + if field.data != "mdltesters2022": + raise ValidationError("Invitation code does not match") + + invitation_code = StringField("Invitation code", validators=[InputRequired()]) + name_first = StringField("First name", validators=[InputRequired()]) + name_last = StringField("Last name", validators=[InputRequired()]) + submit = SubmitField("Register") diff --git a/app/modules/auth/routes.py b/app/modules/auth/routes.py new file mode 100644 index 0000000..db59bf1 --- /dev/null +++ b/app/modules/auth/routes.py @@ -0,0 +1,73 @@ +# -*- mode: python; -*- + +from flask import Blueprint, render_template, redirect, url_for, request, flash +from flask_login import login_user, login_required, logout_user +from werkzeug.security import generate_password_hash, check_password_hash + +from ... import db +from ...models import User +from .forms import LoginForm, RegisterForm + + +auth = Blueprint("auth", __name__) + + +@auth.route("/login", methods=["GET", "POST"]) +def login(): + form = LoginForm() + if form.validate_on_submit(): + req = request.form + # print(req["remember"]) + remember = True if req.get("remember") else False + user = User.query.filter_by(username=req["username"]).first() + if user is None: + flash("User not registered.", "error") + return redirect(url_for("auth.register")) + if check_password_hash(user.hashed_password, req["password"]) is False: + flash("Wrong password.", "error") + return redirect(url_for("auth.login")) + login_user(user, remember=remember) + flash( + f"Logged in as user {user.username} successfully. " + + f"You will{' not ' if remember is False else ' '}be remembered next time!" + ) + return redirect(url_for("main.home")) + return render_template("modules/login.html", form=form) + + +@auth.route("/register", methods=["GET", "POST"]) +def register(): + form = RegisterForm() + if form.validate_on_submit(): + req = request.form + user_already_exists = User.query.filter_by( + name_first=req["name_first"], + name_last=req["name_last"], + ).first() + if user_already_exists: + flash( + f"User {req['name_first']} {req['name_last']} already exists.", "error" + ) + return redirect(url_for("auth.login")) + if req["invitation_code"] != "mdltesters2022": + flash("Wrong invitation code.", "error") + return redirect(url_for("auth.register")) + new_user = User( + username=req["username"], + hashed_password=generate_password_hash(req["password"], method="sha256"), + name_first=req["name_first"], + name_last=req["name_last"], + ) + db.session.add(new_user) + db.session.commit() + flash(f"Created user {req['name_first']} {req['name_last']} successfully.") + return redirect(url_for("main.home")) + return render_template("modules/register.html", form=form) + + +@auth.route("/logout") +@login_required +def logout(): + logout_user() + flash(f"Logged out successfully.") + return redirect(url_for("main.home")) diff --git a/app/modules/common.py b/app/modules/common.py new file mode 100644 index 0000000..1250878 --- /dev/null +++ b/app/modules/common.py @@ -0,0 +1,75 @@ +# -*- mode: python; -*- + +import inspect +from flask import Blueprint, request, render_template, redirect, flash, jsonify +from flask_login import login_required, current_user + +from .. import db +from .. import models +# from . import forms + +from wtforms import SelectField + + +common = Blueprint("common", __name__) + + +@common.route("/modules/<module>/add/<table>", methods=["GET", "POST"]) +@login_required +def add_item(module, table): + """Add new item to table accessible via module.""" + # print("db table keys are", db.metadata.tables.keys()) + if table not in db.metadata.tables.keys(): + return render_template("errors/item-not-found.html", table=table) + form = getattr(forms, f"Add{table}")() + if form.validate_on_submit(): + model = getattr(models, table) + table_fields = inspect.signature(model).parameters + form_values = {key: request.form.get(key) for key in table_fields} + print(f"Ready to insert in {table} from {module} {form_values}") + record = model(**form_values) + db.session.add(record) + db.session.commit() + item_pk = model.query.order_by(model.primary_key.desc()).first().primary_key + flash(f"Successfully added item #{item_pk} to {table} table.", "info") + return redirect(f"/modules/{module}") + return render_template("modules/add-item.html", table=table, form=form) + + +@common.route("/modules/<module>/edit/<table>/<int:pk>", methods=["GET", "POST"]) +@login_required +def edit_item(module, table, pk): + """Edit existing item in table accessible via module.""" + if table not in db.metadata.tables.keys(): + return render_template("errors/item-not-found.html", table=table) + model = getattr(models, table) + item = model.query.filter_by(primary_key=pk).first() + # Instantiate form with selected item's field values. + form = getattr(forms, f"Add{table}")(**item.__dict__) + if form.validate_on_submit(): + table_fields = inspect.signature(model).parameters + form_values = {key: request.form.get(key) for key in table_fields} + print(f"Ready to update {form_values}") + model.query.filter_by(primary_key=pk).update(form_values) + db.session.commit() + flash(f"Successfully edited item #{pk} in {table} table.", "info") + return redirect(f"/modules/{module}") + return render_template("modules/edit-item.html", table=table, pk=pk, form=form) + + +@common.route("/modules/<module>/delete/<table>/<int:pk>", methods=["POST"]) +@login_required +def delete_item(module, table, pk): + """Delete item with Primary Key = pk from table in module.""" + model = getattr(models, table) + record = model.query.filter_by(primary_key=pk).first() + db.session.delete(record) + db.session.commit() + flash(f"Successfully removed item #{pk} from {table} table.", "info") + return redirect(f"/modules/{module}") + + +@common.route("/modules/settings") +@login_required +def settings(): + return render_template("modules/settings.html", user=current_user) |