completed authentication system
This commit is contained in:
72
app.py
72
app.py
@@ -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
12
auth.py
@@ -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
3
db.py
@@ -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)
|
||||||
|
12
forms.py
12
forms.py
@@ -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()])
|
@@ -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">
|
||||||
|
34
templates/createAccount.html
Normal file
34
templates/createAccount.html
Normal 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 %}
|
@@ -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>
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
<div>
|
<form method="post">
|
||||||
<div>
|
{{ form.csrf_token }}
|
||||||
<input type="password" name="password" placeholder="Your Password">
|
<p>
|
||||||
</div>
|
{{ form.userName.label }}
|
||||||
</div>
|
{{ form.userName }}
|
||||||
<div>
|
</p>
|
||||||
<label>
|
<p>
|
||||||
<input type="checkbox" name="remember">
|
{{ form.password.label }}
|
||||||
Remember me
|
{{ form.password }}
|
||||||
</label>
|
</p>
|
||||||
</div>
|
<p>
|
||||||
<button>Login</button>
|
<button class="btn btn-primary" type="submit">Submit</button>
|
||||||
</form>
|
</p>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
Reference in New Issue
Block a user