From 53a5c2f9de6c82fb0a673de8f8528498292978ca Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Thu, 14 Sep 2023 10:47:06 -0600 Subject: [PATCH 01/38] Update script to remove old container --- scripts/invoke_in_container.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/invoke_in_container.sh b/scripts/invoke_in_container.sh index 35492c10..3643c10a 100755 --- a/scripts/invoke_in_container.sh +++ b/scripts/invoke_in_container.sh @@ -5,7 +5,7 @@ args="$@" # TODO: Do we need this? --user="${UID}" \ # Or this for wrapping the command? bash --login -c \ -docker-compose run \ +docker-compose run --rm \ usaon-vta-survey \ invoke $args From 9cfae4a9ab0362b2654706b0d8a154bde63fa4e3 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Fri, 15 Sep 2023 14:29:24 -0600 Subject: [PATCH 02/38] Comment out where environment variables were being set unintentionally --- tasks/test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tasks/test.py b/tasks/test.py index 75036ad4..c0cce63c 100644 --- a/tasks/test.py +++ b/tasks/test.py @@ -6,10 +6,14 @@ from .util import print_and_run +# TODO: Put this in a function where you want to run pytest +# WARNING: If uncommented this will cause major issues. +# (Will set the variables true for invoke tasks in all envs) +# Causes issues with DB in non-dev envs # NOTE: This is a hack, we want to be able to run pytest # without setting environment variables. -os.environ['USAON_VTA_DB_SQLITE'] = 'true' -os.environ['FLASK_DEBUG'] = 'true' +# os.environ['USAON_VTA_DB_SQLITE'] = 'true' +# os.environ['FLASK_DEBUG'] = 'true' PROJECT_DIR = Path(__file__).resolve().parent.parent sys.path.append(PROJECT_DIR) From ecaa06ced1658b8744ae8aa3b8201f4c096923f2 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Fri, 15 Sep 2023 14:38:22 -0600 Subject: [PATCH 03/38] Linting --- tasks/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tasks/test.py b/tasks/test.py index c0cce63c..3279faee 100644 --- a/tasks/test.py +++ b/tasks/test.py @@ -1,4 +1,3 @@ -import os import sys from pathlib import Path @@ -7,7 +6,7 @@ from .util import print_and_run # TODO: Put this in a function where you want to run pytest -# WARNING: If uncommented this will cause major issues. +# WARNING: If uncommented this will cause major issues. # (Will set the variables true for invoke tasks in all envs) # Causes issues with DB in non-dev envs # NOTE: This is a hack, we want to be able to run pytest From da5d4a79c445999b571efef73c47141c570fb8ab Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Fri, 15 Sep 2023 14:41:37 -0600 Subject: [PATCH 04/38] Add envs to mypy function --- tasks/test.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tasks/test.py b/tasks/test.py index 3279faee..e644482d 100644 --- a/tasks/test.py +++ b/tasks/test.py @@ -1,3 +1,4 @@ +import os import sys from pathlib import Path @@ -5,14 +6,6 @@ from .util import print_and_run -# TODO: Put this in a function where you want to run pytest -# WARNING: If uncommented this will cause major issues. -# (Will set the variables true for invoke tasks in all envs) -# Causes issues with DB in non-dev envs -# NOTE: This is a hack, we want to be able to run pytest -# without setting environment variables. -# os.environ['USAON_VTA_DB_SQLITE'] = 'true' -# os.environ['FLASK_DEBUG'] = 'true' PROJECT_DIR = Path(__file__).resolve().parent.parent sys.path.append(PROJECT_DIR) @@ -25,6 +18,11 @@ def typecheck(ctx): """Run mypy static type analysis.""" from usaon_vta_survey.constants.paths import PACKAGE_DIR + # NOTE: This is a hack, we want to be able to run pytest and mypy + # without setting environment variables. + os.environ['USAON_VTA_DB_SQLITE'] = 'true' + os.environ['FLASK_DEBUG'] = 'true' + print_and_run( f'cd {PROJECT_DIR} &&' f' mypy --config-file={PROJECT_DIR}/.mypy.ini {PACKAGE_DIR}', From 0e8fc1be6ae49dd9d95f84498dc5820bab9135bd Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Fri, 15 Sep 2023 15:10:20 -0600 Subject: [PATCH 05/38] Update envarrs to not be hacky --- tasks/test.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tasks/test.py b/tasks/test.py index e644482d..5d32eec9 100644 --- a/tasks/test.py +++ b/tasks/test.py @@ -1,4 +1,3 @@ -import os import sys from pathlib import Path @@ -18,14 +17,10 @@ def typecheck(ctx): """Run mypy static type analysis.""" from usaon_vta_survey.constants.paths import PACKAGE_DIR - # NOTE: This is a hack, we want to be able to run pytest and mypy - # without setting environment variables. - os.environ['USAON_VTA_DB_SQLITE'] = 'true' - os.environ['FLASK_DEBUG'] = 'true' - print_and_run( f'cd {PROJECT_DIR} &&' f' mypy --config-file={PROJECT_DIR}/.mypy.ini {PACKAGE_DIR}', + env={'USAON_VTA_DB_SQLITE': 'true', 'FLASK_DEBUG': 'true'}, ) print('🎉🦆 Type checking passed.') From fc8e0d52a856a0851dac83a4502be9d64f32b260 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 10:28:22 -0600 Subject: [PATCH 06/38] part 1 setting up blueprint --- usaon_vta_survey/__init__.py | 53 +++++++++++++---------------- usaon_vta_survey/model.py | 16 +++++++++ usaon_vta_survey/routes/__init__.py | 5 +++ 3 files changed, 45 insertions(+), 29 deletions(-) create mode 100644 usaon_vta_survey/model.py diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 49271085..3c63ba7c 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -3,41 +3,36 @@ from flask import Flask from flask_bootstrap import Bootstrap5 -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy import MetaData from sqlalchemy import inspect as sqla_inspect from werkzeug.middleware.proxy_fix import ProxyFix from usaon_vta_survey.constants.version import VERSION +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.db.connect import db_connstr from usaon_vta_survey.util.envvar import envvar_is_true __version__: Final[str] = VERSION -db = SQLAlchemy( - metadata=MetaData( - naming_convention={ - 'ix': 'ix_%(column_0_label)s', - 'uq': 'uq_%(table_name)s_%(column_0_name)s', - 'ck': 'ck_%(table_name)s_%(constraint_name)s', - 'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', - 'pk': 'pk_%(table_name)s', - } - ) -) - -app = Flask(__name__) -app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY', 'youcanneverguess') -app.config['LOGIN_DISABLED'] = envvar_is_true("USAON_VTA_LOGIN_DISABLED") -app.config['SQLALCHEMY_DATABASE_URI'] = db_connstr(app) -if envvar_is_true("USAON_VTA_PROXY"): - app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore - -db.init_app(app) -bootstrap = Bootstrap5(app) - -app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) - -# NOTE: This is a circular import, but it's specified by the Flask docs: -# https://flask.palletsprojects.com/en/3.1.x/patterns/packages/ -import usaon_vta_survey.routes # noqa: E402, F401 + +def create_app(): + """Create and configure the app.""" + # TODO: enable override config to test_config + # https://flask.palletsprojects.com/en/2.3.x/tutorial/factory/ + + app = Flask(__name__) + app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY', 'youcanneverguess') + app.config['LOGIN_DISABLED'] = envvar_is_true("USAON_VTA_LOGIN_DISABLED") + app.config['SQLALCHEMY_DATABASE_URI'] = db_connstr(app) + if envvar_is_true("USAON_VTA_PROXY"): + app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore + + from usaon_vta_survey.model import db + + db.init_app(app) + Bootstrap5(app) + + app.register_blueprint(root_blueprint) + + app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) + + return app diff --git a/usaon_vta_survey/model.py b/usaon_vta_survey/model.py new file mode 100644 index 00000000..55e66ad5 --- /dev/null +++ b/usaon_vta_survey/model.py @@ -0,0 +1,16 @@ +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import MetaData + +# TODO: Figure out where to put this. model.py? +# https://flask.palletsprojects.com/en/2.3.x/patterns/appfactories/#factories-extensions +db = SQLAlchemy( + metadata=MetaData( + naming_convention={ + 'ix': 'ix_%(column_0_label)s', + 'uq': 'uq_%(table_name)s_%(column_0_name)s', + 'ck': 'ck_%(table_name)s_%(constraint_name)s', + 'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', + 'pk': 'pk_%(table_name)s', + } + ) +) diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py index 88252595..003f8941 100644 --- a/usaon_vta_survey/routes/__init__.py +++ b/usaon_vta_survey/routes/__init__.py @@ -1,3 +1,6 @@ +from flask import Blueprint + +# may not need this anymore once setting up blueprints is complete in regular __init__ import usaon_vta_survey.routes.response import usaon_vta_survey.routes.response.applications import usaon_vta_survey.routes.response.data_products @@ -13,3 +16,5 @@ import usaon_vta_survey.routes.survey import usaon_vta_survey.routes.surveys import usaon_vta_survey.routes.users + +root_blueprint = Blueprint(prefix='/') From d018d8eb0f716bad9e71cab18905cd196f80d50f Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 11:20:55 -0600 Subject: [PATCH 07/38] WIP #2 adding application factory --- usaon_vta_survey/__init__.py | 19 +++++++++++++++++-- usaon_vta_survey/model.py | 16 ---------------- usaon_vta_survey/routes/login.py | 4 +++- usaon_vta_survey/routes/logout.py | 4 ++-- usaon_vta_survey/routes/response/__init__.py | 5 +++-- .../routes/response/applications.py | 7 +++++-- .../routes/response/data_products.py | 7 +++++-- .../routes/response/observing_systems.py | 7 +++++-- .../application_societal_benefit_area.py | 7 ++++--- .../relationships/data_product_application.py | 7 ++++--- .../observing_system_data_product.py | 5 +++-- usaon_vta_survey/routes/response/sbas.py | 5 +++-- usaon_vta_survey/routes/root.py | 4 ++-- usaon_vta_survey/routes/survey.py | 7 ++++--- usaon_vta_survey/routes/surveys.py | 4 ++-- usaon_vta_survey/routes/user.py | 4 +++- usaon_vta_survey/routes/users.py | 4 ++-- 17 files changed, 67 insertions(+), 49 deletions(-) delete mode 100644 usaon_vta_survey/model.py diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 3c63ba7c..c612abaa 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -3,6 +3,8 @@ from flask import Flask from flask_bootstrap import Bootstrap5 +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import MetaData from sqlalchemy import inspect as sqla_inspect from werkzeug.middleware.proxy_fix import ProxyFix @@ -14,6 +16,21 @@ __version__: Final[str] = VERSION +# TODO: Figure out where to put this. model.py? +# https://flask.palletsprojects.com/en/2.3.x/patterns/appfactories/#factories-extensions +db = SQLAlchemy( + metadata=MetaData( + naming_convention={ + 'ix': 'ix_%(column_0_label)s', + 'uq': 'uq_%(table_name)s_%(column_0_name)s', + 'ck': 'ck_%(table_name)s_%(constraint_name)s', + 'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', + 'pk': 'pk_%(table_name)s', + } + ) +) + + def create_app(): """Create and configure the app.""" # TODO: enable override config to test_config @@ -26,8 +43,6 @@ def create_app(): if envvar_is_true("USAON_VTA_PROXY"): app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore - from usaon_vta_survey.model import db - db.init_app(app) Bootstrap5(app) diff --git a/usaon_vta_survey/model.py b/usaon_vta_survey/model.py deleted file mode 100644 index 55e66ad5..00000000 --- a/usaon_vta_survey/model.py +++ /dev/null @@ -1,16 +0,0 @@ -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy import MetaData - -# TODO: Figure out where to put this. model.py? -# https://flask.palletsprojects.com/en/2.3.x/patterns/appfactories/#factories-extensions -db = SQLAlchemy( - metadata=MetaData( - naming_convention={ - 'ix': 'ix_%(column_0_label)s', - 'uq': 'uq_%(table_name)s_%(column_0_name)s', - 'ck': 'ck_%(table_name)s_%(constraint_name)s', - 'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', - 'pk': 'pk_%(table_name)s', - } - ) -) diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index 5a8474ab..d9bb3d70 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -6,6 +6,7 @@ from flask_login import login_user from usaon_vta_survey import app +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.db.user import ensure_user_exists blueprint = make_google_blueprint( @@ -13,10 +14,11 @@ client_secret=os.getenv('USAON_VTA_GOOGLE_CLIENT_SECRET'), scope=["profile", "email"], ) +# TODO: Figure out how to handle this with app factory app.register_blueprint(blueprint, url_prefix="/google_oauth") -@app.route("/login") +@root_blueprint.route("/login") def login(): if not google.authorized: return redirect(url_for("google.login")) diff --git a/usaon_vta_survey/routes/logout.py b/usaon_vta_survey/routes/logout.py index 79a43ae5..07f8d5c5 100644 --- a/usaon_vta_survey/routes/logout.py +++ b/usaon_vta_survey/routes/logout.py @@ -1,10 +1,10 @@ from flask import redirect from flask_login import logout_user -from usaon_vta_survey import app +from usaon_vta_survey.routes import root_blueprint -@app.route("/logout") +@root_blueprint.route("/logout") def logout(): logout_user() return redirect("/") diff --git a/usaon_vta_survey/routes/response/__init__.py b/usaon_vta_survey/routes/response/__init__.py index 66044508..a7597f58 100644 --- a/usaon_vta_survey/routes/response/__init__.py +++ b/usaon_vta_survey/routes/response/__init__.py @@ -1,11 +1,12 @@ from flask import render_template -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.models.tables import Response, Survey +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors -@app.route('/response/', methods=['GET']) +@root_blueprint.route('/response/', methods=['GET']) def view_response(survey_id: str): """View or create response to a survey.""" # Anyone should be able to view a survey diff --git a/usaon_vta_survey/routes/response/applications.py b/usaon_vta_survey/routes/response/applications.py index 25a4bbaf..a1b66193 100644 --- a/usaon_vta_survey/routes/response/applications.py +++ b/usaon_vta_survey/routes/response/applications.py @@ -1,13 +1,16 @@ from flask import redirect, render_template, request, url_for -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseApplication, Survey +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors from usaon_vta_survey.util.sankey import applications_sankey -@app.route('/response//applications', methods=['GET', 'POST']) +@root_blueprint.route( + '/response//applications', methods=['GET', 'POST'] +) def view_response_applications(survey_id: str): """View and add to applications associated with a response.""" Form = FORMS_BY_MODEL[ResponseApplication] diff --git a/usaon_vta_survey/routes/response/data_products.py b/usaon_vta_survey/routes/response/data_products.py index 93b307e7..827bbff1 100644 --- a/usaon_vta_survey/routes/response/data_products.py +++ b/usaon_vta_survey/routes/response/data_products.py @@ -1,12 +1,15 @@ from flask import redirect, render_template, request, url_for -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseDataProduct, Survey +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors -@app.route('/response//data_products', methods=['GET', 'POST']) +@root_blueprint.route( + '/response//data_products', methods=['GET', 'POST'] +) def view_response_data_products(survey_id: str): """View and add to data products associated with a response.""" Form = FORMS_BY_MODEL[ResponseDataProduct] diff --git a/usaon_vta_survey/routes/response/observing_systems.py b/usaon_vta_survey/routes/response/observing_systems.py index a672838c..b4b08f9a 100644 --- a/usaon_vta_survey/routes/response/observing_systems.py +++ b/usaon_vta_survey/routes/response/observing_systems.py @@ -1,13 +1,16 @@ from flask import redirect, render_template, request, url_for -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey._types import ObservingSystemType from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseObservingSystem, Survey +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors -@app.route('/response//observing_systems', methods=['GET', 'POST']) +@root_blueprint.route( + '/response//observing_systems', methods=['GET', 'POST'] +) def view_response_observing_systems(survey_id: str): """View and add to observing systems associated with a response.""" Form = FORMS_BY_MODEL[ResponseObservingSystem] diff --git a/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py b/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py index 5f8be7c0..945c018b 100644 --- a/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py +++ b/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py @@ -2,7 +2,7 @@ from flask_wtf import FlaskForm from wtforms import FormField -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ( ResponseApplication, @@ -10,6 +10,7 @@ ResponseSocietalBenefitArea, Survey, ) +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors @@ -130,7 +131,7 @@ def _request_args(request: Request) -> tuple[int | None, int | None]: return societal_benefit_area_id, application_id -@app.route( +@root_blueprint.route( '/response//application_societal_benefit_area_relationships', methods=['GET', 'POST'], ) @@ -232,7 +233,7 @@ class SuperForm(FlaskForm): ) -@app.route( +@root_blueprint.route( '/response//application_societal_benefit_area_relationships', methods=['GET', 'POST'], ) diff --git a/usaon_vta_survey/routes/response/relationships/data_product_application.py b/usaon_vta_survey/routes/response/relationships/data_product_application.py index 6d7259a6..8d47595e 100644 --- a/usaon_vta_survey/routes/response/relationships/data_product_application.py +++ b/usaon_vta_survey/routes/response/relationships/data_product_application.py @@ -2,7 +2,7 @@ from flask_wtf import FlaskForm from wtforms import FormField -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ( ResponseApplication, @@ -10,6 +10,7 @@ ResponseDataProductApplication, Survey, ) +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors @@ -121,7 +122,7 @@ def _request_args(request: Request) -> tuple[int | None, int | None]: return data_product_id, application_id -@app.route( +@root_blueprint.route( '/response//data_product_application_relationships', methods=['GET', 'POST'], ) @@ -218,7 +219,7 @@ class SuperForm(FlaskForm): relationship=response_data_product_application, ) - @app.route( + @root_blueprint.route( '/response//data_product_application_relationships', methods=['GET', 'POST'], ) diff --git a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py index 98855143..88356c47 100644 --- a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py +++ b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py @@ -2,7 +2,7 @@ from flask_wtf import FlaskForm from wtforms import FormField -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ( ResponseDataProduct, @@ -10,6 +10,7 @@ ResponseObservingSystemDataProduct, Survey, ) +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors @@ -125,7 +126,7 @@ def _request_args(request: Request) -> tuple[int | None, int | None]: return data_product_id, observing_system_id -@app.route( +@root_blueprint.route( '/response//observing_system_data_product_relationships', methods=['GET', 'POST'], ) diff --git a/usaon_vta_survey/routes/response/sbas.py b/usaon_vta_survey/routes/response/sbas.py index dc0bbaf0..d43458c6 100644 --- a/usaon_vta_survey/routes/response/sbas.py +++ b/usaon_vta_survey/routes/response/sbas.py @@ -1,16 +1,17 @@ from flask import redirect, render_template, request, url_for -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ( ResponseSocietalBenefitArea, SocietalBenefitArea, Survey, ) +from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors -@app.route( +@root_blueprint.route( '/response//societal_benefit_areas', methods=['GET', 'POST'] ) def view_response_sbas(survey_id: str): diff --git a/usaon_vta_survey/routes/root.py b/usaon_vta_survey/routes/root.py index 27bd09d9..4656b970 100644 --- a/usaon_vta_survey/routes/root.py +++ b/usaon_vta_survey/routes/root.py @@ -1,9 +1,9 @@ from flask import render_template -from usaon_vta_survey import app +from usaon_vta_survey.routes import root_blueprint -@app.route("/") +@root_blueprint.route("/") def root(): return render_template( 'home.html', diff --git a/usaon_vta_survey/routes/survey.py b/usaon_vta_survey/routes/survey.py index 1e6ff28e..c6cd06de 100644 --- a/usaon_vta_survey/routes/survey.py +++ b/usaon_vta_survey/routes/survey.py @@ -1,11 +1,12 @@ from flask import redirect, render_template, request, url_for -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import Survey +from usaon_vta_survey.routes import root_blueprint -@app.route('/survey/new', methods=['GET', 'POST']) +@root_blueprint.route('/survey/new', methods=['GET', 'POST']) def new_survey(): Form = FORMS_BY_MODEL[Survey] survey = Survey() @@ -25,7 +26,7 @@ def new_survey(): return render_template('new_survey.html', form=form) -@app.route('/survey/') +@root_blueprint.route('/survey/') def view_survey(survey_id: str): # Fetch survey by id survey = db.get_or_404(Survey, survey_id) diff --git a/usaon_vta_survey/routes/surveys.py b/usaon_vta_survey/routes/surveys.py index 62ca975a..223951a6 100644 --- a/usaon_vta_survey/routes/surveys.py +++ b/usaon_vta_survey/routes/surveys.py @@ -1,10 +1,10 @@ from flask import render_template -from usaon_vta_survey import app from usaon_vta_survey.models.tables import Survey +from usaon_vta_survey.routes import root_blueprint -@app.route('/surveys') +@root_blueprint.route('/surveys') def view_surveys(): surveys = Survey.query.order_by(Survey.created_timestamp).all() return render_template( diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 8b63cd3c..03b12069 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -4,6 +4,7 @@ from usaon_vta_survey import app, db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User +from usaon_vta_survey.routes import root_blueprint login_manager = LoginManager(app) @@ -13,6 +14,7 @@ def load_user(user_id: str) -> User: return User.query.get(user_id) +# TODO: figure out how to handle this with app factory if app.config["LOGIN_DISABLED"]: # HACK: Always logged in as dev user when login is disabled import flask_login.utils as flask_login_utils @@ -27,7 +29,7 @@ def _validate_role_change(user: User, form) -> None: raise RuntimeError("Only admins can edit users roles.") -@app.route('/user/', methods=['POST', 'GET']) +@root_blueprint.route('/user/', methods=['POST', 'GET']) def user(user_id: str): Form = FORMS_BY_MODEL[User] user = db.get_or_404(User, user_id) diff --git a/usaon_vta_survey/routes/users.py b/usaon_vta_survey/routes/users.py index 6f3a18c1..2af9aeba 100644 --- a/usaon_vta_survey/routes/users.py +++ b/usaon_vta_survey/routes/users.py @@ -1,10 +1,10 @@ from flask import render_template -from usaon_vta_survey import app from usaon_vta_survey.models.tables import User +from usaon_vta_survey.routes import root_blueprint -@app.route('/users') +@root_blueprint.route('/users') def view_users(): users = User.query.order_by(User.name).all() return render_template( From c017dbe802870131247805533fd9e59200816d4b Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 15:35:25 -0600 Subject: [PATCH 08/38] Fix circular import issue --- usaon_vta_survey/__init__.py | 5 ++++- usaon_vta_survey/routes/__init__.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index c612abaa..5543677d 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -9,7 +9,6 @@ from werkzeug.middleware.proxy_fix import ProxyFix from usaon_vta_survey.constants.version import VERSION -from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.db.connect import db_connstr from usaon_vta_survey.util.envvar import envvar_is_true @@ -43,9 +42,13 @@ def create_app(): if envvar_is_true("USAON_VTA_PROXY"): app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore + from usaon_vta_survey.model import db + db.init_app(app) Bootstrap5(app) + from usaon_vta_survey.routes import root_blueprint + app.register_blueprint(root_blueprint) app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py index 003f8941..3ef3e09d 100644 --- a/usaon_vta_survey/routes/__init__.py +++ b/usaon_vta_survey/routes/__init__.py @@ -1,5 +1,3 @@ -from flask import Blueprint - # may not need this anymore once setting up blueprints is complete in regular __init__ import usaon_vta_survey.routes.response import usaon_vta_survey.routes.response.applications @@ -17,4 +15,6 @@ import usaon_vta_survey.routes.surveys import usaon_vta_survey.routes.users +from flask import Blueprint + root_blueprint = Blueprint(prefix='/') From ce8dbf6a9b0ffe8a53e9bba2aae65fb1ce0009ff Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 15:42:37 -0600 Subject: [PATCH 09/38] fix blueprint --- usaon_vta_survey/routes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py index 3ef3e09d..cc32a960 100644 --- a/usaon_vta_survey/routes/__init__.py +++ b/usaon_vta_survey/routes/__init__.py @@ -17,4 +17,4 @@ from flask import Blueprint -root_blueprint = Blueprint(prefix='/') +root_blueprint = Blueprint('', __name__, url_prefix='/') From f29779e7f5d1ce7996175b65787b969feff77eb7 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 15:56:44 -0600 Subject: [PATCH 10/38] remove unused import --- usaon_vta_survey/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 5543677d..0875afe1 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -42,8 +42,6 @@ def create_app(): if envvar_is_true("USAON_VTA_PROXY"): app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore - from usaon_vta_survey.model import db - db.init_app(app) Bootstrap5(app) From 3b20204adecc71b03d809e8aa43e8eb9c13273e9 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 15:57:14 -0600 Subject: [PATCH 11/38] TEMPORARY resolve `app` errors - need to figure out true solution --- usaon_vta_survey/routes/login.py | 2 +- usaon_vta_survey/routes/user.py | 3 ++- usaon_vta_survey/util/db/setup.py | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index d9bb3d70..2c992f5d 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -5,8 +5,8 @@ from flask_dance.contrib.google import google, make_google_blueprint from flask_login import login_user -from usaon_vta_survey import app from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.util.db.setup import app from usaon_vta_survey.util.db.user import ensure_user_exists blueprint = make_google_blueprint( diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 03b12069..e1ddcf88 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -1,10 +1,11 @@ from flask import flash, render_template, request from flask_login import LoginManager, current_user -from usaon_vta_survey import app, db +from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.util.db.setup import app login_manager = LoginManager(app) diff --git a/usaon_vta_survey/util/db/setup.py b/usaon_vta_survey/util/db/setup.py index 2c3f6e22..96a06722 100644 --- a/usaon_vta_survey/util/db/setup.py +++ b/usaon_vta_survey/util/db/setup.py @@ -2,7 +2,7 @@ from sqlalchemy import MetaData from sqlalchemy.orm import Session -from usaon_vta_survey import app, db +from usaon_vta_survey import create_app, db from usaon_vta_survey.constants.roles import ROLES from usaon_vta_survey.constants.sba import IAOA_SBA_FRAMEWORK from usaon_vta_survey.constants.status import STATUSES @@ -15,6 +15,8 @@ ) from usaon_vta_survey.util.dev import DEV_USER +app = create_app() + def recreate_tables() -> None: # Drop all tables From cca5a3f3e2827c68083ae641e38130096e98b121 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 17:48:03 -0600 Subject: [PATCH 12/38] WIP different blueprint for responses --- usaon_vta_survey/__init__.py | 4 ++++ usaon_vta_survey/routes/__init__.py | 4 ++-- usaon_vta_survey/routes/response/__init__.py | 7 ++++--- usaon_vta_survey/routes/response/applications.py | 6 ++---- usaon_vta_survey/routes/response/data_products.py | 6 ++---- usaon_vta_survey/routes/response/observing_systems.py | 6 ++---- usaon_vta_survey/routes/response/sbas.py | 4 ++-- 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 0875afe1..a42bd708 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -49,6 +49,10 @@ def create_app(): app.register_blueprint(root_blueprint) + from usaon_vta_survey.routes import response + + app.register_blueprint(response.bp) + app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) return app diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py index cc32a960..f79da089 100644 --- a/usaon_vta_survey/routes/__init__.py +++ b/usaon_vta_survey/routes/__init__.py @@ -1,3 +1,5 @@ +from flask import Blueprint + # may not need this anymore once setting up blueprints is complete in regular __init__ import usaon_vta_survey.routes.response import usaon_vta_survey.routes.response.applications @@ -15,6 +17,4 @@ import usaon_vta_survey.routes.surveys import usaon_vta_survey.routes.users -from flask import Blueprint - root_blueprint = Blueprint('', __name__, url_prefix='/') diff --git a/usaon_vta_survey/routes/response/__init__.py b/usaon_vta_survey/routes/response/__init__.py index a7597f58..cc7bb752 100644 --- a/usaon_vta_survey/routes/response/__init__.py +++ b/usaon_vta_survey/routes/response/__init__.py @@ -1,12 +1,13 @@ -from flask import render_template +from flask import Blueprint, render_template from usaon_vta_survey import db from usaon_vta_survey.models.tables import Response, Survey -from usaon_vta_survey.routes import root_blueprint from usaon_vta_survey.util.authorization import limit_response_editors +bp = Blueprint('response', __name__, url_prefix='/respones') -@root_blueprint.route('/response/', methods=['GET']) + +@bp.route('/', methods=['GET']) def view_response(survey_id: str): """View or create response to a survey.""" # Anyone should be able to view a survey diff --git a/usaon_vta_survey/routes/response/applications.py b/usaon_vta_survey/routes/response/applications.py index a1b66193..7d18a302 100644 --- a/usaon_vta_survey/routes/response/applications.py +++ b/usaon_vta_survey/routes/response/applications.py @@ -3,14 +3,12 @@ from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseApplication, Survey -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors from usaon_vta_survey.util.sankey import applications_sankey -@root_blueprint.route( - '/response//applications', methods=['GET', 'POST'] -) +@bp.route('//applications', methods=['GET', 'POST']) def view_response_applications(survey_id: str): """View and add to applications associated with a response.""" Form = FORMS_BY_MODEL[ResponseApplication] diff --git a/usaon_vta_survey/routes/response/data_products.py b/usaon_vta_survey/routes/response/data_products.py index 827bbff1..502d7e92 100644 --- a/usaon_vta_survey/routes/response/data_products.py +++ b/usaon_vta_survey/routes/response/data_products.py @@ -3,13 +3,11 @@ from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseDataProduct, Survey -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors -@root_blueprint.route( - '/response//data_products', methods=['GET', 'POST'] -) +@bp.route('/response//data_products', methods=['GET', 'POST']) def view_response_data_products(survey_id: str): """View and add to data products associated with a response.""" Form = FORMS_BY_MODEL[ResponseDataProduct] diff --git a/usaon_vta_survey/routes/response/observing_systems.py b/usaon_vta_survey/routes/response/observing_systems.py index b4b08f9a..85396e61 100644 --- a/usaon_vta_survey/routes/response/observing_systems.py +++ b/usaon_vta_survey/routes/response/observing_systems.py @@ -4,13 +4,11 @@ from usaon_vta_survey._types import ObservingSystemType from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseObservingSystem, Survey -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors -@root_blueprint.route( - '/response//observing_systems', methods=['GET', 'POST'] -) +@bp.route('/response//observing_systems', methods=['GET', 'POST']) def view_response_observing_systems(survey_id: str): """View and add to observing systems associated with a response.""" Form = FORMS_BY_MODEL[ResponseObservingSystem] diff --git a/usaon_vta_survey/routes/response/sbas.py b/usaon_vta_survey/routes/response/sbas.py index d43458c6..6c5da863 100644 --- a/usaon_vta_survey/routes/response/sbas.py +++ b/usaon_vta_survey/routes/response/sbas.py @@ -7,11 +7,11 @@ SocietalBenefitArea, Survey, ) -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors -@root_blueprint.route( +@bp.route( '/response//societal_benefit_areas', methods=['GET', 'POST'] ) def view_response_sbas(survey_id: str): From 1b8deea6b9798905e06d5a82ddfb3d0d164ae12f Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 18 Sep 2023 17:52:21 -0600 Subject: [PATCH 13/38] WIP continue `response` blueprint update --- .../relationships/application_societal_benefit_area.py | 10 +++++----- .../response/relationships/data_product_application.py | 10 +++++----- .../relationships/observing_system_data_product.py | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py b/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py index 945c018b..80033c11 100644 --- a/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py +++ b/usaon_vta_survey/routes/response/relationships/application_societal_benefit_area.py @@ -10,7 +10,7 @@ ResponseSocietalBenefitArea, Survey, ) -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors @@ -131,8 +131,8 @@ def _request_args(request: Request) -> tuple[int | None, int | None]: return societal_benefit_area_id, application_id -@root_blueprint.route( - '/response//application_societal_benefit_area_relationships', +@bp.route( + '//application_societal_benefit_area_relationships', methods=['GET', 'POST'], ) def view_response_application_societal_benefit_area_relationships(survey_id: str): @@ -233,8 +233,8 @@ class SuperForm(FlaskForm): ) -@root_blueprint.route( - '/response//application_societal_benefit_area_relationships', +@bp.route( + '//application_societal_benefit_area_relationships', methods=['GET', 'POST'], ) def delete_response_application_societal_benefit_area_relationship(survey_id: str): diff --git a/usaon_vta_survey/routes/response/relationships/data_product_application.py b/usaon_vta_survey/routes/response/relationships/data_product_application.py index 8d47595e..cbbc92d1 100644 --- a/usaon_vta_survey/routes/response/relationships/data_product_application.py +++ b/usaon_vta_survey/routes/response/relationships/data_product_application.py @@ -10,7 +10,7 @@ ResponseDataProductApplication, Survey, ) -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors @@ -122,8 +122,8 @@ def _request_args(request: Request) -> tuple[int | None, int | None]: return data_product_id, application_id -@root_blueprint.route( - '/response//data_product_application_relationships', +@bp.route( + '//data_product_application_relationships', methods=['GET', 'POST'], ) def view_response_data_product_application_relationships(survey_id: str): @@ -219,8 +219,8 @@ class SuperForm(FlaskForm): relationship=response_data_product_application, ) - @root_blueprint.route( - '/response//data_product_application_relationships', + @bp.route( + '//data_product_application_relationships', methods=['GET', 'POST'], ) def delete_response_application_societal_benefit_area_relationship(survey_id: str): diff --git a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py index 88356c47..299c2c13 100644 --- a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py +++ b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py @@ -10,7 +10,7 @@ ResponseObservingSystemDataProduct, Survey, ) -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors @@ -126,8 +126,8 @@ def _request_args(request: Request) -> tuple[int | None, int | None]: return data_product_id, observing_system_id -@root_blueprint.route( - '/response//observing_system_data_product_relationships', +@bp.route( + '//observing_system_data_product_relationships', methods=['GET', 'POST'], ) def view_response_observing_system_data_product_relationships(survey_id: str): From 82a1891427d81ddf5ff8754ec87792dfbfab9bee Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 10:02:25 -0600 Subject: [PATCH 14/38] WIP able to startup app, still getting a blueprint error --- usaon_vta_survey/__init__.py | 4 ++-- usaon_vta_survey/routes/__init__.py | 35 +++++++++++++++-------------- usaon_vta_survey/routes/login.py | 5 +++-- usaon_vta_survey/routes/logout.py | 2 +- usaon_vta_survey/routes/root.py | 6 ++--- usaon_vta_survey/routes/survey.py | 2 +- usaon_vta_survey/routes/surveys.py | 2 +- usaon_vta_survey/routes/user.py | 2 +- usaon_vta_survey/routes/users.py | 2 +- 9 files changed, 31 insertions(+), 29 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index a42bd708..ec7694f0 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -45,9 +45,9 @@ def create_app(): db.init_app(app) Bootstrap5(app) - from usaon_vta_survey.routes import root_blueprint + from usaon_vta_survey.routes import root - app.register_blueprint(root_blueprint) + app.register_blueprint(root.root_blueprint) from usaon_vta_survey.routes import response diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py index f79da089..ff351e6d 100644 --- a/usaon_vta_survey/routes/__init__.py +++ b/usaon_vta_survey/routes/__init__.py @@ -1,20 +1,21 @@ -from flask import Blueprint +# from flask import Blueprint # may not need this anymore once setting up blueprints is complete in regular __init__ -import usaon_vta_survey.routes.response -import usaon_vta_survey.routes.response.applications -import usaon_vta_survey.routes.response.data_products -import usaon_vta_survey.routes.response.observing_systems -import usaon_vta_survey.routes.response.sbas -import usaon_vta_survey.routes.response.relationships.application_societal_benefit_area -import usaon_vta_survey.routes.response.relationships.data_product_application -import usaon_vta_survey.routes.response.relationships.observing_system_data_product -import usaon_vta_survey.routes.root -import usaon_vta_survey.routes.login -import usaon_vta_survey.routes.logout -import usaon_vta_survey.routes.user -import usaon_vta_survey.routes.survey -import usaon_vta_survey.routes.surveys -import usaon_vta_survey.routes.users +# import usaon_vta_survey.routes.response +# import usaon_vta_survey.routes.response.applications +# import usaon_vta_survey.routes.response.data_products +# import usaon_vta_survey.routes.response.observing_systems +# import usaon_vta_survey.routes.response.sbas +# import usaon_vta_survey.routes.response +# .relationships.application_societal_benefit_area +# import usaon_vta_survey.routes.response.relationships.data_product_application +# import usaon_vta_survey.routes.response.relationships.observing_system_data_product +# import usaon_vta_survey.routes.root +# import usaon_vta_survey.routes.login +# import usaon_vta_survey.routes.logout +# import usaon_vta_survey.routes.user +# import usaon_vta_survey.routes.survey +# import usaon_vta_survey.routes.surveys +# import usaon_vta_survey.routes.users -root_blueprint = Blueprint('', __name__, url_prefix='/') +# root_blueprint = Blueprint('root', __name__, url_prefix='/') diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index 2c992f5d..37c18a28 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -5,7 +5,7 @@ from flask_dance.contrib.google import google, make_google_blueprint from flask_login import login_user -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.root import root_blueprint from usaon_vta_survey.util.db.setup import app from usaon_vta_survey.util.db.user import ensure_user_exists @@ -15,6 +15,7 @@ scope=["profile", "email"], ) # TODO: Figure out how to handle this with app factory +# NOTE: moving this into `usaon-vta-survey/__init` app.register_blueprint(blueprint, url_prefix="/google_oauth") @@ -31,7 +32,7 @@ def login(): return redirect('/') -@app.before_request +@root_blueprint.before_request def before_request(): """Handle expired google tokens as a pre-request hook.""" if token := (s := session).get('google_oauth_token'): diff --git a/usaon_vta_survey/routes/logout.py b/usaon_vta_survey/routes/logout.py index 07f8d5c5..eef956d7 100644 --- a/usaon_vta_survey/routes/logout.py +++ b/usaon_vta_survey/routes/logout.py @@ -1,7 +1,7 @@ from flask import redirect from flask_login import logout_user -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.root import root_blueprint @root_blueprint.route("/logout") diff --git a/usaon_vta_survey/routes/root.py b/usaon_vta_survey/routes/root.py index 4656b970..62e55451 100644 --- a/usaon_vta_survey/routes/root.py +++ b/usaon_vta_survey/routes/root.py @@ -1,9 +1,9 @@ -from flask import render_template +from flask import Blueprint, render_template -from usaon_vta_survey.routes import root_blueprint +root_blueprint = Blueprint('root', __name__, url_prefix='/') -@root_blueprint.route("/") +@root_blueprint.route('') def root(): return render_template( 'home.html', diff --git a/usaon_vta_survey/routes/survey.py b/usaon_vta_survey/routes/survey.py index c6cd06de..63f4d7fb 100644 --- a/usaon_vta_survey/routes/survey.py +++ b/usaon_vta_survey/routes/survey.py @@ -3,7 +3,7 @@ from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import Survey -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.root import root_blueprint @root_blueprint.route('/survey/new', methods=['GET', 'POST']) diff --git a/usaon_vta_survey/routes/surveys.py b/usaon_vta_survey/routes/surveys.py index 223951a6..09382122 100644 --- a/usaon_vta_survey/routes/surveys.py +++ b/usaon_vta_survey/routes/surveys.py @@ -1,7 +1,7 @@ from flask import render_template from usaon_vta_survey.models.tables import Survey -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.root import root_blueprint @root_blueprint.route('/surveys') diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index e1ddcf88..3ae2eaf8 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -4,7 +4,7 @@ from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.root import root_blueprint from usaon_vta_survey.util.db.setup import app login_manager = LoginManager(app) diff --git a/usaon_vta_survey/routes/users.py b/usaon_vta_survey/routes/users.py index 2af9aeba..180d2a20 100644 --- a/usaon_vta_survey/routes/users.py +++ b/usaon_vta_survey/routes/users.py @@ -1,7 +1,7 @@ from flask import render_template from usaon_vta_survey.models.tables import User -from usaon_vta_survey.routes import root_blueprint +from usaon_vta_survey.routes.root import root_blueprint @root_blueprint.route('/users') From 43913df79f7b8d8933f5f26abcefc6108d83eaa8 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 10:12:54 -0600 Subject: [PATCH 15/38] Remove prefix from route --- usaon_vta_survey/routes/response/data_products.py | 2 +- usaon_vta_survey/routes/response/observing_systems.py | 2 +- usaon_vta_survey/routes/response/sbas.py | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/usaon_vta_survey/routes/response/data_products.py b/usaon_vta_survey/routes/response/data_products.py index 502d7e92..5df01bb4 100644 --- a/usaon_vta_survey/routes/response/data_products.py +++ b/usaon_vta_survey/routes/response/data_products.py @@ -7,7 +7,7 @@ from usaon_vta_survey.util.authorization import limit_response_editors -@bp.route('/response//data_products', methods=['GET', 'POST']) +@bp.route('//data_products', methods=['GET', 'POST']) def view_response_data_products(survey_id: str): """View and add to data products associated with a response.""" Form = FORMS_BY_MODEL[ResponseDataProduct] diff --git a/usaon_vta_survey/routes/response/observing_systems.py b/usaon_vta_survey/routes/response/observing_systems.py index 85396e61..eb4064cf 100644 --- a/usaon_vta_survey/routes/response/observing_systems.py +++ b/usaon_vta_survey/routes/response/observing_systems.py @@ -8,7 +8,7 @@ from usaon_vta_survey.util.authorization import limit_response_editors -@bp.route('/response//observing_systems', methods=['GET', 'POST']) +@bp.route('//observing_systems', methods=['GET', 'POST']) def view_response_observing_systems(survey_id: str): """View and add to observing systems associated with a response.""" Form = FORMS_BY_MODEL[ResponseObservingSystem] diff --git a/usaon_vta_survey/routes/response/sbas.py b/usaon_vta_survey/routes/response/sbas.py index 6c5da863..9dbbd8e1 100644 --- a/usaon_vta_survey/routes/response/sbas.py +++ b/usaon_vta_survey/routes/response/sbas.py @@ -11,9 +11,7 @@ from usaon_vta_survey.util.authorization import limit_response_editors -@bp.route( - '/response//societal_benefit_areas', methods=['GET', 'POST'] -) +@bp.route('//societal_benefit_areas', methods=['GET', 'POST']) def view_response_sbas(survey_id: str): """View and add to observing systems associated with a response.""" sbas = SocietalBenefitArea.query.all() From af2192a7e677b0be9681cada35e038a65b5c1c66 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 10:42:02 -0600 Subject: [PATCH 16/38] Fix import --- usaon_vta_survey/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index ec7694f0..bc0c9a9e 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -45,9 +45,9 @@ def create_app(): db.init_app(app) Bootstrap5(app) - from usaon_vta_survey.routes import root + from usaon_vta_survey.routes.root import root_blueprint - app.register_blueprint(root.root_blueprint) + app.register_blueprint(root_blueprint) from usaon_vta_survey.routes import response From 97b1451a630957811cf847349e1aba53307e5418 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 12:57:24 -0600 Subject: [PATCH 17/38] WIP - current blocker is login manager --- usaon_vta_survey/__init__.py | 13 ++++++++++-- usaon_vta_survey/routes/__init__.py | 21 ------------------- usaon_vta_survey/routes/login.py | 6 +++--- usaon_vta_survey/routes/response/__init__.py | 2 +- .../routes/response/applications.py | 4 +++- usaon_vta_survey/routes/root.py | 4 ++-- usaon_vta_survey/routes/surveys.py | 7 ++++--- usaon_vta_survey/routes/user.py | 7 +++---- usaon_vta_survey/routes/users.py | 7 ++++--- .../templates/macros/nav_buttons.j2 | 8 +++---- 10 files changed, 35 insertions(+), 44 deletions(-) delete mode 100644 usaon_vta_survey/routes/__init__.py diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index bc0c9a9e..262f1ef3 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -3,6 +3,7 @@ from flask import Flask from flask_bootstrap import Bootstrap5 +from flask_login import LoginManager from flask_sqlalchemy import SQLAlchemy from sqlalchemy import MetaData from sqlalchemy import inspect as sqla_inspect @@ -44,15 +45,23 @@ def create_app(): db.init_app(app) Bootstrap5(app) + LoginManager(app) - from usaon_vta_survey.routes.root import root_blueprint + from usaon_vta_survey.routes.root import root_bp - app.register_blueprint(root_blueprint) + app.register_blueprint(root_bp) + from usaon_vta_survey.routes.surveys import surveys_bp + + app.register_blueprint(surveys_bp) + from usaon_vta_survey.routes.users import users_bp + + app.register_blueprint(users_bp) from usaon_vta_survey.routes import response app.register_blueprint(response.bp) + # breakpoint() app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) return app diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py deleted file mode 100644 index ff351e6d..00000000 --- a/usaon_vta_survey/routes/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# from flask import Blueprint - -# may not need this anymore once setting up blueprints is complete in regular __init__ -# import usaon_vta_survey.routes.response -# import usaon_vta_survey.routes.response.applications -# import usaon_vta_survey.routes.response.data_products -# import usaon_vta_survey.routes.response.observing_systems -# import usaon_vta_survey.routes.response.sbas -# import usaon_vta_survey.routes.response -# .relationships.application_societal_benefit_area -# import usaon_vta_survey.routes.response.relationships.data_product_application -# import usaon_vta_survey.routes.response.relationships.observing_system_data_product -# import usaon_vta_survey.routes.root -# import usaon_vta_survey.routes.login -# import usaon_vta_survey.routes.logout -# import usaon_vta_survey.routes.user -# import usaon_vta_survey.routes.survey -# import usaon_vta_survey.routes.surveys -# import usaon_vta_survey.routes.users - -# root_blueprint = Blueprint('root', __name__, url_prefix='/') diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index 37c18a28..c24d20bd 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -5,7 +5,7 @@ from flask_dance.contrib.google import google, make_google_blueprint from flask_login import login_user -from usaon_vta_survey.routes.root import root_blueprint +from usaon_vta_survey.routes import login_bp from usaon_vta_survey.util.db.setup import app from usaon_vta_survey.util.db.user import ensure_user_exists @@ -19,7 +19,7 @@ app.register_blueprint(blueprint, url_prefix="/google_oauth") -@root_blueprint.route("/login") +@login_bp.route("") def login(): if not google.authorized: return redirect(url_for("google.login")) @@ -32,7 +32,7 @@ def login(): return redirect('/') -@root_blueprint.before_request +@login_bp.before_request def before_request(): """Handle expired google tokens as a pre-request hook.""" if token := (s := session).get('google_oauth_token'): diff --git a/usaon_vta_survey/routes/response/__init__.py b/usaon_vta_survey/routes/response/__init__.py index cc7bb752..e6837eaa 100644 --- a/usaon_vta_survey/routes/response/__init__.py +++ b/usaon_vta_survey/routes/response/__init__.py @@ -4,7 +4,7 @@ from usaon_vta_survey.models.tables import Response, Survey from usaon_vta_survey.util.authorization import limit_response_editors -bp = Blueprint('response', __name__, url_prefix='/respones') +bp = Blueprint('response', __name__, url_prefix='/response') @bp.route('/', methods=['GET']) diff --git a/usaon_vta_survey/routes/response/applications.py b/usaon_vta_survey/routes/response/applications.py index 7d18a302..1795f437 100644 --- a/usaon_vta_survey/routes/response/applications.py +++ b/usaon_vta_survey/routes/response/applications.py @@ -24,7 +24,9 @@ def view_response_applications(survey_id: str): db.session.add(response_application) db.session.commit() - return redirect(url_for('view_response_applications', survey_id=survey.id)) + return redirect( + url_for('response.view_response_applications', survey_id=survey.id) + ) form = Form(obj=response_application) return render_template( diff --git a/usaon_vta_survey/routes/root.py b/usaon_vta_survey/routes/root.py index 62e55451..14b4fdc5 100644 --- a/usaon_vta_survey/routes/root.py +++ b/usaon_vta_survey/routes/root.py @@ -1,9 +1,9 @@ from flask import Blueprint, render_template -root_blueprint = Blueprint('root', __name__, url_prefix='/') +root_bp = Blueprint('root', __name__, url_prefix='/') -@root_blueprint.route('') +@root_bp.route('') def root(): return render_template( 'home.html', diff --git a/usaon_vta_survey/routes/surveys.py b/usaon_vta_survey/routes/surveys.py index 09382122..844f2867 100644 --- a/usaon_vta_survey/routes/surveys.py +++ b/usaon_vta_survey/routes/surveys.py @@ -1,10 +1,11 @@ -from flask import render_template +from flask import Blueprint, render_template from usaon_vta_survey.models.tables import Survey -from usaon_vta_survey.routes.root import root_blueprint +surveys_bp = Blueprint('surveys', __name__, url_prefix='/surveys') -@root_blueprint.route('/surveys') + +@surveys_bp.route('') def view_surveys(): surveys = Survey.query.order_by(Survey.created_timestamp).all() return render_template( diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 3ae2eaf8..957e0258 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -1,5 +1,5 @@ from flask import flash, render_template, request -from flask_login import LoginManager, current_user +from flask_login import current_user from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL @@ -7,10 +7,9 @@ from usaon_vta_survey.routes.root import root_blueprint from usaon_vta_survey.util.db.setup import app -login_manager = LoginManager(app) - -@login_manager.user_loader +# TODO: discover if this is porrible with app factory +# @login_manager.user_loader def load_user(user_id: str) -> User: return User.query.get(user_id) diff --git a/usaon_vta_survey/routes/users.py b/usaon_vta_survey/routes/users.py index 180d2a20..feea2a72 100644 --- a/usaon_vta_survey/routes/users.py +++ b/usaon_vta_survey/routes/users.py @@ -1,10 +1,11 @@ -from flask import render_template +from flask import Blueprint, render_template from usaon_vta_survey.models.tables import User -from usaon_vta_survey.routes.root import root_blueprint +users_bp = Blueprint('users', __name__, url_prefix='/users') -@root_blueprint.route('/users') + +@users_bp.route('') def view_users(): users = User.query.order_by(User.name).all() return render_template( diff --git a/usaon_vta_survey/templates/macros/nav_buttons.j2 b/usaon_vta_survey/templates/macros/nav_buttons.j2 index a724eb63..78f194b5 100644 --- a/usaon_vta_survey/templates/macros/nav_buttons.j2 +++ b/usaon_vta_survey/templates/macros/nav_buttons.j2 @@ -1,18 +1,18 @@ {% macro nav_buttons(current_user) -%} {% from "bootstrap5/nav.html" import render_nav_item %} - {{ render_nav_item("root", "Home")}} - {{ render_nav_item("view_surveys", "Surveys")}} + {{ render_nav_item("root.root", "Home")}} + {{ render_nav_item("surveys.view_surveys", "Surveys")}} {% if current_user.is_authenticated %} {{ render_nav_item("user", "Profile", user_id=current_user.id)}} {% if current_user.role_id=="admin" %} - {{ render_nav_item("view_users", "Users")}} + {{ render_nav_item("users.view_users", "Users")}} {{ render_nav_item("logout", "Log out")}} {% else %} {{ render_nav_item("logout", "Log out")}} {% endif %} {% else %} - {{ render_nav_item("login", "Log in")}} + {{ render_nav_item("login.login", "Log in")}} {% endif %} {%- endmacro -%} From 724c533869e7abb2c630a6f2e57411033de7f908 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 13:49:44 -0600 Subject: [PATCH 18/38] LoginManager --- usaon_vta_survey/routes/user.py | 8 +++++--- usaon_vta_survey/templates/macros/nav_buttons.j2 | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 957e0258..1965da49 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -1,5 +1,5 @@ from flask import flash, render_template, request -from flask_login import current_user +from flask_login import LoginManager, current_user from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL @@ -7,9 +7,11 @@ from usaon_vta_survey.routes.root import root_blueprint from usaon_vta_survey.util.db.setup import app +login_manager = LoginManager(app) -# TODO: discover if this is porrible with app factory -# @login_manager.user_loader + +# TODO: discover if this is possible with app factory +@login_manager.user_loader def load_user(user_id: str) -> User: return User.query.get(user_id) diff --git a/usaon_vta_survey/templates/macros/nav_buttons.j2 b/usaon_vta_survey/templates/macros/nav_buttons.j2 index 78f194b5..e8be0056 100644 --- a/usaon_vta_survey/templates/macros/nav_buttons.j2 +++ b/usaon_vta_survey/templates/macros/nav_buttons.j2 @@ -4,7 +4,7 @@ {{ render_nav_item("root.root", "Home")}} {{ render_nav_item("surveys.view_surveys", "Surveys")}} {% if current_user.is_authenticated %} - {{ render_nav_item("user", "Profile", user_id=current_user.id)}} + {{ render_nav_item("root.user", "Profile", user_id=current_user.id)}} {% if current_user.role_id=="admin" %} {{ render_nav_item("users.view_users", "Users")}} From 90e69b4985f79d33562b1b85b7255303bf3dfeb7 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 14:13:02 -0600 Subject: [PATCH 19/38] Login manager working --- usaon_vta_survey/__init__.py | 7 ++++- usaon_vta_survey/routes/user.py | 29 +++++++++---------- .../templates/macros/nav_buttons.j2 | 6 ++-- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 262f1ef3..7959fc70 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -30,7 +30,10 @@ ) ) +login_manager = LoginManager() + +@login_manager.user_loader def create_app(): """Create and configure the app.""" # TODO: enable override config to test_config @@ -45,7 +48,7 @@ def create_app(): db.init_app(app) Bootstrap5(app) - LoginManager(app) + login_manager.init_app(app) from usaon_vta_survey.routes.root import root_bp @@ -56,7 +59,9 @@ def create_app(): from usaon_vta_survey.routes.users import users_bp app.register_blueprint(users_bp) + from usaon_vta_survey.routes.login import blueprint + app.register_blueprint(blueprint, url_prefix="/google_oauth") from usaon_vta_survey.routes import response app.register_blueprint(response.bp) diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 1965da49..4493fb10 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -1,29 +1,23 @@ -from flask import flash, render_template, request -from flask_login import LoginManager, current_user +from flask import Blueprint, flash, render_template, request +from flask_login import current_user from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User -from usaon_vta_survey.routes.root import root_blueprint -from usaon_vta_survey.util.db.setup import app -login_manager = LoginManager(app) - -# TODO: discover if this is possible with app factory -@login_manager.user_loader def load_user(user_id: str) -> User: return User.query.get(user_id) # TODO: figure out how to handle this with app factory -if app.config["LOGIN_DISABLED"]: - # HACK: Always logged in as dev user when login is disabled - import flask_login.utils as flask_login_utils - - from usaon_vta_survey.util.dev import DEV_USER - - flask_login_utils._get_user = lambda: DEV_USER +# if app.config["LOGIN_DISABLED"]: +# # HACK: Always logged in as dev user when login is disabled +# import flask_login.utils as flask_login_utils +# +# from usaon_vta_survey.util.dev import DEV_USER +# +# flask_login_utils._get_user = lambda: DEV_USER def _validate_role_change(user: User, form) -> None: @@ -31,7 +25,10 @@ def _validate_role_change(user: User, form) -> None: raise RuntimeError("Only admins can edit users roles.") -@root_blueprint.route('/user/', methods=['POST', 'GET']) +user_bp = Blueprint('user', __name__, url_prefix='/user') + + +@user_bp.route('/user/', methods=['POST', 'GET']) def user(user_id: str): Form = FORMS_BY_MODEL[User] user = db.get_or_404(User, user_id) diff --git a/usaon_vta_survey/templates/macros/nav_buttons.j2 b/usaon_vta_survey/templates/macros/nav_buttons.j2 index e8be0056..a1cc21b6 100644 --- a/usaon_vta_survey/templates/macros/nav_buttons.j2 +++ b/usaon_vta_survey/templates/macros/nav_buttons.j2 @@ -4,13 +4,13 @@ {{ render_nav_item("root.root", "Home")}} {{ render_nav_item("surveys.view_surveys", "Surveys")}} {% if current_user.is_authenticated %} - {{ render_nav_item("root.user", "Profile", user_id=current_user.id)}} + {{ render_nav_item("user.user", "Profile", user_id=current_user.id)}} {% if current_user.role_id=="admin" %} {{ render_nav_item("users.view_users", "Users")}} - {{ render_nav_item("logout", "Log out")}} + {{ render_nav_item("root.logout", "Log out")}} {% else %} - {{ render_nav_item("logout", "Log out")}} + {{ render_nav_item("root.logout", "Log out")}} {% endif %} {% else %} {{ render_nav_item("login.login", "Log in")}} From e619c6f22e7847620941ddba5b38b50985d2ff10 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 14:19:40 -0600 Subject: [PATCH 20/38] Login blueprint --- usaon_vta_survey/routes/login.py | 9 +++------ usaon_vta_survey/routes/logout.py | 4 ++-- usaon_vta_survey/templates/macros/nav_buttons.j2 | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index c24d20bd..0c2a7358 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -1,12 +1,10 @@ import os import time -from flask import redirect, session, url_for +from flask import Blueprint, redirect, session, url_for from flask_dance.contrib.google import google, make_google_blueprint from flask_login import login_user -from usaon_vta_survey.routes import login_bp -from usaon_vta_survey.util.db.setup import app from usaon_vta_survey.util.db.user import ensure_user_exists blueprint = make_google_blueprint( @@ -14,9 +12,8 @@ client_secret=os.getenv('USAON_VTA_GOOGLE_CLIENT_SECRET'), scope=["profile", "email"], ) -# TODO: Figure out how to handle this with app factory -# NOTE: moving this into `usaon-vta-survey/__init` -app.register_blueprint(blueprint, url_prefix="/google_oauth") + +login_bp = Blueprint('login', __name__, url_prefix='/login') @login_bp.route("") diff --git a/usaon_vta_survey/routes/logout.py b/usaon_vta_survey/routes/logout.py index eef956d7..fe76d067 100644 --- a/usaon_vta_survey/routes/logout.py +++ b/usaon_vta_survey/routes/logout.py @@ -1,10 +1,10 @@ from flask import redirect from flask_login import logout_user -from usaon_vta_survey.routes.root import root_blueprint +from usaon_vta_survey.routes.root import root_bp -@root_blueprint.route("/logout") +@root_bp.route("/logout") def logout(): logout_user() return redirect("/") diff --git a/usaon_vta_survey/templates/macros/nav_buttons.j2 b/usaon_vta_survey/templates/macros/nav_buttons.j2 index a1cc21b6..870f2e5a 100644 --- a/usaon_vta_survey/templates/macros/nav_buttons.j2 +++ b/usaon_vta_survey/templates/macros/nav_buttons.j2 @@ -13,6 +13,6 @@ {{ render_nav_item("root.logout", "Log out")}} {% endif %} {% else %} - {{ render_nav_item("login.login", "Log in")}} + {{ render_nav_item("google.login", "Log in")}} {% endif %} {%- endmacro -%} From 471175ad5ee45ec92897866d36c00c679c9ea7f0 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 17:43:27 -0600 Subject: [PATCH 21/38] Add survey blueprint and remove `app` from user.py --- usaon_vta_survey/__init__.py | 3 +++ usaon_vta_survey/routes/survey.py | 9 +++++---- usaon_vta_survey/routes/user.py | 15 ++++++++------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 7959fc70..d265d353 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -56,6 +56,9 @@ def create_app(): from usaon_vta_survey.routes.surveys import surveys_bp app.register_blueprint(surveys_bp) + from usaon_vta_survey.routes.survey import survey_bp + + app.register_blueprint(survey_bp) from usaon_vta_survey.routes.users import users_bp app.register_blueprint(users_bp) diff --git a/usaon_vta_survey/routes/survey.py b/usaon_vta_survey/routes/survey.py index 63f4d7fb..94609e10 100644 --- a/usaon_vta_survey/routes/survey.py +++ b/usaon_vta_survey/routes/survey.py @@ -1,12 +1,13 @@ -from flask import redirect, render_template, request, url_for +from flask import Blueprint, redirect, render_template, request, url_for from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import Survey -from usaon_vta_survey.routes.root import root_blueprint +survey_bp = Blueprint('survey', '/survey') -@root_blueprint.route('/survey/new', methods=['GET', 'POST']) + +@survey_bp.route('/new', methods=['GET', 'POST']) def new_survey(): Form = FORMS_BY_MODEL[Survey] survey = Survey() @@ -26,7 +27,7 @@ def new_survey(): return render_template('new_survey.html', form=form) -@root_blueprint.route('/survey/') +@survey_bp.route('/') def view_survey(survey_id: str): # Fetch survey by id survey = db.get_or_404(Survey, survey_id) diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 4493fb10..6f616d8b 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -4,6 +4,7 @@ from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User +from usaon_vta_survey.util.envvar import envvar_is_true def load_user(user_id: str) -> User: @@ -11,13 +12,13 @@ def load_user(user_id: str) -> User: # TODO: figure out how to handle this with app factory -# if app.config["LOGIN_DISABLED"]: -# # HACK: Always logged in as dev user when login is disabled -# import flask_login.utils as flask_login_utils -# -# from usaon_vta_survey.util.dev import DEV_USER -# -# flask_login_utils._get_user = lambda: DEV_USER +if envvar_is_true("USAON_VTA_LOGIN_DISABLED"): + # HACK: Always logged in as dev user when login is disabled + import flask_login.utils as flask_login_utils + + from usaon_vta_survey.util.dev import DEV_USER + + flask_login_utils._get_user = lambda: DEV_USER def _validate_role_change(user: User, form) -> None: From f018cbca072e6c9673ed7ac10cd477736e5f78a8 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 17:49:34 -0600 Subject: [PATCH 22/38] Update task/db to use create_app function --- tasks/db.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tasks/db.py b/tasks/db.py index ceb5c9b5..2777f8a6 100644 --- a/tasks/db.py +++ b/tasks/db.py @@ -13,9 +13,11 @@ def init(ctx, load=True): ) return - from usaon_vta_survey import app + from usaon_vta_survey import create_app from usaon_vta_survey.util.db.setup import recreate_tables as recreate_tables_ + app = create_app() + # TODO: "Are you sure" confirmation? with app.app_context(): print('Recreating tables...') @@ -36,8 +38,10 @@ def load_reference_data(ctx): ) return - from usaon_vta_survey import app + from usaon_vta_survey import create_app from usaon_vta_survey.util.db.setup import populate_reference_data + app = create_app() + with app.app_context(): populate_reference_data() From e6304f6092c548d6e990cd4eda5bc78e39fefbc5 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 17:55:19 -0600 Subject: [PATCH 23/38] Import login_bp --- usaon_vta_survey/__init__.py | 3 ++- usaon_vta_survey/templates/macros/nav_buttons.j2 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index d265d353..a525434a 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -62,8 +62,9 @@ def create_app(): from usaon_vta_survey.routes.users import users_bp app.register_blueprint(users_bp) - from usaon_vta_survey.routes.login import blueprint + from usaon_vta_survey.routes.login import blueprint, login_bp + app.register_blueprint(login_bp) app.register_blueprint(blueprint, url_prefix="/google_oauth") from usaon_vta_survey.routes import response diff --git a/usaon_vta_survey/templates/macros/nav_buttons.j2 b/usaon_vta_survey/templates/macros/nav_buttons.j2 index 870f2e5a..a1cc21b6 100644 --- a/usaon_vta_survey/templates/macros/nav_buttons.j2 +++ b/usaon_vta_survey/templates/macros/nav_buttons.j2 @@ -13,6 +13,6 @@ {{ render_nav_item("root.logout", "Log out")}} {% endif %} {% else %} - {{ render_nav_item("google.login", "Log in")}} + {{ render_nav_item("login.login", "Log in")}} {% endif %} {%- endmacro -%} From f929ee94918a1e70849d58f68ae0af29b8246a48 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 19 Sep 2023 18:16:44 -0600 Subject: [PATCH 24/38] Attempt at getting login working - not successful --- usaon_vta_survey/__init__.py | 11 ++++++++++- usaon_vta_survey/routes/login.py | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index a525434a..e93061aa 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -1,7 +1,8 @@ import os +import time from typing import Final -from flask import Flask +from flask import Flask, session from flask_bootstrap import Bootstrap5 from flask_login import LoginManager from flask_sqlalchemy import SQLAlchemy @@ -46,6 +47,14 @@ def create_app(): if envvar_is_true("USAON_VTA_PROXY"): app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore + @app.before_request + def before_request(): + """Handle expired google tokens as a pre-request hook.""" + if token := (s := session).get('google_oauth_token'): + print("Token expiring in", token['expires_at'] - time.time()) + if time.time() >= token['expires_at']: + del s['google_oauth_token'] + db.init_app(app) Bootstrap5(app) login_manager.init_app(app) diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index 0c2a7358..d24739c7 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -1,7 +1,6 @@ import os -import time -from flask import Blueprint, redirect, session, url_for +from flask import Blueprint, redirect, url_for from flask_dance.contrib.google import google, make_google_blueprint from flask_login import login_user @@ -24,15 +23,17 @@ def login(): assert resp.ok, resp.text user = ensure_user_exists(resp.json()) + # breakpoint() login_user(user) return redirect('/') -@login_bp.before_request -def before_request(): - """Handle expired google tokens as a pre-request hook.""" - if token := (s := session).get('google_oauth_token'): - print("Token expiring in", token['expires_at'] - time.time()) - if time.time() >= token['expires_at']: - del s['google_oauth_token'] +# this may be the login issue +# @app.before_request +# def before_request(): +# """Handle expired google tokens as a pre-request hook.""" +# if token := (s := session).get('google_oauth_token'): +# print("Token expiring in", token['expires_at'] - time.time()) +# if time.time() >= token['expires_at']: +# del s['google_oauth_token'] From e9e563f46e8dc1f46437bcf15fddaf8b105ebe92 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 14:38:40 -0600 Subject: [PATCH 25/38] Temporarily remove ability to bypass googleSSO move google login blueprint --- docker-compose.dev.yml | 3 +++ usaon_vta_survey/__init__.py | 4 +++- usaon_vta_survey/routes/google.py | 9 +++++++++ usaon_vta_survey/routes/login.py | 11 ++--------- usaon_vta_survey/routes/user.py | 18 ++++++++---------- 5 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 usaon_vta_survey/routes/google.py diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index b17be19d..50418c2e 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -23,6 +23,9 @@ services: - "USAON_VTA_DB_SQLITE=true" # Enable the in-browser debugger: - "FLASK_DEBUG=True" + # Creds for talking to Google: + - "USAON_VTA_GOOGLE_CLIENT_ID=${USAON_VTA_GOOGLE_CLIENT_ID:?USAON_VTA_GOOGLE_CLIENT_ID must be set}" + - "USAON_VTA_GOOGLE_CLIENT_SECRET=${USAON_VTA_GOOGLE_CLIENT_SECRET:?USAON_VTA_GOOGLE_CLIENT_SECRET must be set}" # Development DANGER ZONE: Do not use the below settings except for diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index e93061aa..cf7321c6 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -71,9 +71,11 @@ def before_request(): from usaon_vta_survey.routes.users import users_bp app.register_blueprint(users_bp) - from usaon_vta_survey.routes.login import blueprint, login_bp + from usaon_vta_survey.routes.login import login_bp app.register_blueprint(login_bp) + from usaon_vta_survey.routes.google import blueprint + app.register_blueprint(blueprint, url_prefix="/google_oauth") from usaon_vta_survey.routes import response diff --git a/usaon_vta_survey/routes/google.py b/usaon_vta_survey/routes/google.py new file mode 100644 index 00000000..5b3baf5d --- /dev/null +++ b/usaon_vta_survey/routes/google.py @@ -0,0 +1,9 @@ +import os + +from flask_dance.contrib.google import make_google_blueprint + +blueprint = make_google_blueprint( + client_id=os.getenv('USAON_VTA_GOOGLE_CLIENT_ID'), + client_secret=os.getenv('USAON_VTA_GOOGLE_CLIENT_SECRET'), + scope=["profile", "email"], +) diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index d24739c7..9a9cff90 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -1,23 +1,16 @@ -import os - from flask import Blueprint, redirect, url_for -from flask_dance.contrib.google import google, make_google_blueprint +from flask_dance.contrib.google import google from flask_login import login_user from usaon_vta_survey.util.db.user import ensure_user_exists -blueprint = make_google_blueprint( - client_id=os.getenv('USAON_VTA_GOOGLE_CLIENT_ID'), - client_secret=os.getenv('USAON_VTA_GOOGLE_CLIENT_SECRET'), - scope=["profile", "email"], -) - login_bp = Blueprint('login', __name__, url_prefix='/login') @login_bp.route("") def login(): if not google.authorized: + # breakpoint() return redirect(url_for("google.login")) resp = google.get("/oauth2/v2/userinfo") assert resp.ok, resp.text diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index 6f616d8b..a7b75172 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -4,21 +4,19 @@ from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User -from usaon_vta_survey.util.envvar import envvar_is_true def load_user(user_id: str) -> User: return User.query.get(user_id) -# TODO: figure out how to handle this with app factory -if envvar_is_true("USAON_VTA_LOGIN_DISABLED"): - # HACK: Always logged in as dev user when login is disabled - import flask_login.utils as flask_login_utils - - from usaon_vta_survey.util.dev import DEV_USER - - flask_login_utils._get_user = lambda: DEV_USER +# if envvar_is_true("USAON_VTA_LOGIN_DISABLED"): +# # HACK: Always logged in as dev user when login is disabled +# import flask_login.utils as flask_login_utils +# +# from usaon_vta_survey.util.dev import DEV_USER +# +# flask_login_utils._get_user = lambda: DEV_USER def _validate_role_change(user: User, form) -> None: @@ -29,7 +27,7 @@ def _validate_role_change(user: User, form) -> None: user_bp = Blueprint('user', __name__, url_prefix='/user') -@user_bp.route('/user/', methods=['POST', 'GET']) +@user_bp.route('/', methods=['POST', 'GET']) def user(user_id: str): Form = FORMS_BY_MODEL[User] user = db.get_or_404(User, user_id) From 5a7ebfc0552e0d6fa257e824b85dcca0f8494ce1 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 15:22:32 -0600 Subject: [PATCH 26/38] Remove unused `app` in this file --- usaon_vta_survey/util/db/setup.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/usaon_vta_survey/util/db/setup.py b/usaon_vta_survey/util/db/setup.py index 96a06722..47ce3284 100644 --- a/usaon_vta_survey/util/db/setup.py +++ b/usaon_vta_survey/util/db/setup.py @@ -2,7 +2,7 @@ from sqlalchemy import MetaData from sqlalchemy.orm import Session -from usaon_vta_survey import create_app, db +from usaon_vta_survey import db from usaon_vta_survey.constants.roles import ROLES from usaon_vta_survey.constants.sba import IAOA_SBA_FRAMEWORK from usaon_vta_survey.constants.status import STATUSES @@ -15,8 +15,6 @@ ) from usaon_vta_survey.util.dev import DEV_USER -app = create_app() - def recreate_tables() -> None: # Drop all tables @@ -44,8 +42,8 @@ def populate_reference_data() -> None: init_roles(db.session) init_statuses(db.session) - if app.config["LOGIN_DISABLED"]: - init_dev_user(db.session) + # if app.config["LOGIN_DISABLED"]: + # init_dev_user(db.session) logger.info('Reference data loaded.') From 92e273875d5cc9e1474fcd692e2e5de2e195fa4b Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 18:01:18 -0600 Subject: [PATCH 27/38] Fix login related error and call current_app as recommended by docs --- usaon_vta_survey/__init__.py | 19 +++++++++++-------- usaon_vta_survey/routes/user.py | 5 ----- usaon_vta_survey/util/db/setup.py | 5 +++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index cf7321c6..0eef1ed8 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -31,10 +31,7 @@ ) ) -login_manager = LoginManager() - -@login_manager.user_loader def create_app(): """Create and configure the app.""" # TODO: enable override config to test_config @@ -47,6 +44,17 @@ def create_app(): if envvar_is_true("USAON_VTA_PROXY"): app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1) # type: ignore + db.init_app(app) + Bootstrap5(app) + login_manager = LoginManager() + login_manager.init_app(app) + + from usaon_vta_survey.models.tables import User + + @login_manager.user_loader + def load_user(user_id: str) -> User: + return User.query.get(user_id) + @app.before_request def before_request(): """Handle expired google tokens as a pre-request hook.""" @@ -55,10 +63,6 @@ def before_request(): if time.time() >= token['expires_at']: del s['google_oauth_token'] - db.init_app(app) - Bootstrap5(app) - login_manager.init_app(app) - from usaon_vta_survey.routes.root import root_bp app.register_blueprint(root_bp) @@ -81,7 +85,6 @@ def before_request(): app.register_blueprint(response.bp) - # breakpoint() app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) return app diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index a7b75172..a4252d51 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -5,11 +5,6 @@ from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User - -def load_user(user_id: str) -> User: - return User.query.get(user_id) - - # if envvar_is_true("USAON_VTA_LOGIN_DISABLED"): # # HACK: Always logged in as dev user when login is disabled # import flask_login.utils as flask_login_utils diff --git a/usaon_vta_survey/util/db/setup.py b/usaon_vta_survey/util/db/setup.py index 47ce3284..4be3105b 100644 --- a/usaon_vta_survey/util/db/setup.py +++ b/usaon_vta_survey/util/db/setup.py @@ -1,3 +1,4 @@ +from flask import current_app from loguru import logger from sqlalchemy import MetaData from sqlalchemy.orm import Session @@ -42,8 +43,8 @@ def populate_reference_data() -> None: init_roles(db.session) init_statuses(db.session) - # if app.config["LOGIN_DISABLED"]: - # init_dev_user(db.session) + if current_app.config["LOGIN_DISABLED"]: + init_dev_user(db.session) logger.info('Reference data loaded.') From 25241bd887d4ee1ff7ace8a9f64e7e097f03bd07 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 18:05:57 -0600 Subject: [PATCH 28/38] Add logout blueprint --- usaon_vta_survey/__init__.py | 6 ++++++ usaon_vta_survey/routes/logout.py | 6 +++--- usaon_vta_survey/templates/macros/nav_buttons.j2 | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 0eef1ed8..538658d4 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -72,12 +72,18 @@ def before_request(): from usaon_vta_survey.routes.survey import survey_bp app.register_blueprint(survey_bp) + from usaon_vta_survey.routes.user import user_bp + + app.register_blueprint(user_bp) from usaon_vta_survey.routes.users import users_bp app.register_blueprint(users_bp) from usaon_vta_survey.routes.login import login_bp app.register_blueprint(login_bp) + from usaon_vta_survey.routes.logout import logout_bp + + app.register_blueprint(logout_bp) from usaon_vta_survey.routes.google import blueprint app.register_blueprint(blueprint, url_prefix="/google_oauth") diff --git a/usaon_vta_survey/routes/logout.py b/usaon_vta_survey/routes/logout.py index fe76d067..feb21ce5 100644 --- a/usaon_vta_survey/routes/logout.py +++ b/usaon_vta_survey/routes/logout.py @@ -1,10 +1,10 @@ -from flask import redirect +from flask import Blueprint, redirect from flask_login import logout_user -from usaon_vta_survey.routes.root import root_bp +logout_bp = Blueprint('logout', __name__, url_prefix='/logout') -@root_bp.route("/logout") +@logout_bp.route("") def logout(): logout_user() return redirect("/") diff --git a/usaon_vta_survey/templates/macros/nav_buttons.j2 b/usaon_vta_survey/templates/macros/nav_buttons.j2 index a1cc21b6..ef88b008 100644 --- a/usaon_vta_survey/templates/macros/nav_buttons.j2 +++ b/usaon_vta_survey/templates/macros/nav_buttons.j2 @@ -8,9 +8,9 @@ {% if current_user.role_id=="admin" %} {{ render_nav_item("users.view_users", "Users")}} - {{ render_nav_item("root.logout", "Log out")}} + {{ render_nav_item("logout.logout", "Log out")}} {% else %} - {{ render_nav_item("root.logout", "Log out")}} + {{ render_nav_item("logout.logout", "Log out")}} {% endif %} {% else %} {{ render_nav_item("login.login", "Log in")}} From d7c50cbd8b7d848ed521d7d62089518d5ae26221 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 18:09:51 -0600 Subject: [PATCH 29/38] Update users template to include blueprint --- usaon_vta_survey/templates/users.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usaon_vta_survey/templates/users.html b/usaon_vta_survey/templates/users.html index 3ac461ef..54e87f98 100644 --- a/usaon_vta_survey/templates/users.html +++ b/usaon_vta_survey/templates/users.html @@ -7,7 +7,7 @@

{% block title %}Users{% endblock %}

{% if not current_user.role_id=='admin' %}

You don't belong here! This page is for admins only.

{% else %} - {{ render_table(users, show_actions=True, edit_url=('user', [('user_id',':id')])) }} + {{ render_table(users, show_actions=True, edit_url=('user.user', [('user_id',':id')])) }} {% endif %} From 53a51771cd6926f9f7ebc34a4250463bbb8e41e7 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 18:15:11 -0600 Subject: [PATCH 30/38] Add survey blueprint to redirect url --- usaon_vta_survey/routes/survey.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usaon_vta_survey/routes/survey.py b/usaon_vta_survey/routes/survey.py index 94609e10..505f388d 100644 --- a/usaon_vta_survey/routes/survey.py +++ b/usaon_vta_survey/routes/survey.py @@ -4,7 +4,7 @@ from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import Survey -survey_bp = Blueprint('survey', '/survey') +survey_bp = Blueprint('survey', __name__, url_prefix='/survey') @survey_bp.route('/new', methods=['GET', 'POST']) @@ -21,7 +21,7 @@ def new_survey(): db.session.add(survey) db.session.commit() - return redirect(url_for('view_survey', survey_id=survey.id)) + return redirect(url_for('survey.view_survey', survey_id=survey.id)) form = Form(obj=survey) return render_template('new_survey.html', form=form) From 376c23e3a61386af3fe8be0d3d323d7a1526b05e Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 18:16:14 -0600 Subject: [PATCH 31/38] Add response blueprint --- usaon_vta_survey/templates/survey.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usaon_vta_survey/templates/survey.html b/usaon_vta_survey/templates/survey.html index af09c46e..e2d4d640 100644 --- a/usaon_vta_survey/templates/survey.html +++ b/usaon_vta_survey/templates/survey.html @@ -14,13 +14,13 @@

Notes

Response

{% if survey.response_id %} - + View response

Response by: {{ survey.response.created_by.email}}

{% else %}

No response available.

- + Create response From ac3fcf0b9ae4fe53b282d8313889d9707485978f Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 18:18:25 -0600 Subject: [PATCH 32/38] Start adding response blueprint - response sub pages need their own bp --- usaon_vta_survey/templates/response/base.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usaon_vta_survey/templates/response/base.html b/usaon_vta_survey/templates/response/base.html index bf0f1a3a..d82c5461 100644 --- a/usaon_vta_survey/templates/response/base.html +++ b/usaon_vta_survey/templates/response/base.html @@ -9,7 +9,7 @@

{% block title %}Response to: {{survey.title}}{% endblock %}

  • - + Response home
  • @@ -39,7 +39,7 @@

    {% block title %}Response to: {{survey.title}}{% endblock %}

  • - + View survey config
  • From 1b1e1019d3586d5d61bbd941a7db90b28f3c1e1e Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 20 Sep 2023 21:30:36 -0600 Subject: [PATCH 33/38] view surveys blueprint --- usaon_vta_survey/templates/surveys.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usaon_vta_survey/templates/surveys.html b/usaon_vta_survey/templates/surveys.html index f7bf1dae..b2562bee 100644 --- a/usaon_vta_survey/templates/surveys.html +++ b/usaon_vta_survey/templates/surveys.html @@ -41,7 +41,7 @@

    {% block title %}Surveys{% endblock %}

    {{survey.status.id}} {{survey.private}} - {{render_icon('eye-fill')}} + {{render_icon('eye-fill')}} From af5ca07b5490d93bdcfc89894e80b8ce4578fbde Mon Sep 17 00:00:00 2001 From: Robyn Marowitz <103532760+rmarow@users.noreply.github.com> Date: Sun, 24 Sep 2023 20:34:26 -0600 Subject: [PATCH 34/38] remove breakpoint Co-authored-by: Matt Fisher --- usaon_vta_survey/routes/login.py | 1 - 1 file changed, 1 deletion(-) diff --git a/usaon_vta_survey/routes/login.py b/usaon_vta_survey/routes/login.py index 9a9cff90..93cdd48b 100644 --- a/usaon_vta_survey/routes/login.py +++ b/usaon_vta_survey/routes/login.py @@ -10,7 +10,6 @@ @login_bp.route("") def login(): if not google.authorized: - # breakpoint() return redirect(url_for("google.login")) resp = google.get("/oauth2/v2/userinfo") assert resp.ok, resp.text From af48db010be9302bf73fb792178ba3e479fbf62f Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Sun, 24 Sep 2023 20:36:13 -0600 Subject: [PATCH 35/38] Add comments regarding issue #144 --- docker-compose.dev.yml | 1 + usaon_vta_survey/routes/user.py | 1 + 2 files changed, 2 insertions(+) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 50418c2e..1f7dcf6b 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -23,6 +23,7 @@ services: - "USAON_VTA_DB_SQLITE=true" # Enable the in-browser debugger: - "FLASK_DEBUG=True" + # NOTE: This is temporary until issue #144 is resolved # Creds for talking to Google: - "USAON_VTA_GOOGLE_CLIENT_ID=${USAON_VTA_GOOGLE_CLIENT_ID:?USAON_VTA_GOOGLE_CLIENT_ID must be set}" - "USAON_VTA_GOOGLE_CLIENT_SECRET=${USAON_VTA_GOOGLE_CLIENT_SECRET:?USAON_VTA_GOOGLE_CLIENT_SECRET must be set}" diff --git a/usaon_vta_survey/routes/user.py b/usaon_vta_survey/routes/user.py index a4252d51..d7ba2a19 100644 --- a/usaon_vta_survey/routes/user.py +++ b/usaon_vta_survey/routes/user.py @@ -5,6 +5,7 @@ from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import User +# NOTE: This is temporary until issue #144 is resolved # if envvar_is_true("USAON_VTA_LOGIN_DISABLED"): # # HACK: Always logged in as dev user when login is disabled # import flask_login.utils as flask_login_utils From 4a3113aaa6d2889be361162310aa3ff58b713dfc Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Sun, 24 Sep 2023 20:38:35 -0600 Subject: [PATCH 36/38] Group blueprint imports together to reduce additional spacing --- usaon_vta_survey/__init__.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 538658d4..61fe4c52 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -63,32 +63,24 @@ def before_request(): if time.time() >= token['expires_at']: del s['google_oauth_token'] + from usaon_vta_survey.routes import response + from usaon_vta_survey.routes.google import blueprint + from usaon_vta_survey.routes.login import login_bp + from usaon_vta_survey.routes.logout import logout_bp from usaon_vta_survey.routes.root import root_bp - - app.register_blueprint(root_bp) + from usaon_vta_survey.routes.survey import survey_bp from usaon_vta_survey.routes.surveys import surveys_bp + from usaon_vta_survey.routes.user import user_bp + from usaon_vta_survey.routes.users import users_bp + app.register_blueprint(root_bp) app.register_blueprint(surveys_bp) - from usaon_vta_survey.routes.survey import survey_bp - app.register_blueprint(survey_bp) - from usaon_vta_survey.routes.user import user_bp - app.register_blueprint(user_bp) - from usaon_vta_survey.routes.users import users_bp - app.register_blueprint(users_bp) - from usaon_vta_survey.routes.login import login_bp - app.register_blueprint(login_bp) - from usaon_vta_survey.routes.logout import logout_bp - app.register_blueprint(logout_bp) - from usaon_vta_survey.routes.google import blueprint - app.register_blueprint(blueprint, url_prefix="/google_oauth") - from usaon_vta_survey.routes import response - app.register_blueprint(response.bp) app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) From 1e52cd0cc294a7d1fe0fad85ff7e1ecdc281c704 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Thu, 28 Sep 2023 08:15:51 -0600 Subject: [PATCH 37/38] Update path --- usaon_vta_survey/templates/response/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usaon_vta_survey/templates/response/base.html b/usaon_vta_survey/templates/response/base.html index d82c5461..badd9301 100644 --- a/usaon_vta_survey/templates/response/base.html +++ b/usaon_vta_survey/templates/response/base.html @@ -15,7 +15,7 @@

    {% block title %}Response to: {{survey.title}}{% endblock %}

  • - + Observing systems ({{survey.response.observing_systems | length}})
  • From b9bd6381c63f17ff90a207142010b59e9771a041 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Thu, 28 Sep 2023 08:44:49 -0600 Subject: [PATCH 38/38] Adding blueprints --- usaon_vta_survey/__init__.py | 12 ++++++++++-- usaon_vta_survey/routes/response/applications.py | 9 ++++++--- usaon_vta_survey/routes/response/data_products.py | 9 ++++++--- .../routes/response/observing_systems.py | 9 ++++++--- usaon_vta_survey/routes/response/sbas.py | 9 ++++++--- usaon_vta_survey/templates/response/base.html | 8 ++++---- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/usaon_vta_survey/__init__.py b/usaon_vta_survey/__init__.py index 61fe4c52..37ae79c6 100644 --- a/usaon_vta_survey/__init__.py +++ b/usaon_vta_survey/__init__.py @@ -63,10 +63,14 @@ def before_request(): if time.time() >= token['expires_at']: del s['google_oauth_token'] - from usaon_vta_survey.routes import response from usaon_vta_survey.routes.google import blueprint from usaon_vta_survey.routes.login import login_bp from usaon_vta_survey.routes.logout import logout_bp + from usaon_vta_survey.routes.response import bp + from usaon_vta_survey.routes.response.applications import application_bp + from usaon_vta_survey.routes.response.data_products import dp_bp + from usaon_vta_survey.routes.response.observing_systems import obs_bp + from usaon_vta_survey.routes.response.sbas import sba_bp from usaon_vta_survey.routes.root import root_bp from usaon_vta_survey.routes.survey import survey_bp from usaon_vta_survey.routes.surveys import surveys_bp @@ -81,7 +85,11 @@ def before_request(): app.register_blueprint(login_bp) app.register_blueprint(logout_bp) app.register_blueprint(blueprint, url_prefix="/google_oauth") - app.register_blueprint(response.bp) + app.register_blueprint(bp) + app.register_blueprint(obs_bp) + app.register_blueprint(sba_bp) + app.register_blueprint(application_bp) + app.register_blueprint(dp_bp) app.jinja_env.globals.update(sqla_inspect=sqla_inspect, __version__=__version__) diff --git a/usaon_vta_survey/routes/response/applications.py b/usaon_vta_survey/routes/response/applications.py index 1795f437..82675663 100644 --- a/usaon_vta_survey/routes/response/applications.py +++ b/usaon_vta_survey/routes/response/applications.py @@ -1,14 +1,17 @@ -from flask import redirect, render_template, request, url_for +from flask import Blueprint, redirect, render_template, request, url_for from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseApplication, Survey -from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors from usaon_vta_survey.util.sankey import applications_sankey +application_bp = Blueprint( + 'application', __name__, url_prefix='/response//applications' +) -@bp.route('//applications', methods=['GET', 'POST']) + +@application_bp.route('', methods=['GET', 'POST']) def view_response_applications(survey_id: str): """View and add to applications associated with a response.""" Form = FORMS_BY_MODEL[ResponseApplication] diff --git a/usaon_vta_survey/routes/response/data_products.py b/usaon_vta_survey/routes/response/data_products.py index 5df01bb4..bf5310de 100644 --- a/usaon_vta_survey/routes/response/data_products.py +++ b/usaon_vta_survey/routes/response/data_products.py @@ -1,13 +1,16 @@ -from flask import redirect, render_template, request, url_for +from flask import Blueprint, redirect, render_template, request, url_for from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseDataProduct, Survey -from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors +dp_bp = Blueprint( + 'data_product', __name__, url_prefix='/response//data_products' +) -@bp.route('//data_products', methods=['GET', 'POST']) + +@dp_bp.route('', methods=['GET', 'POST']) def view_response_data_products(survey_id: str): """View and add to data products associated with a response.""" Form = FORMS_BY_MODEL[ResponseDataProduct] diff --git a/usaon_vta_survey/routes/response/observing_systems.py b/usaon_vta_survey/routes/response/observing_systems.py index eb4064cf..d1623481 100644 --- a/usaon_vta_survey/routes/response/observing_systems.py +++ b/usaon_vta_survey/routes/response/observing_systems.py @@ -1,14 +1,17 @@ -from flask import redirect, render_template, request, url_for +from flask import Blueprint, redirect, render_template, request, url_for from usaon_vta_survey import db from usaon_vta_survey._types import ObservingSystemType from usaon_vta_survey.forms import FORMS_BY_MODEL from usaon_vta_survey.models.tables import ResponseObservingSystem, Survey -from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors +obs_bp = Blueprint( + 'obs', __name__, url_prefix='/response//observing_systems' +) -@bp.route('//observing_systems', methods=['GET', 'POST']) + +@obs_bp.route('', methods=['GET', 'POST']) def view_response_observing_systems(survey_id: str): """View and add to observing systems associated with a response.""" Form = FORMS_BY_MODEL[ResponseObservingSystem] diff --git a/usaon_vta_survey/routes/response/sbas.py b/usaon_vta_survey/routes/response/sbas.py index 9dbbd8e1..f83f35e6 100644 --- a/usaon_vta_survey/routes/response/sbas.py +++ b/usaon_vta_survey/routes/response/sbas.py @@ -1,4 +1,4 @@ -from flask import redirect, render_template, request, url_for +from flask import Blueprint, redirect, render_template, request, url_for from usaon_vta_survey import db from usaon_vta_survey.forms import FORMS_BY_MODEL @@ -7,11 +7,14 @@ SocietalBenefitArea, Survey, ) -from usaon_vta_survey.routes.response import bp from usaon_vta_survey.util.authorization import limit_response_editors +sba_bp = Blueprint( + 'sba', __name__, url_prefix='/response//societal_benefit_areas' +) + -@bp.route('//societal_benefit_areas', methods=['GET', 'POST']) +@sba_bp.route('', methods=['GET', 'POST']) def view_response_sbas(survey_id: str): """View and add to observing systems associated with a response.""" sbas = SocietalBenefitArea.query.all() diff --git a/usaon_vta_survey/templates/response/base.html b/usaon_vta_survey/templates/response/base.html index badd9301..23da99d7 100644 --- a/usaon_vta_survey/templates/response/base.html +++ b/usaon_vta_survey/templates/response/base.html @@ -15,25 +15,25 @@

    {% block title %}Response to: {{survey.title}}{% endblock %}

  • - + Observing systems ({{survey.response.observing_systems | length}})
  • - + Data products ({{survey.response.data_products | length}})
  • - + Applications ({{survey.response.applications | length}})
  • - + Societal Benefit Areas ({{survey.response.societal_benefit_areas | length}})