Add login functionality and basic HTML pages
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
from flask import Flask
|
||||
from config import Config
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_login import LoginManager
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(Config)
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
login = LoginManager(app)
|
||||
login.login_view = "login"
|
||||
|
||||
from app import routes, models
|
||||
|
||||
10
code/app/forms.py
Normal file
10
code/app/forms.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
||||
username = StringField("Username", validators=[DataRequired()])
|
||||
password = PasswordField("Password", validators=[DataRequired()])
|
||||
remember_me = BooleanField("Remember Me")
|
||||
submit = SubmitField("Sign In")
|
||||
@@ -1,16 +1,16 @@
|
||||
from app import db
|
||||
from subprocess import run
|
||||
from database.constants import DB_USER, DB_PW, DB_NAME
|
||||
from app import db, login
|
||||
from flask_login import UserMixin
|
||||
from werkzeug.security import check_password_hash
|
||||
|
||||
|
||||
class Glacier(db.Model):
|
||||
uid = db.Column(db.String(5), primary_key=True)
|
||||
id = db.Column(db.String(20), primary_key=True)
|
||||
country = db.Column(db.String(60))
|
||||
name = db.Column(db.String(60))
|
||||
annual_data = db.relationship("Annual_Data")
|
||||
|
||||
def __init__(self, uid, country, name):
|
||||
self.uid = uid
|
||||
def __init__(self, id, country, name):
|
||||
self.id = id
|
||||
self.country = country
|
||||
self.name = name
|
||||
|
||||
@@ -18,7 +18,7 @@ class Glacier(db.Model):
|
||||
class Annual_Data(db.Model):
|
||||
__tablename__ = "annual_data"
|
||||
year = db.Column(db.Integer, primary_key=True)
|
||||
uid = db.Column(db.ForeignKey("glacier.uid"), primary_key=True)
|
||||
id = db.Column(db.ForeignKey("glacier.id"), primary_key=True)
|
||||
surface = db.Column(db.Float)
|
||||
length = db.Column(db.Float)
|
||||
elevation = db.Column(db.Float)
|
||||
@@ -30,15 +30,22 @@ class Annual_Data(db.Model):
|
||||
self.elevation = elevation
|
||||
|
||||
|
||||
class User(db.Model):
|
||||
uid = db.Column(db.Integer, primary_key=True)
|
||||
class User(UserMixin, db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
registration_date = db.Column(
|
||||
db.DateTime, nullable=False, server_default=db.func.now()
|
||||
)
|
||||
username = db.Column(db.String(20), nullable=False, unique=True)
|
||||
password = db.Column(db.String(60))
|
||||
password_hash = db.Column(db.String(128), unique=True)
|
||||
|
||||
def __init__(self, uid, username, password):
|
||||
self.uid = uid
|
||||
def __init__(self, id, username, password_hash):
|
||||
self.id = id
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.password_hash = password_hash
|
||||
|
||||
def check_password(self, password):
|
||||
return check_password_hash(self.password_hash, password)
|
||||
|
||||
@login.user_loader
|
||||
def load_user(id):
|
||||
return User.query.get(int(id))
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
from app import app
|
||||
from flask import render_template
|
||||
from app.forms import LoginForm
|
||||
from app.models import User
|
||||
from flask import flash, redirect, render_template, url_for, request
|
||||
from flask_login import current_user, login_user, logout_user, login_required
|
||||
from werkzeug.urls import url_parse
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@app.route("/index")
|
||||
def index():
|
||||
user = {"username": "Bolaji"}
|
||||
posts = [
|
||||
{"author": {"username": "Miloud"}, "body": "Beautiful day in Meknes!"},
|
||||
{"author": {"username": "Sebtaoui"}, "body": "The Farkouss movie was lit!"},
|
||||
]
|
||||
return render_template("index.html", title="Home", user=user, posts=posts)
|
||||
return render_template("index.html", title="Home Page")
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for("admin"))
|
||||
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("login"))
|
||||
login_user(user, remember=form.remember_me.data)
|
||||
next_page = request.args.get("next")
|
||||
if not next_page or url_parse(next_page).netloc != "":
|
||||
next_page = url_for("admin")
|
||||
return redirect(next_page)
|
||||
return render_template("login.html", title="Sign In", form=form)
|
||||
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@app.route("/admin")
|
||||
@login_required
|
||||
def admin():
|
||||
return render_template("admin.html", title="Admin Page")
|
||||
|
||||
6
code/app/templates/admin.html
Normal file
6
code/app/templates/admin.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Hi, {{ current_user.username }}!</h1>
|
||||
Do you want to nuke the database?
|
||||
{% endblock %}
|
||||
@@ -7,8 +7,24 @@
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
<div>IGDB: <a href="/index">Home</a></div>
|
||||
<div>IGDB:
|
||||
<a href="{{ url_for('index') }}">Home</a>
|
||||
{% if current_user.is_anonymous %}
|
||||
<a href="{{ url_for('login') }}">Login</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('admin') }}">Administration</a>
|
||||
<a href="{{ url_for('logout') }}">Logout</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<ul>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %} </body>
|
||||
</html>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Hi, {{ user.username }}!</h1>
|
||||
{% for post in posts %}
|
||||
<div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
|
||||
{% endfor %}
|
||||
<h1>IGDB: International Glacier Database</h1>
|
||||
The IGDB is a database, that uses data from the <a href="https://dx.doi.org/10.5904/wgms-fog-2019-12">WGMS</a> to illustrate the consequences of climate change.
|
||||
{% endblock %}
|
||||
|
||||
24
code/app/templates/login.html
Normal file
24
code/app/templates/login.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Sign In</h1>
|
||||
<form action="" method="post" novalidate>
|
||||
{{ form.hidden_tag() }}
|
||||
<p>
|
||||
{{ form.username.label }}<br>
|
||||
{{ form.username(size=32) }}<br>
|
||||
{% for error in form.username.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>
|
||||
{{ form.password.label }}<br>
|
||||
{{ form.password(size=32) }}<br>
|
||||
{% for error in form.password.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
</form>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user