Login form implemented

This commit is contained in:
Jordan Stremming
2019-03-22 10:28:11 -05:00
parent 4affd1e71f
commit 57ecef68c0
15 changed files with 419 additions and 5 deletions

View File

@@ -1,10 +1,11 @@
from flask import Flask
from flask_assets import Environment
from webassets import Bundle
from app.forms import CustomUserManager
from app.models import db, migrate, User
from app.schemas import ma
from flask_mail import Mail
from flask_user import UserManager
from flask_wtf.csrf import CSRFProtect
# Instantiate Flask extensions
@@ -55,7 +56,7 @@ def register_extensions(app):
ma.init_app(app)
mail.init_app(app)
csrf_protect.init_app(app)
user_manager = UserManager(app, db, User)
user_manager = CustomUserManager(app, db, User)
@app.context_processor
def context_processor():
return dict(user_manager=user_manager)
@@ -75,8 +76,8 @@ def register_blueprints(app):
from .main import main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth_blueprint
app.register_blueprint(auth_blueprint)
# from .auth import auth_blueprint
# app.register_blueprint(auth_blueprint)
def init_email_error_handler(app):

53
app/forms.py Normal file
View File

@@ -0,0 +1,53 @@
from flask import current_app, flash
from flask_user import UserManager
from flask_user.forms import RegisterForm
from flask_wtf import FlaskForm
from wtforms import StringField, HiddenField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired
from app import models
class CustomUserManager(UserManager):
# noinspection PyAttributeOutsideInit
def customize(self, app):
self.LoginFormClass = CustomLoginForm
class CustomLoginForm(FlaskForm):
"""Login form"""
next = HiddenField()
reg_next = HiddenField()
netid = StringField('NetID', validators=[
DataRequired('NetID is required'),
])
password = PasswordField('Password', validators=[
DataRequired('Password is required'),
])
remember_me = BooleanField('Remember me')
submit = SubmitField('Sign in')
def __init__(self, *args, **kwargs):
super(CustomLoginForm, self).__init__(*args, **kwargs)
def validate(self):
# grab the user manager
user_manager = current_app.user_manager
# handle invalid fields
if not super(CustomLoginForm, self).validate():
return False
# find user by netid
user = user_manager.db_manager.db_adapter.ifind_first_object(models.User, netid=self.netid.data)
# handle successful authentication
if user and user_manager.verify_password(self.password.data, user.password):
return True
# unsuccessful authentication
flash('Invalid NetID or Password', 'error')
return False

View File

@@ -0,0 +1,42 @@
{% macro render_field(field, label=None, label_visible=true, right_url=None, right_label=None) -%}
<div class="form-group {% if field.errors %}has-error{% endif %} {{ kwargs.pop('class_', '') }}">
{% if field.type != 'HiddenField' and label_visible %}
{% if not label %}{% set label=field.label.text %}{% endif %}
<label for="{{ field.id }}" class="control-label">{{ label|safe }}</label>
{% endif %}
{{ field(class_='form-control', **kwargs) }}
{% if field.errors %}
{% for e in field.errors %}
<p class="help-block">{{ e }}</p>
{% endfor %}
{% endif %}
</div>
{%- endmacro %}
{% macro render_checkbox_field(field, label=None) -%}
{% if not label %}{% set label=field.label.text %}{% endif %}
<div class="checkbox">
<label>
{{ field(type='checkbox', **kwargs) }} {{ label }}
</label>
</div>
{%- endmacro %}
{% macro render_radio_field(field) -%}
{% for value, label, checked in field.iter_choices() %}
<div class="radio">
<label>
<input type="radio" name="{{ field.id }}" id="{{ field.id }}" value="{{ value }}"{% if checked %} checked{% endif %}>
{{ label }}
</label>
</div>
{% endfor %}
{%- endmacro %}
{% macro render_submit_field(field, label=None, tabindex=None) -%}
{% if not label %}{% set label=field.label.text %}{% endif %}
{#<button type="submit" class="form-control btn btn-default btn-primary">{{label}}</button>#}
<input type="submit" class="btn btn-default btn-primary" value="{{label}}"
{% if tabindex %}tabindex="{{ tabindex }}"{% endif %}
>
{%- endmacro %}

View File

@@ -0,0 +1 @@
{% extends 'base.jinja2' %}

View File

@@ -0,0 +1,17 @@
{% extends 'flask_user/_authorized_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Change password{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.old_password, tabindex=10) }}
{{ render_field(form.new_password, tabindex=20) }}
{% if user_manager.USER_REQUIRE_RETYPE_PASSWORD %}
{{ render_field(form.retype_password, tabindex=30) }}
{% endif %}
{{ render_submit_field(form.submit, tabindex=90) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,14 @@
{% extends 'flask_user/_authorized_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Change username{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.new_username, tabindex=10) }}
{{ render_field(form.old_password, tabindex=20) }}
{{ render_submit_field(form.submit, tabindex=90) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends 'flask_user/_authorized_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_checkbox_field, render_submit_field %}
<h1>{%trans%}User profile{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{% for field in form %}
{% if not field.flags.hidden %}
{% if field.type=='SubmitField' %}
{{ render_submit_field(field, tabindex=loop.index*10) }}
{% else %}
{{ render_field(field, tabindex=loop.index*10) }}
{% endif %}
{% endif %}
{% endfor %}
</form>
<br/>
{% if not user_manager.USER_ENABLE_AUTH0 %}
{% if user_manager.USER_ENABLE_CHANGE_USERNAME %}
<p><a href="{{ url_for('user.change_username') }}">{%trans%}Change username{%endtrans%}</a></p>
{% endif %}
{% if user_manager.USER_ENABLE_CHANGE_PASSWORD %}
<p><a href="{{ url_for('user.change_password') }}">{%trans%}Change password{%endtrans%}</a></p>
{% endif %}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,13 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Forgot Password{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.email, tabindex=10) }}
{{ render_submit_field(form.submit, tabindex=90) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,13 @@
{% extends 'flask_user/_authorized_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Invite User{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.email, tabindex=10) }}
{{ render_submit_field(form.submit, tabindex=90) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,116 @@
{% extends 'flask_user/_public_base.html' %}
{% set navbar_shadow = True %}
{% block title %}Login{% endblock %}
{% block header %}{% endblock %}
{% block css %}
{{ super() }}
{# override the body and html css to force center #}
<style>
html, body {
height: 100%;
background-color: #777777;
}
</style>
{% endblock %}
{% from "flask_user/_macros.html" import render_field, render_checkbox_field, render_submit_field %}
{% block content_before %}
<div class="container-fluid h-100">
<div class="row h-100 justify-content-center align-items-center">
<div class="mx-auto" style="max-width: 30em;">
{# Splash card #}
<div class="card shadow rounded border-0 h-100">
<div class="card-header bg-primary pt-4 text-center text-white">
<img class="img-fluid mb-3" src="http://lib.msstate.edu/_assets/img/2015-header-logo-msstate.png"
alt=""/>
<h5>Electronic Thesis and Dissertation System</h5>
</div>
<div class="card-body d-flex flex-column m-2">
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
<h3>
Login
</h3>
<hr class="mb-4"/>
{# Show any errors #}
{% with messages = get_flashed_messages() %}
{% for message in messages %}
<div class="alert alert-warning" role="alert">
{{ message }}
</div>
{% endfor %}
{% endwith %}
{# NetID field #}
{% set field = form.netid %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
{# Label on left, "New here? Register." on right #}
<div class="row">
<div class="col-6">
<label for="{{ field.id }}" class="font-weight-bold">{{ field.label.text }}</label>
</div>
<div class="col-6 text-right">
{% if user_manager.USER_ENABLE_REGISTER and not user_manager.USER_REQUIRE_INVITATION %}
<a href="{{ url_for('user.register') }}" class="text-primary" tabindex='190'>
{%trans%}New here? Register.{%endtrans%}</a>
{% endif %}
</div>
</div>
{{ field(class_='form-control', tabindex=110) }}
{% if field.errors %}
{% for e in field.errors %}
<p class="help-block">{{ e }}</p>
{% endfor %}
{% endif %}
</div>
{# Password field #}
{% set field = form.password %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
{# Label on left, "Forgot your Password?" on right #}
<div class="row">
<div class="col-6">
<label for="{{ field.id }}" class="font-weight-bold">{{ field.label.text }}</label>
</div>
<div class="col-6 text-right">
{% if user_manager.USER_ENABLE_FORGOT_PASSWORD %}
<a href="{{ url_for('user.forgot_password') }}" class="text-primary" tabindex='195'>
{%trans%}Forgot your Password?{%endtrans%}</a>
{% endif %}
</div>
</div>
{{ field(class_='form-control', tabindex=120) }}
{% if field.errors %}
{% for e in field.errors %}
<p class="help-block">{{ e }}</p>
{% endfor %}
{% endif %}
</div>
{# Remember me #}
{% if user_manager.USER_ENABLE_REMEMBER_ME %}
{{ render_checkbox_field(login_form.remember_me, tabindex=130) }}
{% endif %}
{# Submit button #}
{{ render_submit_field(form.submit, tabindex=180) }}
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,39 @@
{% extends 'flask_user/_authorized_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Manage Emails{%endtrans%}</h1>
<table class="table">
<tr><th>Email</th><th>Status</th><th>Actions</th></tr>
{% for user_email in user_emails %}
<tr>
<td>{{ user_email.email }}</td>
<td>
{% if user_email.email_confirmed_at %}
Confirmed
{% else %}
<a href="{{ url_for('user.email_action', id=user_email.id, action='confirm') }}">Confirm Email</a>
{% endif %}
</td>
<td>
{% if user_email.is_primary %}
<b>Primary email</b>
{% else %}
{% if user_email.email_confirmed_at %}
<a href="{{ url_for('user.email_action', id=user_email.id, action='make-primary') }}">Make primary</a> |
{% endif %}
<a href="{{ url_for('user.email_action', id=user_email.id, action='delete') }}">Delete</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.email) }}
{{ render_submit_field(form.submit) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,46 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Register{%endtrans%}</h1>
<form action="" method="POST" novalidate formnovalidate class="form" role="form">
{{ form.hidden_tag() }}
{# Username or Email #}
{% set field = form.username if user_manager.USER_ENABLE_USERNAME else form.email %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
{# Label on left, "Already registered? Sign in." on right #}
<div class="row">
<div class="col-xs-6">
<label for="{{ field.id }}" class="control-label">{{ field.label.text }}</label>
</div>
<div class="col-xs-6 text-right">
{% if user_manager.USER_ENABLE_REGISTER %}
<a href="{{ url_for('user.login') }}" tabindex='290'>
{%trans%}Already registered? Sign in.{%endtrans%}</a>
{% endif %}
</div>
</div>
{{ field(class_='form-control', tabindex=210) }}
{% if field.errors %}
{% for e in field.errors %}
<p class="help-block">{{ e }}</p>
{% endfor %}
{% endif %}
</div>
{% if user_manager.USER_ENABLE_EMAIL and user_manager.USER_ENABLE_USERNAME %}
{{ render_field(form.email, tabindex=220) }}
{% endif %}
{{ render_field(form.password, tabindex=230) }}
{% if user_manager.USER_REQUIRE_RETYPE_PASSWORD %}
{{ render_field(form.retype_password, tabindex=240) }}
{% endif %}
{{ render_submit_field(form.submit, tabindex=280) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,13 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Resend Confirmation Email{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.email, tabindex=10) }}
{{ render_submit_field(form.submit, tabindex=90) }}
</form>
{% endblock %}

View File

@@ -0,0 +1,16 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
<h1>{%trans%}Reset Password{%endtrans%}</h1>
<form action="" method="POST" class="form" role="form">
{{ form.hidden_tag() }}
{{ render_field(form.new_password, tabindex=10) }}
{% if user_manager.USER_REQUIRE_RETYPE_PASSWORD %}
{{ render_field(form.retype_password, tabindex=20) }}
{% endif %}
{{ render_submit_field(form.submit, tabindex=90) }}
</form>
{% endblock %}

View File

@@ -36,7 +36,7 @@
</p>
{# TODO: link to CAS sign in #}
<a href="{{ url_for("auth.login") }}" class="btn btn-primary btn-lg mt-auto align-self-center px-4">
<a href="{{ url_for("user.login") }}" class="btn btn-primary btn-lg mt-auto align-self-center px-4">
Sign in with CAS
</a>
</div>