completed authentication system

This commit is contained in:
2022-11-19 15:55:38 -05:00
parent 30493ec187
commit 400c870056
7 changed files with 144 additions and 44 deletions

72
app.py
View File

@@ -1,9 +1,11 @@
import os import os
from flask import Flask, render_template, redirect from flask import Flask, render_template, redirect, url_for, request, flash
from flask_migrate import Migrate from flask_migrate import Migrate
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import (LoginManager, login_user, login_required, logout_user, current_user)
from misc import datetime, date, time, currDay from misc import datetime, date, time, currDay
from db import (db, Period, Task, Event) from db import (db, Period, Task, Event, User)
from forms import (TaskForm, EventForm, PeriodForm) from forms import (TaskForm, EventForm, PeriodForm, SignupForm, LoginForm)
from create_events import createEvents from create_events import createEvents
basedir = os.path.abspath(os.path.dirname(__file__)) basedir = os.path.abspath(os.path.dirname(__file__))
@@ -19,22 +21,73 @@ db.init_app(app)
migrate = Migrate() migrate = Migrate()
migrate.init_app(app, db) migrate.init_app(app, db)
# Authentication stuff
from auth import auth as auth_blueprint login_manager = LoginManager()
app.register_blueprint(auth_blueprint) login_manager.login_view = 'login'
login_manager.init_app(app)
signup_enabled = False
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Index route
@app.route('/') @app.route('/')
def index(): def index():
createEvents(db, currDay, Period, Event) createEvents(db, currDay, Period, Event)
return redirect('/events') return redirect('/events')
# Authentication routes
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
userName = form.userName.data
password = form.password.data
user = User.query.filter_by(userName=userName).first()
if not user or not check_password_hash(user.password, password):
flash('Credentials incorrect! Please try again')
return redirect(url_for('login'))
login_user(user)
return redirect(url_for('events'))
return render_template('login.html', form=form)
@app.route('/createaccount', methods=['GET', 'POST'])
def createAccount():
if signup_enabled == True:
form = SignupForm()
if form.validate_on_submit():
usernameExists = User.query.filter_by(userName=form.userName.data).first()
if usernameExists:
flash('Username already exists')
return redirect(url_for('createAccount'))
new_user = User(email=form.email.data, userName=form.userName.data, realName=form.realName.data,
password=generate_password_hash(form.password.data, method='sha256'))
db.session.add(new_user)
db.session.commit()
return redirect(url_for('login'))
return render_template('createAccount.html', form=form)
else:
return 'Account creation is currently disabled'
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
# Periods routes # Periods routes
@app.route('/periods') @app.route('/periods')
@login_required
def periods(): def periods():
periods = Period.query.all() periods = Period.query.all()
return render_template('periods.html', periods=periods, datetime=datetime) return render_template('periods.html', periods=periods, datetime=datetime)
@app.route('/period/new', methods=('GET', 'POST')) @app.route('/period/new', methods=('GET', 'POST'))
@login_required
def newPeriod(): def newPeriod():
form = PeriodForm() form = PeriodForm()
if form.validate_on_submit(): if form.validate_on_submit():
@@ -49,6 +102,7 @@ def newPeriod():
@app.route('/period/edit/<int:periodNum>', methods=('GET', 'POST')) @app.route('/period/edit/<int:periodNum>', methods=('GET', 'POST'))
@login_required
def editPeriod(periodNum): def editPeriod(periodNum):
period = Period.query.get_or_404(periodNum) period = Period.query.get_or_404(periodNum)
form = PeriodForm(obj=period) form = PeriodForm(obj=period)
@@ -60,6 +114,7 @@ def editPeriod(periodNum):
return render_template('editPeriod.html', period=period, form=form, datetime=datetime) return render_template('editPeriod.html', period=period, form=form, datetime=datetime)
@app.post('/period/delete/<int:periodNum>') @app.post('/period/delete/<int:periodNum>')
@login_required
def delete_period(periodNum): def delete_period(periodNum):
period = Period.query.get_or_404(periodNum) period = Period.query.get_or_404(periodNum)
db.session.delete(period) db.session.delete(period)
@@ -69,6 +124,7 @@ def delete_period(periodNum):
# Events routes # Events routes
@app.route('/events') @app.route('/events')
@login_required
def events(): def events():
events = Event.query.all() events = Event.query.all()
periods = Period.query.all() periods = Period.query.all()
@@ -77,6 +133,7 @@ def events():
return render_template('events.html', events=events, periods=periods, datetime=datetime, date=date) return render_template('events.html', events=events, periods=periods, datetime=datetime, date=date)
@app.route('/event/edit/<int:event_id>/', methods=('GET', 'POST')) @app.route('/event/edit/<int:event_id>/', methods=('GET', 'POST'))
@login_required
def editEvent(event_id): def editEvent(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
form = EventForm(obj=event) form = EventForm(obj=event)
@@ -91,16 +148,19 @@ def editEvent(event_id):
# Tasks routes # Tasks routes
@app.route('/tasks') @app.route('/tasks')
@login_required
def tasks(): def tasks():
tasks = Task.query.all() tasks = Task.query.all()
return render_template('tasks.html', str=str, tasks=tasks, datetime=datetime, date=date) return render_template('tasks.html', str=str, tasks=tasks, datetime=datetime, date=date)
@app.route('/task/<int:task_id>/') @app.route('/task/<int:task_id>/')
@login_required
def task(task_id): def task(task_id):
task = Task.query.get_or_404(task_id) task = Task.query.get_or_404(task_id)
return render_template('task.html', str=str, task=task, datetime=datetime, date=date) return render_template('task.html', str=str, task=task, datetime=datetime, date=date)
@app.route('/task/new', methods=('GET', 'POST')) @app.route('/task/new', methods=('GET', 'POST'))
@login_required
def newTask(): def newTask():
form = TaskForm() form = TaskForm()
if form.validate_on_submit(): if form.validate_on_submit():
@@ -113,6 +173,7 @@ def newTask():
return render_template('newtask.html', form=form) return render_template('newtask.html', form=form)
@app.route('/task/<int:task_id>/edit', methods=('GET', 'POST')) @app.route('/task/<int:task_id>/edit', methods=('GET', 'POST'))
@login_required
def editTask(task_id): def editTask(task_id):
task = Task.query.get_or_404(task_id) task = Task.query.get_or_404(task_id)
form = TaskForm(obj=task) form = TaskForm(obj=task)
@@ -123,6 +184,7 @@ def editTask(task_id):
return redirect(f'/task/{task_id}') return redirect(f'/task/{task_id}')
return render_template('edittask.html', task=task, form=form) return render_template('edittask.html', task=task, form=form)
@app.post('/task/<int:task_id>/delete') @app.post('/task/<int:task_id>/delete')
@login_required
def delete_task(task_id): def delete_task(task_id):
task = Task.query.get_or_404(task_id) task = Task.query.get_or_404(task_id)
db.session.delete(task) db.session.delete(task)

12
auth.py
View File

@@ -1,12 +0,0 @@
from flask import Blueprint, render_template
from app import db
auth = Blueprint('auth', __name__)
@auth.route('/login')
def login():
return render_template('login.html')
@auth.route('/logout')
def logout():
return 'Logout'

3
db.py
View File

@@ -1,4 +1,5 @@
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
db = SQLAlchemy() db = SQLAlchemy()
@@ -36,7 +37,7 @@ class Event(db.Model):
return f'<Event "{self.id}">' return f'<Event "{self.id}">'
class User(db.Model): class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
userName = db.Column(db.String(1000)) userName = db.Column(db.String(1000))
email = db.Column(db.String(100), unique=True) email = db.Column(db.String(100), unique=True)

View File

@@ -1,7 +1,7 @@
from db import Task from db import Task
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import (StringField, DateField, TimeField, TextAreaField, IntegerField, BooleanField, from wtforms import (StringField, DateField, TimeField, TextAreaField, IntegerField, BooleanField,
RadioField) RadioField, EmailField, PasswordField)
from wtforms.validators import InputRequired, Length from wtforms.validators import InputRequired, Length
from wtforms_sqlalchemy.orm import QuerySelectField from wtforms_sqlalchemy.orm import QuerySelectField
@@ -20,3 +20,13 @@ class EventForm(FlaskForm):
class PeriodForm(FlaskForm): class PeriodForm(FlaskForm):
weekendSchedule = BooleanField(label='Include on Weekends?', false_values=None) weekendSchedule = BooleanField(label='Include on Weekends?', false_values=None)
periodTime = TimeField('Time', format="%H:%M") periodTime = TimeField('Time', format="%H:%M")
class SignupForm(FlaskForm):
userName = StringField('Username', validators=[InputRequired()])
password = PasswordField('Password', validators=[InputRequired()])
realName = StringField('Real Name')
email = EmailField('Email Address')
class LoginForm(FlaskForm):
userName = StringField('Username', validators=[InputRequired()])
password = PasswordField('Password', validators=[InputRequired()])

View File

@@ -29,6 +29,14 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="float-right">
{% if current_user.is_authenticated %}
<a href="{{ url_for('logout') }}" class="nav-link"> Logout {{current_user.userName}} </a>
{% endif %}
{% if not current_user.is_authenticated %}
<a href="{{ url_for('login') }}" class="nav-link"> Login </a>
{% endif %}
</div>
</nav> </nav>
<hr> <hr>
<div class="container"> <div class="container">

View File

@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block content %}
<span><h1>{% block title %} Create Account {% endblock %}</h1></span>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="notification is-danger">
{{ messages[0] }}. Go to <a href="{{ url_for('login') }}">login page</a>.
</div>
{% endif %}
{% endwith %}
<form method="post">
{{ form.csrf_token }}
<p>
{{ form.userName.label }}
{{ form.userName }}
</p>
<p>
{{ form.password.label }}
{{ form.password }}
</p>
<p>
{{ form.realName.label }}
{{ form.realName }}
</p>
<p>
{{ form.email.label }}
{{ form.email }}
</p>
<p>
<button class="btn btn-primary" type="submit">Submit</button>
</p>
</form>
{% endblock %}

View File

@@ -1,29 +1,26 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<div> <span><h1>{% block title %} Login {% endblock %}</h1></span>
<h3>Login</h3> {% with messages = get_flashed_messages() %}
<div> {% if messages %}
<form method="POST" action="/login"> <div class="notification is-danger">
<div> {{ messages[0] }}
<div>
<input type="email" name="email" placeholder="Your Email" autofocus="">
</div>
</div>
<div>
<div>
<input type="password" name="password" placeholder="Your Password">
</div>
</div>
<div>
<label>
<input type="checkbox" name="remember">
Remember me
</label>
</div>
<button>Login</button>
</form>
</div> </div>
</div> {% endif %}
{% endwith %}
<form method="post">
{{ form.csrf_token }}
<p>
{{ form.userName.label }}
{{ form.userName }}
</p>
<p>
{{ form.password.label }}
{{ form.password }}
</p>
<p>
<button class="btn btn-primary" type="submit">Submit</button>
</p>
</form>
{% endblock %} {% endblock %}