stc

a simple time card webapp
git clone _git@git.brennen.work:stc.git
Log | Files | Refs | README

commit bc705487fa1437dfce442fff23ad8f2d9d462ade
parent a1ce6b1b72c0217a93598a4bf6365df73add2928
Author: Brennen T. Mazur <brennen@madis.cool>
Date:   Sun, 22 Jan 2023 19:21:20 -0700

layout change and some auth work. @login.user_loader not working yet.

Diffstat:
Mapp/__init__.py | 7++++---
Aapp/forms.py | 16++++++++++++++++
Mapp/models.py | 24+++++++++++++++++++++---
Mapp/routes.py | 29++++++++++++++++++++++++-----
Mapp/templates/login.html | 17++++++++++++++++-
Aconfig.py | 5+++++
6 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/app/__init__.py b/app/__init__.py @@ -1,6 +1,7 @@ -from flask import Flask, abort, redirect, request, session, jsonify +from flask import Flask +from config import Config app = Flask(__name__) +app.config.from_object(Config) -from app import routes -from app import models +from app import routes, models diff --git a/app/forms.py b/app/forms.py @@ -0,0 +1,16 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, PasswordField, BooleanField +from wtforms.validators import DataRequired + +# Login class currently assumes mongodb collection(Users) with structure +# { +# Name: [username], +# Password: [hashed_password] +# } +class Login(FlaskForm): + name = StringField('name', validators=[DataRequired()]) + password = PasswordField('Password', validators=[DataRequired()]) + remember_me = BooleanField('Remember Me') + login = SubmitField('Login') + + diff --git a/app/models.py b/app/models.py @@ -5,7 +5,6 @@ import datetime import uuid -from app import app from flask import jsonify, request, redirect, session from fastapi.encoders import jsonable_encoder #from passlib.hash import pbkdf2_sha256 # Replace with Brennen's hash when he finds it @@ -57,6 +56,25 @@ class Users: def username_alphanumeric(cls, v): assert v.isalnum(), 'Username must be alphanumeric' return v + + @staticmethod + def is_authenticated(): + return True + + @staticmethod + def is_active(): + return True + + @staticmethod + def is_anonymous(): + return False + + def get_id(self): + return self.username + + @staticmethod + def check_password(password_hash, password): + return check_password_hash(password_hash, password) class Time: @@ -85,14 +103,14 @@ class Time: _id: int # forign key - clock_in: Optional[datetime.datetime.utcnow] #System time + clock_in: Optional[datetime.datetime.utcnow] #System time Clock_out should be optional, but can clock_in? modified_by: str #link to _id of user date: Optional [datetime.date] project: str clock_out: Optional[datetime.datetime.utcnow] #System time note: str perdium: bool - total_time: int #clock_out - clock_in + total_time: int #clock_out - clock_in OR if ! clock_out utcnow - clock_in def to_json(self): return jsonable_encoder(self, exclude_none=True) diff --git a/app/routes.py b/app/routes.py @@ -1,10 +1,21 @@ import datetime - -from app import models from app import app -from flask import render_template +from flask_pymongo import PyMongo +from flask_login import LoginManager +from flask import render_template, url_for, request, flash +from app.forms import Login +from flask import request +from werkzeug.urls import url_parse +from werkzeug.security import generate_password_hash, check_password_hash +from flask_login import current_user, login_user, logout_user, login_required +from app.forms import Login + +OrganizationName = 'Youth Employment Program' # Maybe pass this as a value though the object for relevant pages??? -OrganizationName = 'Youth Employment Program' +# DB Connection & LoginManager init +mongo = PyMongo(app) +login = LoginManager(app) +login.login_view = 'login' #from models import Users, Time, Fleet, Agreement, Projects @app.route('/user/signup', methods=['GET']) @@ -20,7 +31,15 @@ def hello(): @app.route("/login") def login(): - return render_template('login.html',ORGNAME = OrganizationName) + form = Login() + return render_template('login.html',form=form,ORGNAME = OrganizationName) + +@login.user_loader +def load_user(username): + u = mongo.db.Users.find_one({"Name": username}) + if not u: + return None + return User(username=u['name']) @app.route("/dashboard") def dashboard(): diff --git a/app/templates/login.html b/app/templates/login.html @@ -5,7 +5,21 @@ {% block navigation %}<div id="nav" href="#"></div><div id="logout"></div>{% endblock %} {% block content %} - <section class="login-grid"> + <form action="" method="post" novalidate> + {{ form.hidden_tag() }} + <p> + {{ form.username.label }}<br> + {{ form.username(size=32) }} + </p> + <p> + {{ form.password.label }}<br> + {{ form.password(size=32) }} <!-- is it necessary to limit password lenght? --> + </p> + <p>{{ form.remember_me() }} {{ form.remember_me.label }}</p> + <p>{{ form.login() }}</p> + </form> +<!-- old version before structure change --> +<!-- <section class="login-grid"> <form class="login"> <label for="username">Login: </label> <input type="text" id="username" name="username"><br> @@ -14,4 +28,5 @@ <input type="submit" value="Login"> </form> </section> +--> {% endblock %} diff --git a/config.py b/config.py @@ -0,0 +1,5 @@ +import os + +class Config(object): + SECRET_KEY = os.environ.get('SECRET_KEY') or 'temporary-dev-key-here-change-prior-to-deployment' + MONGO_URI = "mongodb://localhost:27017/app.db"