diff --git a/application/__init__.py b/application/__init__.py index 5644943..9c58210 100755 --- a/application/__init__.py +++ b/application/__init__.py @@ -2,17 +2,15 @@ from pathlib import Path from flask import Flask -from werkzeug.utils import import_string - from flask_admin import Admin -from flask_admin.contrib.sqla import ModelView from flask_login import LoginManager from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy from sqlalchemy import MetaData +from werkzeug.utils import import_string # Possible configurations -# TODO :: Make production the default at some point +# TODO: Make production the default at some point config_dict = { "production": "application.config.ProductionConfig", "testing": "application.config.TestConfig", @@ -50,19 +48,23 @@ def create_app(test_config=True): admininstrator.init_app(app) db.init_app(app) db.app = app - # TODO :: `render_as_batch` only for SQLite.. + # TODO: `render_as_batch` only for SQLite.. migrate.init_app(app, db, render_as_batch=True) login_manager.init_app(app) with app.app_context(): + # Import the Admin views + from application.admin.admin_routes import add_admin_views + + # Register Admin routes + add_admin_views(admininstrator) + # Import the the Blueprints - # (this has to happen inside the app context) from application.home.home_routes import home_bp from application.loggedin.loggedin_routes import loggedin_bp from application.signup.signup_routes import signup_bp from application.login.login_routes import login_bp - from application.admin.admin_routes import add_admin_views # Register Blueprints app.register_blueprint(home_bp, url_prefix='/') @@ -70,7 +72,4 @@ def create_app(test_config=True): app.register_blueprint(signup_bp) app.register_blueprint(login_bp) - # Admin Handling - add_admin_views(admininstrator) - return app diff --git a/application/admin/admin_routes.py b/application/admin/admin_routes.py index 0973021..e98ac72 100755 --- a/application/admin/admin_routes.py +++ b/application/admin/admin_routes.py @@ -1,4 +1,5 @@ from flask_admin.contrib.sqla import ModelView +from flask_login import login_required from application import db from application.models import ( @@ -14,7 +15,6 @@ User, UserLedger ) -from flask_login import login_required def add_admin_views(administrator): diff --git a/application/admin/templates/home.html b/application/admin/templates/home.html new file mode 100644 index 0000000..93c5413 --- /dev/null +++ b/application/admin/templates/home.html @@ -0,0 +1 @@ +{{ arg1 }} \ No newline at end of file diff --git a/application/forms.py b/application/forms.py index 1a5c2c2..04d6729 100755 --- a/application/forms.py +++ b/application/forms.py @@ -57,3 +57,13 @@ class LogInForm(FlaskForm): ) submit = SubmitField('Log In') + + +class SearchForm(FlaskForm): + """ + Class to encapsulate search form + """ + text = StringField( + 'Search terms', + validators=[DataRequired("Please enter your search terms.")] + ) \ No newline at end of file diff --git a/application/home/home_routes.py b/application/home/home_routes.py index 625f9ec..096fa12 100755 --- a/application/home/home_routes.py +++ b/application/home/home_routes.py @@ -4,13 +4,16 @@ home_bp = Blueprint('home_bp', __name__, template_folder='templates') -@home_bp.route('/', methods=['GET', 'POST']) +@home_bp.route('/', methods=['GET']) def home(): """ Homepage route. - TODO :: This needs to be updated. + GET: Redirects user to their dashboard if they are already logged in. """ + + # redirect a user to their dashboard + # if they are alreday logged in if current_user.is_authenticated: return redirect(url_for('loggedin_bp.dashboard')) @@ -25,11 +28,9 @@ def about(): """ About page route. - TODO :: This needs to be updated. + TODO: This needs to be updated. """ return render_template( 'index.html', title='About', - template='template main', - body="About" ) diff --git a/application/home/templates/index.html b/application/home/templates/index.html index 11b4eee..c38a3ae 100755 --- a/application/home/templates/index.html +++ b/application/home/templates/index.html @@ -1,9 +1,6 @@ {% extends "base.html" %} - {% block content %} - {% include "navigation-default.html" %} -
@@ -100,7 +97,5 @@

Bet smarter with groups.

- {% include "footer-default.html" %} - {% endblock %} \ No newline at end of file diff --git a/application/loggedin/loggedin_routes.py b/application/loggedin/loggedin_routes.py index fb05eeb..f0195a5 100755 --- a/application/loggedin/loggedin_routes.py +++ b/application/loggedin/loggedin_routes.py @@ -2,24 +2,29 @@ from flask_login import current_user, login_required from application import login_manager +from application.forms import SearchForm loggedin_bp = Blueprint('loggedin_bp', __name__, template_folder='templates') @login_manager.unauthorized_handler def unauthorized_callback(): + """Redirects an unaurhtorize user to login page.""" return redirect(url_for('login_bp.login')) -@loggedin_bp.route('/dashboard', methods=['GET', 'POST']) +@loggedin_bp.route('/dashboard', methods=['GET']) @login_required def dashboard(): """ Dashboard route. - TODO :: This will be updated. + TODO: This will be updated. """ + search_form = SearchForm() + return render_template( 'dashboard.html', - title='Dashboard' + title='Dashboard', + form=search_form ) diff --git a/application/loggedin/templates/dashboard-container-start.html b/application/loggedin/templates/dashboard-container-start.html index f39462e..5b5d9c1 100644 --- a/application/loggedin/templates/dashboard-container-start.html +++ b/application/loggedin/templates/dashboard-container-start.html @@ -1,2 +1,2 @@ -
-
\ No newline at end of file +
+
\ No newline at end of file diff --git a/application/loggedin/templates/dashboard.html b/application/loggedin/templates/dashboard.html index 2723d83..707d2ec 100755 --- a/application/loggedin/templates/dashboard.html +++ b/application/loggedin/templates/dashboard.html @@ -1,159 +1,152 @@ {% extends "base.html" %} - {% block content %} - {% include "navigation-loggedin.html" %} {% include "dashboard-container-start.html" %} {% include "sidebar-loggedin.html" %} - -
-
-

Dashboard

-
-
+
+
+

Dashboard

+
+
-
-
+ -
-
- - - -

Section title

-
- - + + + + +

Section title

+
+
+ - - - - - + + + + + - - + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - -
#HeaderHeaderHeaderHeader#HeaderHeaderHeaderHeader
1,001Loremipsumdolorsit1,001Loremipsumdolorsit
1,002ametconsecteturadipiscingelit1,002ametconsecteturadipiscingelit
1,003IntegernecodioPraesent1,003IntegernecodioPraesent
1,003liberoSedcursusante1,003liberoSedcursusante
1,004dapibusdiamSednisi1,004dapibusdiamSednisi
1,005Nullaquissemat1,005Nullaquissemat
1,006nibhelementumimperdietDuis1,006nibhelementumimperdietDuis
1,007sagittisipsumPraesentmauris1,007sagittisipsumPraesentmauris
1,008Fuscenectellussed1,008Fuscenectellussed
1,009auguesemperportaMauris1,009auguesemperportaMauris
1,010massaVestibulumlaciniaarcu1,010massaVestibulumlaciniaarcu
1,011egetnullaClassaptent1,011egetnullaClassaptent
1,012tacitisociosquadlitora1,012tacitisociosquadlitora
1,013torquentperconubianostra1,013torquentperconubianostra
1,014perinceptoshimenaeosCurabitur1,014perinceptoshimenaeosCurabitur
1,015sodalesligulainlibero1,015sodalesligulainlibero
-
-
- + + +
+ {% include "dashboard-container-end.html" %} {% include "footer-loggedin.html" %} - {% endblock %} \ No newline at end of file diff --git a/application/login/login_routes.py b/application/login/login_routes.py index 2f727af..d7be78d 100755 --- a/application/login/login_routes.py +++ b/application/login/login_routes.py @@ -12,7 +12,12 @@ def login(): """ End point for login page. + + GET: Redirects user to their dashboard if they are logged in. + POST: Attempts a login; if fail, reaches redirect back with error messages. """ + + # redirect user to dashboard if they are authenticated if current_user.is_authenticated: return redirect(url_for('loggedin_bp.dashboard')) @@ -40,12 +45,15 @@ def login(): flash('Invalid username/password combination') return redirect(url_for('login_bp.login')) + # notify of any form errors + for error_type, error_messages in login_form.errors.items(): + for message in error_messages: + flash(message) + return render_template( 'login_form.html', form=login_form, title='Log in', - template='template main', # template='login-page', - body="Log in" ) @@ -54,6 +62,8 @@ def login(): def logout(): """ End point for log out. + + GET: Logs out a user and redirects them to login page. """ logout_user() return redirect(url_for('login_bp.login')) diff --git a/application/login/templates/login_form.html b/application/login/templates/login_form.html index 060dc0d..f3f9c16 100755 --- a/application/login/templates/login_form.html +++ b/application/login/templates/login_form.html @@ -1,25 +1,20 @@ {% extends "base.html" %} - {% block content %} - {% include "navigation-default.html" %} -

Sign in


{% with messages = get_flashed_messages() %} - {% if messages %} - {% for message in messages %} -

{{ message }}

- {% endfor %} - {% endif %} + {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} {% endwith %}
- {{ form.csrf_token }} {{ form.hidden_tag() }} -
@@ -30,12 +25,8 @@

Sign in

{{ form.password(class='form-control', placeholder='Password', required=True, autocomplete='off', id='inputFirstName') }}
- {{ form.submit(class='btn btn-primary') }} -
- {% include "footer-default.html" %} - {% endblock %} \ No newline at end of file diff --git a/application/signup/signup_routes.py b/application/signup/signup_routes.py index 7a64911..476f042 100755 --- a/application/signup/signup_routes.py +++ b/application/signup/signup_routes.py @@ -10,16 +10,21 @@ def signup(): """ End point for sign up page. + + GET: Returns the sign up page. + POST: Attempts signup; if fail, redirect and display errors. If success, + redirect to signup succes page. + """ - form = SignUpForm() + signup_form = SignUpForm() - if form.validate_on_submit(): + if signup_form.validate_on_submit(): # get the form data, if submission was valid - first_name = form.first_name.data - last_name = form.last_name.data - email_address = form.email_address.data - password = form.password.data + first_name = signup_form.first_name.data + last_name = signup_form.last_name.data + email_address = signup_form.email_address.data + password = signup_form.password.data # check to see if this user already exists in the database if User.query.filter_by(email_address=email_address).first() is None: @@ -44,14 +49,14 @@ def signup(): flash('A user already exists with that email address.') return redirect(url_for('signup_bp.signup')) - # handle form errors - for error_type, error_messages in form.errors.items(): + # notify of any form errors + for error_type, error_messages in signup_form.errors.items(): for message in error_messages: flash(message) return render_template( 'signup_form.html', - form=form, + form=signup_form, title="Sign Up" ) diff --git a/application/signup/templates/signup_form.html b/application/signup/templates/signup_form.html index d46d67f..3de26d6 100644 --- a/application/signup/templates/signup_form.html +++ b/application/signup/templates/signup_form.html @@ -1,25 +1,20 @@ {% extends "base.html" %} - {% block content %} - {% include "navigation-default.html" %} -

Sign up


{% with messages = get_flashed_messages() %} - {% if messages %} - {% for message in messages %} -

{{ message }}

- {% endfor %} - {% endif %} + {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} {% endwith %}
- {{ form.csrf_token }} {{ form.hidden_tag() }} -
@@ -42,12 +37,9 @@

Sign up

{{ form.password_check(class='form-control', placeholder='Password again', autocomplete='off', required=True, id='inputPassword') }}
- {{ form.submit(class='btn btn-primary') }} -- + -
- {% include "footer-default.html" %} - {% endblock %} \ No newline at end of file diff --git a/application/signup/templates/signup_success.html b/application/signup/templates/signup_success.html index 76eecc0..1b687cf 100755 --- a/application/signup/templates/signup_success.html +++ b/application/signup/templates/signup_success.html @@ -1,14 +1,9 @@ {% extends "base.html" %} - {% block content %} - {% include "navigation-default.html" %} -

Congratulations! You've signed up!

- {% include "footer-default.html" %} - {% endblock %} \ No newline at end of file diff --git a/application/loggedin/templates/footer-loggedin.html b/application/templates/footer-loggedin.html similarity index 100% rename from application/loggedin/templates/footer-loggedin.html rename to application/templates/footer-loggedin.html diff --git a/application/templates/footer-search.html b/application/templates/footer-search.html new file mode 100644 index 0000000..528749a --- /dev/null +++ b/application/templates/footer-search.html @@ -0,0 +1,5 @@ +
+
+ Return to dashboard. +
+
\ No newline at end of file diff --git a/application/templates/meta.html b/application/templates/meta.html index 0cd4e48..e3960c7 100755 --- a/application/templates/meta.html +++ b/application/templates/meta.html @@ -1,9 +1,6 @@ {% block meta %} - - - + + + {% endblock %} \ No newline at end of file diff --git a/application/loggedin/templates/navigation-loggedin.html b/application/templates/navigation-loggedin.html similarity index 100% rename from application/loggedin/templates/navigation-loggedin.html rename to application/templates/navigation-loggedin.html diff --git a/application/templates/scripts.html b/application/templates/scripts.html index b046037..d187fc8 100755 --- a/application/templates/scripts.html +++ b/application/templates/scripts.html @@ -1,9 +1,7 @@ - + diff --git a/application/loggedin/templates/sidebar-loggedin.html b/application/templates/sidebar-loggedin.html similarity index 100% rename from application/loggedin/templates/sidebar-loggedin.html rename to application/templates/sidebar-loggedin.html diff --git a/notebooks/make_test_database.py b/notebooks/make_test_database.py deleted file mode 100755 index 83e7573..0000000 --- a/notebooks/make_test_database.py +++ /dev/null @@ -1,122 +0,0 @@ -import argparse -import os -from random import choice, randint -from string import ascii_lowercase, ascii_uppercase, punctuation - -import names - -from application import create_app, db -from application.config import TestConfig -from application.models import User - -POSSIBLE_CHARS = list(ascii_lowercase + ascii_uppercase + punctuation) - - -def make_fake_password(n_chars=10): - """ - Generate a fake, random password. The password - will start with an uppercase letter and end with - a lowercase letter. - - Parameters - ---------- - n_chars : int - The number of characters (3, 20) - """ - assert n_chars >= 3 and n_chars <= 20 - return ''.join([choice(ascii_uppercase)] + - [choice(POSSIBLE_CHARS) for _ in range(n_chars - 2)] + - [choice(ascii_lowercase)]) - - -def make_user_test_data(n=20, - add_fake_admin=True, - password_chars_range=(8, 15)): - """ - Make test user data - - Parameters - ---------- - n : int - The number of users. - Defaults to 20. - add_fake_admin : bool, optional - Whether to add a fake admin user. - Defaults to True. - password_chars_range : 2-tuple, optional - The range of possible password characters - Defaults to (8, 15). - """ - data = [] - start = 0 - if add_fake_admin: - # add the fake admin user to the database - data.append({'id': 0, - 'first_name': 'Admin', - 'last_name': 'User', - 'email_address': 'admin@admin.com', - 'password': 'admin'}) - start += 1 - - for i in range(start, n + start): - - # get random email address form first initial and last name - first_name = names.get_first_name() - last_name = names.get_last_name() - email = choice(['@yahoo.com', '@gmail.com', '@aol.com']) - email = ''.join([first_name.title(), last_name, email]) - - # create a fake password - password = make_fake_password(randint(password_chars_range[0], - password_chars_range[1])) - - data.append({'id': i, - 'first_name': first_name, - 'last_name': last_name, - 'email_address': email, - 'password': password}) - - return data - - -if __name__ == '__main__': - - # parse the arguments - parser = argparse.ArgumentParser(prog='make_test_database') - - parser.add_argument('-n', dest='n', default=20, - help="The number of records to create.") - - parser.add_argument('-v', '--verbose', action='store_true', - help="Whether to print the records at the end.") - - # TODO :: Add other arguments? - - args = parser.parse_args() - - # remove the existing database - if os.path.exists(TestConfig.db_path): - os.remove(TestConfig.db_path) - - # create test data - users = make_user_test_data(args.n) - - # create table - app = create_app(test_config=True) - db.create_all() - - # add the test data - for user in users: - - # we'll want to hash the password - password = user.pop('password') - user = User(**user) - user.set_password(password) - db.session.add(user) - - db.session.commit() - - if args.verbose: - print([{'id': u.id, - 'email': u.email_address, - 'pass': u.password} for u in User.query.all()]) diff --git a/notebooks/ui/index.html b/notebooks/ui/index.html deleted file mode 100644 index f82d249..0000000 --- a/notebooks/ui/index.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - Album example for Bootstrap - - - - - - - - - - - - -
-
Betfund
- - Sign up -
- -
- -
-
-

Bet smarter with groups.

-

Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.

-

- Our funds - Our strategies -

-
-
- -
-
- -
-
-
- Card image cap -
-

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

-
-
- -
-
-
-
-
-
-
- Card image cap -
-

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

-
-
- -
-
-
-
-
-
-
- Card image cap -
-

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

-
-
- -
-
-
-
-
- -
-
- Card image cap -
-

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

-
-
- -
-
-
-
-
-
-
- Card image cap -
-

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

-
-
- -
-
-
-
-
-
-
- Card image cap -
-

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

-
-
- -
-
-
-
-
-
-
-
- -
- - - - - - - - - - - -