Reworked login and register
This commit is contained in:
parent
3a1137561d
commit
81dbaceb46
|
@ -5,6 +5,10 @@ from flask_login import UserMixin
|
||||||
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
FORM_RENDER_KW = {
|
||||||
|
"class_": "form-control"
|
||||||
|
}
|
||||||
|
|
||||||
class BillForm(Form):
|
class BillForm(Form):
|
||||||
payment_to = StringField("Payment to", [validators.DataRequired()])
|
payment_to = StringField("Payment to", [validators.DataRequired()])
|
||||||
description = TextAreaField("Description", render_kw = {
|
description = TextAreaField("Description", render_kw = {
|
||||||
|
@ -19,35 +23,41 @@ class LoginForm(Form):
|
||||||
email = StringField("Email", [
|
email = StringField("Email", [
|
||||||
validators.DataRequired(),
|
validators.DataRequired(),
|
||||||
validators.Length(min=6, max=254)
|
validators.Length(min=6, max=254)
|
||||||
])
|
],
|
||||||
|
render_kw = FORM_RENDER_KW)
|
||||||
|
|
||||||
password = PasswordField("Password", [
|
password = PasswordField("Password", [
|
||||||
validators.DataRequired(),
|
validators.DataRequired(),
|
||||||
validators.Length(min=4, max=127)
|
validators.Length(min=4, max=127)
|
||||||
])
|
],
|
||||||
|
render_kw = FORM_RENDER_KW)
|
||||||
|
|
||||||
class RegisterForm(Form):
|
class RegisterForm(Form):
|
||||||
email = StringField("Email", [
|
email = StringField("Email", [
|
||||||
validators.DataRequired(),
|
validators.DataRequired(),
|
||||||
validators.Length(min=6, max=254)
|
validators.Length(min=6, max=254)
|
||||||
])
|
],
|
||||||
|
render_kw = FORM_RENDER_KW)
|
||||||
|
|
||||||
password = PasswordField("Password", [
|
password = PasswordField("Password", [
|
||||||
validators.DataRequired(),
|
validators.DataRequired(),
|
||||||
validators.Length(min=4, max=127),
|
validators.Length(min=4, max=127),
|
||||||
validators.EqualTo("confirm_password", message = "Passwords must match")
|
validators.EqualTo("confirm_password", message = "Passwords must match")
|
||||||
])
|
],
|
||||||
confirm_password = PasswordField("Repeat Password")
|
render_kw = FORM_RENDER_KW)
|
||||||
|
confirm_password = PasswordField("Repeat Password", render_kw = FORM_RENDER_KW)
|
||||||
|
|
||||||
firstname = StringField("Firstname", [
|
firstname = StringField("Firstname", [
|
||||||
validators.DataRequired(),
|
validators.DataRequired(),
|
||||||
validators.Length(min=2, max=30)
|
validators.Length(min=2, max=30)
|
||||||
])
|
],
|
||||||
|
render_kw = FORM_RENDER_KW)
|
||||||
|
|
||||||
surname = StringField("Surname", [
|
surname = StringField("Surname", [
|
||||||
validators.DataRequired(),
|
validators.DataRequired(),
|
||||||
validators.Length(min=2, max=30)
|
validators.Length(min=2, max=30)
|
||||||
])
|
],
|
||||||
|
render_kw = FORM_RENDER_KW)
|
||||||
|
|
||||||
accept_tos = BooleanField("I accept the TOS", [validators.DataRequired()])
|
accept_tos = BooleanField("I accept the TOS", [validators.DataRequired()])
|
||||||
|
|
||||||
|
|
27
routes.py
27
routes.py
|
@ -70,20 +70,31 @@ def login():
|
||||||
flash(gettext("Already logged in"), "info")
|
flash(gettext("Already logged in"), "info")
|
||||||
return redirect(url_for("dashboard"))
|
return redirect(url_for("dashboard"))
|
||||||
|
|
||||||
form = LoginForm(request.form)
|
form_login = LoginForm(request.form)
|
||||||
if request.method == "POST" and form.validate():
|
form_register = RegisterForm(request.form)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
if form_register.validate():
|
||||||
try:
|
try:
|
||||||
user = User((form.email.data, form.password.data))
|
register_account(form_register.email.data, form_register.password.data, form_register.firstname.data, form_register.surname.data)
|
||||||
|
flash(gettext("User registered"), "success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
flash(gettext(str(e)), "danger")
|
flash(gettext(str(e)), "danger")
|
||||||
return render_template("login.html", form=form)
|
return redirect(url_for("login"))
|
||||||
|
elif form_login.validate():
|
||||||
|
try:
|
||||||
|
user = User((form_login.email.data, form_login.password.data))
|
||||||
flask_login.login_user(user)
|
flask_login.login_user(user)
|
||||||
logged_in_users.append(user)
|
logged_in_users.append(user)
|
||||||
|
|
||||||
flash(gettext("Logged in"), "success")
|
flash(gettext("Logged in"), "success")
|
||||||
return redirect(url_for("dashboard"))
|
except Exception as e:
|
||||||
return render_template("login.html", form=form)
|
flash(gettext(str(e)), "danger")
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
return redirect(url_for("dashboard")) # Valid login > Redirect to dashboard as user is logged in
|
||||||
|
return render_template("login.html", form = {
|
||||||
|
"login": form_login,
|
||||||
|
"register": form_register
|
||||||
|
})
|
||||||
|
|
||||||
@glob.app.route("/register", methods = ["GET", "POST"])
|
@glob.app.route("/register", methods = ["GET", "POST"])
|
||||||
def register():
|
def register():
|
||||||
|
|
BIN
static/img/login-bg.jpg
Normal file
BIN
static/img/login-bg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 276 KiB |
|
@ -3,57 +3,137 @@
|
||||||
{% extends "layout/bootstrap.html" %}
|
{% extends "layout/bootstrap.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<script src="{{ url_for('static', filename='js/alerts.js') }}"></script>
|
<style>
|
||||||
<div class="container pt-3">
|
html, body {
|
||||||
<div class="row alert-section">
|
height: 100%;
|
||||||
<div class="col-md-8 mx-auto">
|
}
|
||||||
<div class="card rounded-1">
|
|
||||||
<div class="card-header navbar topnav">
|
.main-head{
|
||||||
<h3 class="mb-0">Login Methods</h3>
|
height: 150px;
|
||||||
<div class="my-2 my-lg-0 d-flex">
|
background: #FFF;
|
||||||
<a href="{{ url_for('register') }}">Register</a>
|
}
|
||||||
|
|
||||||
|
.sidenav {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.main {
|
||||||
|
padding: 0px 10px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 25% auto;
|
||||||
|
grid-row-gap: 8px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main > .col:nth-child(1n) {
|
||||||
|
grid-row-start: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main > .col:nth-child(2n) {
|
||||||
|
grid-row-start: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-height: 450px) {
|
||||||
|
.sidenav {padding-top: 15px;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 450px) {
|
||||||
|
.login-form{
|
||||||
|
margin-top: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form{
|
||||||
|
margin-top: 10%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px){
|
||||||
|
.main{
|
||||||
|
margin-left: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidenav{
|
||||||
|
width: 40%;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-main-text{
|
||||||
|
margin-top: 20%;
|
||||||
|
padding: 60px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-main-text h2{
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-black{
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidable[aria-expanded="true"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-form > form:nth-child(2n) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-form.toggled > form:nth-child(1n) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.toggle-form.toggled > form:nth-child(2n) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function toggleform(caller) {
|
||||||
|
let selectedDOM = caller;
|
||||||
|
do {
|
||||||
|
if (selectedDOM.classList.contains("toggle-form")){
|
||||||
|
let classes = selectedDOM.classList;
|
||||||
|
classes[classes.contains("toggled") ? "remove" : "add"]("toggled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedDOM = selectedDOM.parentElement;
|
||||||
|
} while (selectedDOM != null);
|
||||||
|
throw Error("Missing toggle-form class for self/parent(s)");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div class="sidenav">
|
||||||
|
<div class="login-main-text">
|
||||||
|
<h2>Husstanden<br>Login Page</h2>
|
||||||
|
<p>Login is required to use this service.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body row">
|
<div class="main">
|
||||||
<div class="col-md-6">
|
<div class="col pt-4">
|
||||||
<h5>Electronic ID</h5>
|
{% with messages = get_flashed_messages(with_categories = true) %}
|
||||||
<p class="lead">
|
{% if messages %}
|
||||||
Secure login using Electronic ID allows Husstanden to show you banking details, bills and receipts.<br>
|
{% for category, message in messages %}
|
||||||
<a target="_blank" href="https://eid.difi.no/en/id-porten/how-obtain-electronic-id">How to obtain an Electronic ID</a>
|
<div class="alert alert-{{ category }} fade in show" role="alert" style="margin-bottom:0px;padding:6px;">
|
||||||
</p>
|
<a href="#" class="close" data-dismiss="alert" aria-label="close" style="margin-left:10px;">×</a>
|
||||||
|
{{ message }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
{% endfor %}
|
||||||
<h5>House Account</h5>
|
{% endif %}
|
||||||
<p class="lead">
|
{% endwith %}
|
||||||
Accounts with less privileges and fast login to view non-sensitive information.<br>
|
|
||||||
Multiple house accounts can be created by logging in with house holder's verified <i>Electronic ID</i>.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col col-md-6 col-sm-12">
|
||||||
<hr>
|
<div class="login-form">
|
||||||
<div class="card-body row pt-2">
|
|
||||||
<div class="col-md-6 pb-2">
|
|
||||||
<a class="btn btn-primary btn-lg btn-block" href="#TODO_LOGIN_EID" onclick="alertAbove(this, 'warning', 'This should redirect the user to Electronic ID page (but due to phishing, we can not demo this)')">Electronic ID</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<a class="btn btn-primary btn-lg btn-block" href="#" data-toggle="modal" data-target="#myModal">House Account</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal fade" id="myModal" role="dialog">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<!-- Modal content-->
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title">Login</h4>
|
|
||||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% macro render_field(field) %}
|
{% macro render_field(field) %}
|
||||||
<dt>{{ field.label }}
|
<div class="form-group">
|
||||||
<dd>{{ field(**kwargs)|safe }}
|
{{ field.label }}
|
||||||
|
{{ field(**kwargs)|safe }}
|
||||||
{% if field.errors %}
|
{% if field.errors %}
|
||||||
<ul class=errors>
|
<ul class=errors>
|
||||||
{% for error in field.errors %}
|
{% for error in field.errors %}
|
||||||
|
@ -61,31 +141,27 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
<form method=post>
|
<div class="toggle-form false">
|
||||||
<dl>
|
<form method="post">
|
||||||
{{ render_field(form.email) }}
|
{{ render_field(form.login.email) }}
|
||||||
{{ render_field(form.password) }}
|
{{ render_field(form.login.password) }}
|
||||||
</dl>
|
<button class="btn btn-black">Login</button>
|
||||||
<input type=submit value="Login">
|
<span class="btn btn-secondary" onclick="toggleform(this)">Register</span>
|
||||||
|
</form>
|
||||||
|
<form method="post">
|
||||||
|
{{ render_field(form.register.email) }}
|
||||||
|
{{ render_field(form.register.password) }}
|
||||||
|
{{ render_field(form.register.confirm_password) }}
|
||||||
|
{{ render_field(form.register.firstname) }}
|
||||||
|
{{ render_field(form.register.surname) }}
|
||||||
|
{{ render_field(form.register.accept_tos) }}
|
||||||
|
<span class="btn btn-secondary" onclick="toggleform(this)">Login</span>
|
||||||
|
<button class="btn btn-black">Register</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
{% with messages = get_flashed_messages() %}
|
|
||||||
{% if messages %}
|
|
||||||
let alertArea = document.getElementsByClassName("alert-section")[0];
|
|
||||||
{% for message in messages %}
|
|
||||||
alertAbove(alertArea, "info", "{{ message }}");
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -18,7 +18,7 @@
|
||||||
<!-- Modal content-->
|
<!-- Modal content-->
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title">Add bill</h4>
|
<h4 class="modal-title">{{ _("Add bill") }}</h4>
|
||||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user