diff --git a/app/__init__.py b/app/__init__.py index 8de0eab..3bf63f0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -10,11 +10,7 @@ from flask_wtf.csrf import CSRFProtect from app.models import User, Role, UsersRoles from flask_user import user_registered - -import click -from flask.cli import with_appcontext -import datetime -from flask_user import current_app +from app.commands import init_db # Instantiate Flask extensions @@ -120,7 +116,8 @@ def init_email_error_handler(app): Initialize a logger to send emails on error-level messages. Unhandled exceptions will now send an email message to app.config.ADMINS. """ - if app.debug: return # Do not send error emails while developing + if app.debug: + return # Do not send error emails while developing # Retrieve email settings from app.config host = app.config['MAIL_SERVER'] @@ -150,82 +147,3 @@ def init_email_error_handler(app): app.logger.addHandler(mail_handler) # Log errors using: app.logger.error('Some error message') - -# TODO: separate out into a commands file - - -@click.command("init_db") -@with_appcontext -def init_db(): - """ Initialize the database.""" - - print('Initializing Database.') - print('Dropping all tables.') - db.drop_all() - print('Creating all tables.') - db.create_all() - create_users() - print('Database has been initialized.') - - -def create_users(): - """ Create users """ - - # Create all tables - db.create_all() - - # Adding roles - print('Creating Roles.') - admin_role = find_or_create_role('admin', u'Admin') # 1 - user_role = find_or_create_role('user', u'User') # 2 - reviewer = find_or_create_role('reviewer', u'Reviewer') # 3 - viewer = find_or_create_role('viewer', u'Viewer') # 4 - helper = find_or_create_role('helper', u'Helper') # 5 - - - # Add users - print('Creating Admin User.') - admin_user = find_or_create_user(u'Admin', u'Admin', u'Admin', u'admin@library.msstate.edu', 'Password1', u'CSE', u'net001', u'000-000-000', 1970, 1, 1, u'16623257668', u'US', u'Mississippi', u'Mississippi State', u'39762', u'395 Hardy Rd', None, admin_role) - - # Save to DB - db.session.commit() - - -def find_or_create_role(name, label): - """ Find existing role or create new role """ - role = Role.query.filter(Role.name == name).first() - if not role: - role = Role(name=name, label=label) - db.session.add(role) - return role - - -def find_or_create_user(first_name, middle_name, last_name, email, password, department, net_id, msu_id, b_year, b_month, b_day, prim_phone, country=u'US', administrative_area=u'Mississippi', locality=u'Mississippi State', postal_code=u'39762', thoroughfare=u'395 Hardy Rd', premise=None, role=None): - """ Find existing user or create new user """ - user = User.query.filter(User.email == email).first() - if not user: - b_time = datetime.datetime(b_year, b_month, b_day) - user = User(email=email, - first_name=first_name, - middle_name=middle_name, - last_name=last_name, - department=department, - net_id=net_id, - msu_id=msu_id, - birth_date=b_time.strftime('%B %d, %Y'), - prim_phone=prim_phone, - country=country, - administrative_area=administrative_area, - locality=locality, - postal_code=postal_code, - thoroughfare=thoroughfare, - premise=premise, - password=current_app.user_manager.password_manager.hash_password(password), - active=True, - email_confirmed_at=datetime.datetime.utcnow()) - if role: - user.roles.append(role) - db.session.add(user) - return user - - diff --git a/app/commands.py b/app/commands.py new file mode 100644 index 0000000..ba481a9 --- /dev/null +++ b/app/commands.py @@ -0,0 +1,81 @@ +import click +from flask.cli import with_appcontext +import datetime +from flask_user import current_app +from app import db +from app.models import Role, User + + +@click.command("init_db") +@with_appcontext +def init_db(): + """ Initialize the database.""" + + print('Initializing Database.') + print('Dropping all tables.') + db.drop_all() + print('Creating all tables.') + db.create_all() + create_users() + print('Database has been initialized.') + + +def create_users(): + """ Create users """ + + # Create all tables + db.create_all() + + # Adding roles + print('Creating Roles.') + admin_role = find_or_create_role('admin', u'Admin') # 1 + user_role = find_or_create_role('user', u'User') # 2 + reviewer = find_or_create_role('reviewer', u'Reviewer') # 3 + viewer = find_or_create_role('viewer', u'Viewer') # 4 + helper = find_or_create_role('helper', u'Helper') # 5 + + + # Add users + print('Creating Admin User.') + admin_user = find_or_create_user(u'Admin', u'Admin', u'Admin', u'admin@library.msstate.edu', 'Password1', u'CSE', u'net001', u'000-000-000', 1970, 1, 1, u'16623257668', u'US', u'Mississippi', u'Mississippi State', u'39762', u'395 Hardy Rd', None, admin_role) + + # Save to DB + db.session.commit() + + +def find_or_create_role(name, label): + """ Find existing role or create new role """ + role = Role.query.filter(Role.name == name).first() + if not role: + role = Role(name=name, label=label) + db.session.add(role) + return role + + +def find_or_create_user(first_name, middle_name, last_name, email, password, department, net_id, msu_id, b_year, b_month, b_day, prim_phone, country=u'US', administrative_area=u'Mississippi', locality=u'Mississippi State', postal_code=u'39762', thoroughfare=u'395 Hardy Rd', premise=None, role=None): + """ Find existing user or create new user """ + user = User.query.filter(User.email == email).first() + if not user: + b_time = datetime.datetime(b_year, b_month, b_day) + user = User(email=email, + first_name=first_name, + middle_name=middle_name, + last_name=last_name, + department=department, + net_id=net_id, + msu_id=msu_id, + birth_date=b_time.strftime('%B %d, %Y'), + prim_phone=prim_phone, + country=country, + administrative_area=administrative_area, + locality=locality, + postal_code=postal_code, + thoroughfare=thoroughfare, + premise=premise, + password=current_app.user_manager.password_manager.hash_password(password), + active=True, + email_confirmed_at=datetime.datetime.utcnow()) + if role: + user.roles.append(role) + db.session.add(user) + return user diff --git a/app/local_settings_example.py b/app/local_settings_example.py index ae78263..d9d6399 100644 --- a/app/local_settings_example.py +++ b/app/local_settings_example.py @@ -1,4 +1,3 @@ - import os # ***************************** @@ -10,9 +9,10 @@ DEBUG = True # Folders for uploading and supporting documents # THESE FOLDER MUST EXIST ON THE FILE SYSTEM -SIGNATURE_FOLDER = '/path/to/instance/signatures' -SUBMISSION_FOLDER = '/path/to/instance/submissions' -DOCUMENTS_FOLDER = '/path/to/instance/documents' +SIGNATURE_FOLDER = '/data/signatures' +SUBMISSION_FOLDER = '/data/submissions' +DOCUMENTS_FOLDER = '/data/documents' + # DO NOT use Unsecure Secrets in production environments # Generate a safe one with: # python -c "import os; print repr(os.urandom(24));" @@ -20,7 +20,7 @@ SECRET_KEY = 'This is an UNSECURE Secret. CHANGE THIS for production environment # SQLAlchemy settings SQLALCHEMY_DATABASE_URI = 'postgresql://user:password@host:port/database' -SQLALCHEMY_TRACK_MODIFICATIONS = False # Avoids a SQLAlchemy Warning +SQLALCHEMY_TRACK_MODIFICATIONS = False # Avoids a SQLAlchemy Warning # Flask-Mail settings # For smtp.gmail.com to work, you MUST set "Allow less secure apps" to ON in Google Accounts. @@ -33,7 +33,7 @@ MAIL_USERNAME = 'yourname@gmail.com' MAIL_PASSWORD = 'password' # Sendgrid settings -SENDGRID_API_KEY='place-your-sendgrid-api-key-here' +SENDGRID_API_KEY = 'place-your-sendgrid-api-key-here' # Flask-User settings USER_APP_NAME = 'Flask-User starter app' @@ -42,4 +42,4 @@ USER_EMAIL_SENDER_EMAIL = 'yourname@gmail.com' ADMINS = [ '"Admin One" ', - ] +] diff --git a/app/schemas.py b/app/schemas.py index 541229d..2045abc 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -1,5 +1,4 @@ from flask_marshmallow.sqla import ModelSchema -from app import ma from .models import User, Notification, Submission, Revision, Review diff --git a/app/settings.py b/app/settings.py index cb90308..f5d6df9 100644 --- a/app/settings.py +++ b/app/settings.py @@ -1,6 +1,4 @@ # Settings common to all environments (development|staging|production) -# Place environment specific settings in env_settings.py -# An example file (env_settings_example.py) can be used as a starting point # Application settings APP_NAME = "MSState Library ETD System" @@ -22,8 +20,16 @@ USER_ENABLE_EMAIL = True # Register with Email USER_ENABLE_REGISTRATION = True # Allow new users to register USER_REQUIRE_RETYPE_PASSWORD = True # Prompt for `retype password` in: USER_ENABLE_USERNAME = False # Register and Login with username -USER_PASSLIB_CRYPTCONTEXT_SCHEMES = ['argon2'] # argon2 for hashing +# Password hashing settings +USER_PASSLIB_CRYPTCONTEXT_SCHEMES = ['argon2'] # argon2 for password hashing +# I would suggest settings these to the maximum that you can. +USER_PASSLIB_CRYPTCONTEXT_KEYWORDS = dict(argon2__rounds=5, argon2__memory_cost=8192, argon2__max_threads=-1) +# rounds - This corresponds linearly to the amount of time hashing will take. +# memory_cost - Defines the memory usage in kibibytes. This corresponds linearly to the amount of memory hashing will take. +# max_threads - Maximum number of threads that will be used. -1 means unlimited; otherwise hashing will use `min(parallelism, max_threads)` threads. + +# Flask-User routing settings USER_AFTER_LOGIN_ENDPOINT = "main.index" USER_AFTER_LOGOUT_ENDPOINT = "main.signed_out" USER_AFTER_EDIT_USER_PROFILE_ENDPOINT = 'main.profile' diff --git a/app/templates/flask_user/emails/base_message.html b/app/templates/flask_user/emails/base_message.html new file mode 100644 index 0000000..183abc3 --- /dev/null +++ b/app/templates/flask_user/emails/base_message.html @@ -0,0 +1,8 @@ +

Dear {{ user.email }},

+ +{% block message %} +{% endblock %} + +

Sincerely,
+{{ app_name }} +

\ No newline at end of file diff --git a/app/templates/flask_user/emails/base_message.txt b/app/templates/flask_user/emails/base_message.txt new file mode 100644 index 0000000..5d63a0e --- /dev/null +++ b/app/templates/flask_user/emails/base_message.txt @@ -0,0 +1,7 @@ +Dear User, + +{% block message %} +{% endblock %} + +Sincerely, +{{ app_name }} diff --git a/app/templates/flask_user/emails/base_subject.txt b/app/templates/flask_user/emails/base_subject.txt new file mode 100644 index 0000000..7a6c3bf --- /dev/null +++ b/app/templates/flask_user/emails/base_subject.txt @@ -0,0 +1 @@ +{{ app_name }} - {% block subject %}{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/confirm_email_message.html b/app/templates/flask_user/emails/confirm_email_message.html new file mode 100644 index 0000000..e07a73a --- /dev/null +++ b/app/templates/flask_user/emails/confirm_email_message.html @@ -0,0 +1,11 @@ +{% extends 'flask_user/emails/base_message.html' %} + +{% block message %} +

You will need to confirm your email to start using {{ app_name }}.

+ +

If you initiated this confirmation, please click on the link below:
+    Confirm your email.

+ +

If you did not initiate this confirmation, you may safely ignore this email.

+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/confirm_email_message.txt b/app/templates/flask_user/emails/confirm_email_message.txt new file mode 100644 index 0000000..c707421 --- /dev/null +++ b/app/templates/flask_user/emails/confirm_email_message.txt @@ -0,0 +1,10 @@ +{% extends 'flask_user/emails/base_message.txt' %} + +{% block message %} +You will need to confirm your email to start using {{ app_name }}. + +If you initiated this registration, please visit the link below: + {{ confirm_email_link }} + +If you did not initiate this registration, you may safely ignore this email. +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/confirm_email_subject.txt b/app/templates/flask_user/emails/confirm_email_subject.txt new file mode 100644 index 0000000..1f8c456 --- /dev/null +++ b/app/templates/flask_user/emails/confirm_email_subject.txt @@ -0,0 +1,3 @@ +{% extends 'flask_user/emails/base_subject.txt' %} + +{% block subject %}Email Confirmation{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/invite_user_message.html b/app/templates/flask_user/emails/invite_user_message.html new file mode 100644 index 0000000..7d1c393 --- /dev/null +++ b/app/templates/flask_user/emails/invite_user_message.html @@ -0,0 +1,10 @@ +{% extends 'flask_user/emails/base_message.html' %} + +{% block message %} + +

You have been invited to join {{ app_name }}!

+ +

To register an account, please click on the link below:
+    Join {{ app_name }}.

+ +{% endblock %} diff --git a/app/templates/flask_user/emails/invite_user_message.txt b/app/templates/flask_user/emails/invite_user_message.txt new file mode 100644 index 0000000..25986fa --- /dev/null +++ b/app/templates/flask_user/emails/invite_user_message.txt @@ -0,0 +1,9 @@ +{% extends 'flask_user/emails/base_message.txt' %} + +{% block message %} +You have been invited to join {{ app_name }}. + +To register an account, please click on the link below: + {{ accept_invitation_link }} + +{% endblock %} diff --git a/app/templates/flask_user/emails/invite_user_subject.txt b/app/templates/flask_user/emails/invite_user_subject.txt new file mode 100644 index 0000000..782705f --- /dev/null +++ b/app/templates/flask_user/emails/invite_user_subject.txt @@ -0,0 +1,3 @@ +{% extends 'flask_user/emails/base_subject.txt' %} + +{% block subject %}Invitation{% endblock %} diff --git a/app/templates/flask_user/emails/password_changed_message.html b/app/templates/flask_user/emails/password_changed_message.html new file mode 100644 index 0000000..8f62038 --- /dev/null +++ b/app/templates/flask_user/emails/password_changed_message.html @@ -0,0 +1,8 @@ +{% extends 'flask_user/emails/base_message.html' %} + +{% block message %} +

Your password has been changed.

+{% if user_manager.USER_ENABLE_FORGOT_PASSWORD %} +

If you did not initiate this password change, click here to reset it.

+{% endif %} +{% endblock %} diff --git a/app/templates/flask_user/emails/password_changed_message.txt b/app/templates/flask_user/emails/password_changed_message.txt new file mode 100644 index 0000000..b7448e6 --- /dev/null +++ b/app/templates/flask_user/emails/password_changed_message.txt @@ -0,0 +1,12 @@ +{% extends 'flask_user/emails/base_message.txt' %} + +{% block message %} +Your password has been changed. + +{% if user_manager.enable_forgot_password -%} +If you did not initiate this password change, click the link below to reset it. + {{ url_for('user.forgot_password', _external=True) }} +{% endif -%} +{% endblock %} + + diff --git a/app/templates/flask_user/emails/password_changed_subject.txt b/app/templates/flask_user/emails/password_changed_subject.txt new file mode 100644 index 0000000..1c3d89d --- /dev/null +++ b/app/templates/flask_user/emails/password_changed_subject.txt @@ -0,0 +1,3 @@ +{% extends 'flask_user/emails/base_subject.txt' %} + +{% block subject %}Your password has been changed{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/registered_message.html b/app/templates/flask_user/emails/registered_message.html new file mode 100644 index 0000000..a6a7396 --- /dev/null +++ b/app/templates/flask_user/emails/registered_message.html @@ -0,0 +1,16 @@ +{% extends 'flask_user/emails/base_message.html' %} + +{% block message %} + +

Thank you for registering with {{ app_name }}.

+ +{% if confirm_email_link -%} +

You will need to confirm your email next.

+ +

If you initiated this registration, please click on the link below:
+    Confirm your email.

+ +

If you did not initiate this registration, you may safely ignore this email.

+{%- endif %} + +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/registered_message.txt b/app/templates/flask_user/emails/registered_message.txt new file mode 100644 index 0000000..c4c7876 --- /dev/null +++ b/app/templates/flask_user/emails/registered_message.txt @@ -0,0 +1,15 @@ +{% extends 'flask_user/emails/base_message.txt' %} + +{% block message %} +Thank you for registering with {{ app_name }}. + +{% if confirm_email_link -%} +You will need to confirm your email next. + +If you initiated this registration, please visit the link below: + {{ confirm_email_link }} + +If you did not initiate this registration, you may safely ignore this email. + +{%- endif %} +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/registered_subject.txt b/app/templates/flask_user/emails/registered_subject.txt new file mode 100644 index 0000000..c9c6809 --- /dev/null +++ b/app/templates/flask_user/emails/registered_subject.txt @@ -0,0 +1,3 @@ +{% extends 'flask_user/emails/base_subject.txt' %} + +{% block subject %}{% if user_manager.enable_confirm_email and not user.confirmed_at %}Confirm your email{% else %}Thank you for registering{% endif %}{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/reset_password_message.html b/app/templates/flask_user/emails/reset_password_message.html new file mode 100644 index 0000000..45e9c4d --- /dev/null +++ b/app/templates/flask_user/emails/reset_password_message.html @@ -0,0 +1,12 @@ +{% extends 'flask_user/emails/base_message.html' %} + +{% block message %} + +

We have received your password reset request.

+ +

If you initiated this request, please click on the link below:
+    Reset password.

+ +

If you did not initiate this password reset, you may safely ignore this email.

+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/reset_password_message.txt b/app/templates/flask_user/emails/reset_password_message.txt new file mode 100644 index 0000000..265f485 --- /dev/null +++ b/app/templates/flask_user/emails/reset_password_message.txt @@ -0,0 +1,11 @@ +{% extends 'flask_user/emails/base_message.txt' %} + +{% block message %} +We have received your password reset request. + +If you initiated this request, please click on the link below: + {{ reset_password_link }} + +If you did not initiate this password reset, you may safely ignore this email. + +{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/reset_password_subject.txt b/app/templates/flask_user/emails/reset_password_subject.txt new file mode 100644 index 0000000..655b402 --- /dev/null +++ b/app/templates/flask_user/emails/reset_password_subject.txt @@ -0,0 +1,3 @@ +{% extends 'flask_user/emails/base_subject.txt' %} + +{% block subject %}Reset password{% endblock %} \ No newline at end of file diff --git a/app/templates/flask_user/emails/username_changed_message.html b/app/templates/flask_user/emails/username_changed_message.html new file mode 100644 index 0000000..f569fb2 --- /dev/null +++ b/app/templates/flask_user/emails/username_changed_message.html @@ -0,0 +1,6 @@ +{% extends 'flask_user/emails/base_message.html' %} + +{% block message %} +

Your username has been changed.

+

If you did not initiate this username change, please sign in (using your email address) and change your password.

+{% endblock %} diff --git a/app/templates/flask_user/emails/username_changed_message.txt b/app/templates/flask_user/emails/username_changed_message.txt new file mode 100644 index 0000000..1d4ee5c --- /dev/null +++ b/app/templates/flask_user/emails/username_changed_message.txt @@ -0,0 +1,10 @@ +{% extends 'flask_user/emails/base_message.txt' %} + +{% block message %} +Your username has been changed. + +If you did not initiate this username change, please sign in (using your email address) and change your password. + {{ url_for('user.login', _external=True) }} +{% endblock %} + + diff --git a/app/templates/flask_user/emails/username_changed_subject.txt b/app/templates/flask_user/emails/username_changed_subject.txt new file mode 100644 index 0000000..32a3602 --- /dev/null +++ b/app/templates/flask_user/emails/username_changed_subject.txt @@ -0,0 +1,3 @@ +{% extends 'flask_user/emails/base_subject.txt' %} + +{% block subject %}Your username has been changed{% endblock %} \ No newline at end of file