diff --git a/app/__init__.py b/app/__init__.py index 206af2e..7e8ed75 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -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): diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..3efd3c0 --- /dev/null +++ b/app/forms.py @@ -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 diff --git a/app/templates/flask_user/_macros.html b/app/templates/flask_user/_macros.html new file mode 100644 index 0000000..fcb00ed --- /dev/null +++ b/app/templates/flask_user/_macros.html @@ -0,0 +1,42 @@ +{% macro render_field(field, label=None, label_visible=true, right_url=None, right_label=None) -%} +
+ {% if field.type != 'HiddenField' and label_visible %} + {% if not label %}{% set label=field.label.text %}{% endif %} + + {% endif %} + {{ field(class_='form-control', **kwargs) }} + {% if field.errors %} + {% for e in field.errors %} +

{{ e }}

+ {% endfor %} + {% endif %} +
+{%- endmacro %} + +{% macro render_checkbox_field(field, label=None) -%} + {% if not label %}{% set label=field.label.text %}{% endif %} +
+ +
+{%- endmacro %} + +{% macro render_radio_field(field) -%} + {% for value, label, checked in field.iter_choices() %} +
+ +
+ {% endfor %} +{%- endmacro %} + +{% macro render_submit_field(field, label=None, tabindex=None) -%} + {% if not label %}{% set label=field.label.text %}{% endif %} + {##} + +{%- endmacro %} diff --git a/app/templates/flask_user/_public_base.html b/app/templates/flask_user/_public_base.html new file mode 100644 index 0000000..7d12259 --- /dev/null +++ b/app/templates/flask_user/_public_base.html @@ -0,0 +1 @@ +{% extends 'base.jinja2' %} diff --git a/app/templates/flask_user/change_password.html b/app/templates/flask_user/change_password.html new file mode 100644 index 0000000..6c588cd --- /dev/null +++ b/app/templates/flask_user/change_password.html @@ -0,0 +1,17 @@ +{% extends 'flask_user/_authorized_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Change password{%endtrans%}

+ +
+ {{ 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) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/change_username.html b/app/templates/flask_user/change_username.html new file mode 100644 index 0000000..39c7aed --- /dev/null +++ b/app/templates/flask_user/change_username.html @@ -0,0 +1,14 @@ +{% extends 'flask_user/_authorized_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Change username{%endtrans%}

+ +
+ {{ form.hidden_tag() }} + {{ render_field(form.new_username, tabindex=10) }} + {{ render_field(form.old_password, tabindex=20) }} + {{ render_submit_field(form.submit, tabindex=90) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/edit_user_profile.html b/app/templates/flask_user/edit_user_profile.html new file mode 100644 index 0000000..1fa2575 --- /dev/null +++ b/app/templates/flask_user/edit_user_profile.html @@ -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 %} +

{%trans%}User profile{%endtrans%}

+ +
+ {{ 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 %} +
+
+ +{% if not user_manager.USER_ENABLE_AUTH0 %} + {% if user_manager.USER_ENABLE_CHANGE_USERNAME %} +

{%trans%}Change username{%endtrans%}

+ {% endif %} + {% if user_manager.USER_ENABLE_CHANGE_PASSWORD %} +

{%trans%}Change password{%endtrans%}

+ {% endif %} +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/forgot_password.html b/app/templates/flask_user/forgot_password.html new file mode 100644 index 0000000..cf78b45 --- /dev/null +++ b/app/templates/flask_user/forgot_password.html @@ -0,0 +1,13 @@ +{% extends 'flask_user/_public_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Forgot Password{%endtrans%}

+ +
+ {{ form.hidden_tag() }} + {{ render_field(form.email, tabindex=10) }} + {{ render_submit_field(form.submit, tabindex=90) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/invite_user.html b/app/templates/flask_user/invite_user.html new file mode 100644 index 0000000..5abe526 --- /dev/null +++ b/app/templates/flask_user/invite_user.html @@ -0,0 +1,13 @@ +{% extends 'flask_user/_authorized_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Invite User{%endtrans%}

+ +
+ {{ form.hidden_tag() }} + {{ render_field(form.email, tabindex=10) }} + {{ render_submit_field(form.submit, tabindex=90) }} +
+ +{% endblock %} diff --git a/app/templates/flask_user/login.html b/app/templates/flask_user/login.html new file mode 100644 index 0000000..1cb30cc --- /dev/null +++ b/app/templates/flask_user/login.html @@ -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 #} + +{% endblock %} + +{% from "flask_user/_macros.html" import render_field, render_checkbox_field, render_submit_field %} + +{% block content_before %} +
+
+
+ + {# Splash card #} +
+
+ +
Electronic Thesis and Dissertation System
+
+ +
+ +
+ {{ form.hidden_tag() }} + +

+ Login +

+ +
+ + {# Show any errors #} + {% with messages = get_flashed_messages() %} + {% for message in messages %} + + {% endfor %} + {% endwith %} + + + {# NetID field #} + {% set field = form.netid %} +
+ {# Label on left, "New here? Register." on right #} +
+
+ +
+
+ {% if user_manager.USER_ENABLE_REGISTER and not user_manager.USER_REQUIRE_INVITATION %} + + {%trans%}New here? Register.{%endtrans%} + {% endif %} +
+
+ {{ field(class_='form-control', tabindex=110) }} + {% if field.errors %} + {% for e in field.errors %} +

{{ e }}

+ {% endfor %} + {% endif %} +
+ + {# Password field #} + {% set field = form.password %} +
+ {# Label on left, "Forgot your Password?" on right #} +
+
+ +
+
+ {% if user_manager.USER_ENABLE_FORGOT_PASSWORD %} + + {%trans%}Forgot your Password?{%endtrans%} + {% endif %} +
+
+ {{ field(class_='form-control', tabindex=120) }} + {% if field.errors %} + {% for e in field.errors %} +

{{ e }}

+ {% endfor %} + {% endif %} +
+ + {# 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) }} + +
+ +
+
+ +
+
+
+{% endblock %} diff --git a/app/templates/flask_user/manage_emails.html b/app/templates/flask_user/manage_emails.html new file mode 100644 index 0000000..1677db7 --- /dev/null +++ b/app/templates/flask_user/manage_emails.html @@ -0,0 +1,39 @@ +{% extends 'flask_user/_authorized_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Manage Emails{%endtrans%}

+ + + +{% for user_email in user_emails %} + + + + + +{% endfor %} +
EmailStatusActions
{{ user_email.email }} + {% if user_email.email_confirmed_at %} + Confirmed + {% else %} + Confirm Email + {% endif %} + + {% if user_email.is_primary %} + Primary email + {% else %} + {% if user_email.email_confirmed_at %} + Make primary | + {% endif %} + Delete + {% endif %} +
+ +
+ {{ form.hidden_tag() }} + {{ render_field(form.email) }} + {{ render_submit_field(form.submit) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/register.html b/app/templates/flask_user/register.html new file mode 100644 index 0000000..df54c4a --- /dev/null +++ b/app/templates/flask_user/register.html @@ -0,0 +1,46 @@ +{% extends 'flask_user/_public_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Register{%endtrans%}

+ +
+ {{ form.hidden_tag() }} + + {# Username or Email #} + {% set field = form.username if user_manager.USER_ENABLE_USERNAME else form.email %} +
+ {# Label on left, "Already registered? Sign in." on right #} +
+
+ +
+
+ {% if user_manager.USER_ENABLE_REGISTER %} + + {%trans%}Already registered? Sign in.{%endtrans%} + {% endif %} +
+
+ {{ field(class_='form-control', tabindex=210) }} + {% if field.errors %} + {% for e in field.errors %} +

{{ e }}

+ {% endfor %} + {% endif %} +
+ + {% 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) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/resend_confirm_email.html b/app/templates/flask_user/resend_confirm_email.html new file mode 100644 index 0000000..5de6033 --- /dev/null +++ b/app/templates/flask_user/resend_confirm_email.html @@ -0,0 +1,13 @@ +{% extends 'flask_user/_public_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Resend Confirmation Email{%endtrans%}

+ +
+ {{ form.hidden_tag() }} + {{ render_field(form.email, tabindex=10) }} + {{ render_submit_field(form.submit, tabindex=90) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/reset_password.html b/app/templates/flask_user/reset_password.html new file mode 100644 index 0000000..033aa5d --- /dev/null +++ b/app/templates/flask_user/reset_password.html @@ -0,0 +1,16 @@ +{% extends 'flask_user/_public_base.html' %} + +{% block content %} +{% from "flask_user/_macros.html" import render_field, render_submit_field %} +

{%trans%}Reset Password{%endtrans%}

+ +
+ {{ 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) }} +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/main/splash.jinja2 b/app/templates/main/splash.jinja2 index 0dddaf4..f15fd42 100644 --- a/app/templates/main/splash.jinja2 +++ b/app/templates/main/splash.jinja2 @@ -36,7 +36,7 @@

{# TODO: link to CAS sign in #} - + Sign in with CAS