From 12c28682df7ab02ee6a84205811f75d7fb6a4356 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Mon, 4 Nov 2024 11:44:45 -0500 Subject: [PATCH 01/17] Added link to new guidance page that enables navigating --- app/__init__.py | 7 ++ app/main/views/index.py | 20 ++-- app/main/views/sub_navigation_dictionaries.py | 4 + app/navigation.py | 3 + app/templates/components/header.html | 103 ++++++++++-------- urls.js | 26 +++-- 6 files changed, 99 insertions(+), 64 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 483d89ea0..1e0f9c569 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -162,6 +162,13 @@ def _csp(config): def create_app(application): + + @application.context_processor + def inject_feature_flags(): + feature_best_practices_enabled = os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" + return dict(FEATURE_BEST_PRACTICES_ENABLED=feature_best_practices_enabled) + + notify_environment = os.environ["NOTIFY_ENVIRONMENT"] application.config.from_object(configs[notify_environment]) diff --git a/app/main/views/index.py b/app/main/views/index.py index 8b965991c..a5af4d506 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -21,10 +21,8 @@ from notifications_utils.url_safe_token import generate_token # Hook to check for guidance routes @main.before_request def check_guidance_feature(): - current_app.logger.warning("best practices 1234") - current_app.logger.warning(current_app.config["FEATURE_BEST_PRACTICES_ENABLED"]) if ( - request.path.startswith("/best-practices") + request.path.startswith("/guides/best-practices") and not current_app.config["FEATURE_BEST_PRACTICES_ENABLED"] ): abort(404) @@ -205,7 +203,7 @@ def trial_mode_new(): ) -@main.route("/best-practices") +@main.route("/guides/best-practices") @user_is_logged_in def best_practices(): return render_template( @@ -214,7 +212,7 @@ def best_practices(): ) -@main.route("/best-practices/clear-goals") +@main.route("/guides/best-practices/clear-goals") @user_is_logged_in def clear_goals(): return render_template( @@ -223,7 +221,7 @@ def clear_goals(): ) -@main.route("/best-practices/rules-and-regulations") +@main.route("/guides/best-practices/rules-and-regulations") @user_is_logged_in def rules_and_regulations(): return render_template( @@ -232,7 +230,7 @@ def rules_and_regulations(): ) -@main.route("/best-practices/establish-trust") +@main.route("/guides/best-practices/establish-trust") @user_is_logged_in def establish_trust(): return render_template( @@ -241,7 +239,7 @@ def establish_trust(): ) -@main.route("/best-practices/write-for-action") +@main.route("/guides/best-practices/write-for-action") @user_is_logged_in def write_for_action(): return render_template( @@ -250,7 +248,7 @@ def write_for_action(): ) -@main.route("/best-practices/multiple-languages") +@main.route("/guides/best-practices/multiple-languages") @user_is_logged_in def multiple_languages(): return render_template( @@ -259,7 +257,7 @@ def multiple_languages(): ) -@main.route("/best-practices/benchmark-performance") +@main.route("/guides/best-practices/benchmark-performance") @user_is_logged_in def benchmark_performance(): return render_template( @@ -268,7 +266,7 @@ def benchmark_performance(): ) -@main.route("/using-notify/guidance") +@main.route("/guides/using-notify/guidance") @user_is_logged_in def guidance_index(): return render_template( diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index 0689c198d..1f41c4b40 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -26,6 +26,10 @@ def using_notify_nav(): { "name": "Get started", "link": "main.get_started", + }, + { + "name": "Best Practices", + "link": "main.best_practices", }, { "name": "Trial mode", diff --git a/app/navigation.py b/app/navigation.py index 6ef0907a6..73d86a319 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -46,6 +46,9 @@ class HeaderNavigation(Navigation): "roadmap", "security", }, + "best_practices": { + "best_practices", + }, "using_notify": { "get_started", "using_notify", diff --git a/app/templates/components/header.html b/app/templates/components/header.html index 5ae37fc71..82ce61852 100644 --- a/app/templates/components/header.html +++ b/app/templates/components/header.html @@ -1,32 +1,43 @@ {% if current_user.is_authenticated %} - {% set navigation = [ - {"href": url_for("main.show_accounts_or_dashboard"), "text": "Current service", "active": header_navigation.is_selected('accounts-or-dashboard')}, - {"href": url_for('main.get_started'), "text": "Using Notify", "active": header_navigation.is_selected('using_notify')}, - {"href": url_for('main.features'), "text": "Features", "active": header_navigation.is_selected('features')}, - {"href": url_for('main.support'), "text": "Contact us", "active": header_navigation.is_selected('support')} - ] %} +{% set navigation = [ +{"href": url_for("main.show_accounts_or_dashboard"), "text": "Current service", "active": +header_navigation.is_selected('accounts-or-dashboard')}, +{"href": url_for('main.get_started'), "text": "Using Notify", "active": header_navigation.is_selected('using_notify')} +] %} - {% if current_user.platform_admin %} - {% set navigation = navigation + [{"href": url_for('main.platform_admin_splash_page'), "text": "Platform admin", "active": header_navigation.is_selected('platform-admin')}] %} - {% else %} - {% set navigation = navigation + [{"href": url_for('main.user_profile'), "text": "User profile", "active": header_navigation.is_selected('user-profile')}] %} - {% endif %} +{% if FEATURE_BEST_PRACTICES_ENABLED %} +{% set navigation = navigation + [{"href": url_for('main.best_practices'), "text": "Best Practices", "active": +header_navigation.is_selected('best_practices')}] %} +{% endif %} - {% if current_service %} - {% if current_user.has_permissions('manage_service') %} - {% set secondaryNavigation = [ - {"href": url_for('main.service_settings', service_id=current_service.id), "text": "Settings", "active": secondary_navigation.is_selected('settings')}, - {"href": url_for('main.sign_out'), "text": "Sign out"} - ] %} - {% else %} - {% set secondaryNavigation = [ - {"href": url_for('main.sign_out'), "text": "Sign out"} - ] %} +{% set navigation = navigation + [ +{"href": url_for('main.features'), "text": "Features", "active": header_navigation.is_selected('features')}, +{"href": url_for('main.support'), "text": "Contact us", "active": header_navigation.is_selected('support')} +] %} - {% endif %} - {% else %} - {% set secondaryNavigation = [{"href": url_for('main.sign_out'), "text": "Sign out"}] %} - {% endif %} +{% if current_user.platform_admin %} +{% set navigation = navigation + [{"href": url_for('main.platform_admin_splash_page'), "text": "Platform admin", +"active": header_navigation.is_selected('platform-admin')}] %} +{% else %} +{% set navigation = navigation + [{"href": url_for('main.user_profile'), "text": "User profile", "active": +header_navigation.is_selected('user-profile')}] %} +{% endif %} + +{% if current_service %} +{% if current_user.has_permissions('manage_service') %} +{% set secondaryNavigation = [ +{"href": url_for('main.service_settings', service_id=current_service.id), "text": "Settings", "active": +secondary_navigation.is_selected('settings')}, +{"href": url_for('main.sign_out'), "text": "Sign out"} +] %} +{% else %} +{% set secondaryNavigation = [ +{"href": url_for('main.sign_out'), "text": "Sign out"} +] %} +{% endif %} +{% else %} +{% set secondaryNavigation = [{"href": url_for('main.sign_out'), "text": "Sign out"}] %} +{% endif %} {% endif %}
@@ -36,12 +47,12 @@ {% if navigation %} - + {% endif %} @@ -52,29 +63,29 @@
diff --git a/urls.js b/urls.js index 8ff543470..0440430ec 100644 --- a/urls.js +++ b/urls.js @@ -13,13 +13,25 @@ const sublinks = [ { label: 'Roadmap', path: '/features/roadmap' }, { label: 'Security', path: '/features/security' }, { label: 'Support', path: '/support' }, - { label: 'Best Practices', path: '/best-practices' }, - { label: 'Clear Goals', path: '/best-practices/clear-goals' }, - { label: 'Rules And Regulations', path: '/best-practices/rules-and-regulations' }, - { label: 'Establish Trust', path: '/best-practices/establish-trust' }, - { label: 'Write For Action', path: '/best-practices/write-for-action' }, - { label: 'Multiple Languages', path: '/best-practices/multiple-languages' }, - { label: 'Benchmark Performance', path: '/best-practices/benchmark-performance' }, + { label: 'Best Practices', path: '/guides/best-practices' }, + { label: 'Clear Goals', path: '/guides/best-practices/clear-goals' }, + { + label: 'Rules And Regulations', + path: '/guides/best-practices/rules-and-regulations', + }, + { label: 'Establish Trust', path: '/guides/best-practices/establish-trust' }, + { + label: 'Write For Action', + path: '/guides/best-practices/write-for-action', + }, + { + label: 'Multiple Languages', + path: '/guides/best-practices/multiple-languages', + }, + { + label: 'Benchmark Performance', + path: '/guides/best-practices/benchmark-performance', + }, // Add more links here as needed ]; From e7c82b1fc3fc8d582765c0168c84d528ba0e8606 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Mon, 4 Nov 2024 11:50:29 -0500 Subject: [PATCH 02/17] Fixed indent --- app/main/views/sub_navigation_dictionaries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index 1f41c4b40..b4226e98f 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -27,7 +27,7 @@ def using_notify_nav(): "name": "Get started", "link": "main.get_started", }, - { + { "name": "Best Practices", "link": "main.best_practices", }, From 5fa91729015653b4433dab4db506b04d922f4542 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Mon, 4 Nov 2024 11:57:13 -0500 Subject: [PATCH 03/17] Fixing linting errors --- app/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 1e0f9c569..5978b6068 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -162,13 +162,11 @@ def _csp(config): def create_app(application): - @application.context_processor def inject_feature_flags(): feature_best_practices_enabled = os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" return dict(FEATURE_BEST_PRACTICES_ENABLED=feature_best_practices_enabled) - notify_environment = os.environ["NOTIFY_ENVIRONMENT"] application.config.from_object(configs[notify_environment]) From 5cbb1f3befe861ceaed49283a6238a5ed66529e9 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Mon, 4 Nov 2024 15:04:34 -0500 Subject: [PATCH 04/17] Updated route --- .../views/best-practices/best-practices.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/templates/views/best-practices/best-practices.html b/app/templates/views/best-practices/best-practices.html index a00a48660..7711dea9b 100644 --- a/app/templates/views/best-practices/best-practices.html +++ b/app/templates/views/best-practices/best-practices.html @@ -23,37 +23,37 @@ Best Practices "svg_src": "goal", "card_heading": "Establish clear goals", "p_text": "Start with a singular purpose. Make explicit what you want to achieve.", - "link": "/best-practices/clear-goals" + "link": "/guides/best-practices/clear-goals" }, { "svg_src": "compliant", "card_heading": "Follow rules & regulations", "p_text": "Understand what is required when texting the public.", - "link": "/best-practices/rules-and-regulations" + "link": "/guides/best-practices/rules-and-regulations" }, { "svg_src": "trust", "card_heading": "Establish trust", "p_text": "Help your audience anticipate and welcome your texts.", - "link": "/best-practices/establish-trust" + "link": "/guides/best-practices/establish-trust" }, { "svg_src": "runner", "card_heading": "Write texts that provoke action", "p_text": "Help your audience know what to do with the information you send.", - "link": "/best-practices/write-for-action" + "link": "/guides/best-practices/write-for-action" }, { "svg_src": "language", "card_heading": "Send texts in multiple languages", "p_text": "What to know as you plan translated texts.", - "link": "/best-practices/multiple-languages" + "link": "/guides/best-practices/multiple-languages" }, { "svg_src": "chart", "card_heading": "Measure performance with benchmarking", "p_text": "Learn how effective your texting program can be.", - "link": "/best-practices/benchmark-performance" + "link": "/guides/best-practices/benchmark-performance" } ] %} From 13e9b12367aa7c20c42b156159d2a087eaf1b549 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Tue, 12 Nov 2024 10:32:51 -0500 Subject: [PATCH 05/17] Renamed guides to best practices --- app/main/views/sub_navigation_dictionaries.py | 4 ++-- app/navigation.py | 4 ++-- app/templates/components/header.html | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index b4226e98f..54597300d 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -28,8 +28,8 @@ def using_notify_nav(): "link": "main.get_started", }, { - "name": "Best Practices", - "link": "main.best_practices", + "name": "Guides", + "link": "main.guides", }, { "name": "Trial mode", diff --git a/app/navigation.py b/app/navigation.py index 73d86a319..f89b31d9a 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -46,8 +46,8 @@ class HeaderNavigation(Navigation): "roadmap", "security", }, - "best_practices": { - "best_practices", + "guides": { + "guides", }, "using_notify": { "get_started", diff --git a/app/templates/components/header.html b/app/templates/components/header.html index 82ce61852..6ef892bdc 100644 --- a/app/templates/components/header.html +++ b/app/templates/components/header.html @@ -6,8 +6,8 @@ header_navigation.is_selected('accounts-or-dashboard')}, ] %} {% if FEATURE_BEST_PRACTICES_ENABLED %} -{% set navigation = navigation + [{"href": url_for('main.best_practices'), "text": "Best Practices", "active": -header_navigation.is_selected('best_practices')}] %} +{% set navigation = navigation + [{"href": url_for('main.guides'), "text": "Guides", "active": +header_navigation.is_selected('guides')}] %} {% endif %} {% set navigation = navigation + [ From 1a14becc9a0d8d13815203fcf425c09c6d42bac5 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Tue, 12 Nov 2024 12:54:22 -0500 Subject: [PATCH 06/17] Updated link name and route --- app/__init__.py | 4 +++- app/main/views/sub_navigation_dictionaries.py | 2 +- app/navigation.py | 1 + app/templates/components/header.html | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 5978b6068..da52506d3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -162,9 +162,11 @@ def _csp(config): def create_app(application): + application.config['FEATURE_BEST_PRACTICES_ENABLED'] = os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" + @application.context_processor def inject_feature_flags(): - feature_best_practices_enabled = os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" + feature_best_practices_enabled = application.config['FEATURE_BEST_PRACTICES_ENABLED'] return dict(FEATURE_BEST_PRACTICES_ENABLED=feature_best_practices_enabled) notify_environment = os.environ["NOTIFY_ENVIRONMENT"] diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index 54597300d..e35c730a5 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -29,7 +29,7 @@ def using_notify_nav(): }, { "name": "Guides", - "link": "main.guides", + "link": "main.best_practices", }, { "name": "Trial mode", diff --git a/app/navigation.py b/app/navigation.py index f89b31d9a..d764b4cd9 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -48,6 +48,7 @@ class HeaderNavigation(Navigation): }, "guides": { "guides", + "best-practies" }, "using_notify": { "get_started", diff --git a/app/templates/components/header.html b/app/templates/components/header.html index 6ef892bdc..692a9c9d6 100644 --- a/app/templates/components/header.html +++ b/app/templates/components/header.html @@ -6,7 +6,7 @@ header_navigation.is_selected('accounts-or-dashboard')}, ] %} {% if FEATURE_BEST_PRACTICES_ENABLED %} -{% set navigation = navigation + [{"href": url_for('main.guides'), "text": "Guides", "active": +{% set navigation = navigation + [{"href": url_for('main.best_practices'), "text": "Guides", "active": header_navigation.is_selected('guides')}] %} {% endif %} From f6fbe1bd8d23420cfec150e6079df3101f3096db Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Tue, 12 Nov 2024 13:07:57 -0500 Subject: [PATCH 07/17] Fixed linting error --- app/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index da52506d3..da66cec34 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -162,7 +162,9 @@ def _csp(config): def create_app(application): - application.config['FEATURE_BEST_PRACTICES_ENABLED'] = os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" + application.config['FEATURE_BEST_PRACTICES_ENABLED'] = ( + os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" + ) @application.context_processor def inject_feature_flags(): From c4ee02f03802f9e1cce13f826059f0dbc357a8a8 Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Wed, 13 Nov 2024 09:52:37 -0500 Subject: [PATCH 08/17] Removed unused navigation link --- app/navigation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/navigation.py b/app/navigation.py index d764b4cd9..f89b31d9a 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -48,7 +48,6 @@ class HeaderNavigation(Navigation): }, "guides": { "guides", - "best-practies" }, "using_notify": { "get_started", From b8ea1d812a296e37e135685a20fcb168cd70a27e Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Wed, 13 Nov 2024 10:01:33 -0500 Subject: [PATCH 09/17] Fixed error --- app/navigation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/navigation.py b/app/navigation.py index f89b31d9a..73d86a319 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -46,8 +46,8 @@ class HeaderNavigation(Navigation): "roadmap", "security", }, - "guides": { - "guides", + "best_practices": { + "best_practices", }, "using_notify": { "get_started", From 6ca902acd3a486a406dcf409a755c3c16229b7cb Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Wed, 13 Nov 2024 10:18:12 -0500 Subject: [PATCH 10/17] Added back guides because its needed --- app/__init__.py | 6 ++++-- app/navigation.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index da66cec34..64580fcc1 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -162,13 +162,15 @@ def _csp(config): def create_app(application): - application.config['FEATURE_BEST_PRACTICES_ENABLED'] = ( + application.config["FEATURE_BEST_PRACTICES_ENABLED"] = ( os.getenv("FEATURE_BEST_PRACTICES_ENABLED", "false").lower() == "true" ) @application.context_processor def inject_feature_flags(): - feature_best_practices_enabled = application.config['FEATURE_BEST_PRACTICES_ENABLED'] + feature_best_practices_enabled = application.config[ + "FEATURE_BEST_PRACTICES_ENABLED" + ] return dict(FEATURE_BEST_PRACTICES_ENABLED=feature_best_practices_enabled) notify_environment = os.environ["NOTIFY_ENVIRONMENT"] diff --git a/app/navigation.py b/app/navigation.py index 73d86a319..0d067a2ed 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -46,6 +46,7 @@ class HeaderNavigation(Navigation): "roadmap", "security", }, + "guides": {"guides"}, "best_practices": { "best_practices", }, From b9ef8ea0c0c7cc472d1b15bda71de8980ba03b7b Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Wed, 13 Nov 2024 10:26:06 -0500 Subject: [PATCH 11/17] Removed unused code --- app/navigation.py | 1 - app/templates/components/header.html | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/navigation.py b/app/navigation.py index 0d067a2ed..73d86a319 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -46,7 +46,6 @@ class HeaderNavigation(Navigation): "roadmap", "security", }, - "guides": {"guides"}, "best_practices": { "best_practices", }, diff --git a/app/templates/components/header.html b/app/templates/components/header.html index 692a9c9d6..248abf250 100644 --- a/app/templates/components/header.html +++ b/app/templates/components/header.html @@ -7,7 +7,7 @@ header_navigation.is_selected('accounts-or-dashboard')}, {% if FEATURE_BEST_PRACTICES_ENABLED %} {% set navigation = navigation + [{"href": url_for('main.best_practices'), "text": "Guides", "active": -header_navigation.is_selected('guides')}] %} +header_navigation.is_selected('best_practices')}] %} {% endif %} {% set navigation = navigation + [ From 3da5fb406e76ff92e8ae60099c6bd9232d80442d Mon Sep 17 00:00:00 2001 From: alexjanousekGSA Date: Wed, 13 Nov 2024 10:30:06 -0500 Subject: [PATCH 12/17] Added subnav to fix css --- app/navigation.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/navigation.py b/app/navigation.py index 73d86a319..a02df484d 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -48,6 +48,12 @@ class HeaderNavigation(Navigation): }, "best_practices": { "best_practices", + "clear_goals", + "rules_and_regulations", + "establish_trust", + "write_for_action", + "multiple_languages", + "benchmark_performance" }, "using_notify": { "get_started", From cc5c4114e04bde223d12c9b1ff56c6a518fad125 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 13 Nov 2024 10:58:40 -0500 Subject: [PATCH 13/17] Fixed email verify, put time limits on redis stuff. Signed-off-by: Cliff Hill --- app/main/views/index.py | 6 ++++-- app/main/views/sign_in.py | 27 +++++++++++++++++++------- app/notify_client/invite_api_client.py | 16 +++++++++------ app/notify_client/user_api_client.py | 2 +- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/app/main/views/index.py b/app/main/views/index.py index 7728cb325..28ede59d1 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -35,6 +35,8 @@ def index(): if current_user and current_user.is_authenticated: return redirect(url_for("main.choose_account")) + ttl = 24 * 60 * 60 + # make and store the state state = generate_token( str(request.remote_addr), @@ -42,12 +44,12 @@ def index(): current_app.config["DANGEROUS_SALT"], ) state_key = f"login-state-{unquote(state)}" - redis_client.set(state_key, state) + redis_client.set(state_key, state, ex=ttl) # make and store the nonce nonce = secrets.token_urlsafe() nonce_key = f"login-nonce-{unquote(nonce)}" - redis_client.set(nonce_key, nonce) + redis_client.set(nonce_key, nonce, ex=ttl) url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") if url is not None: diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index d948f459e..061d30d22 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -108,11 +108,18 @@ def _do_login_dot_gov(): # $ pragma: no cover ) raise Exception(f"Could not login with login.gov {login_gov_error}") elif code and state: - state_key = f"login-state-{unquote(state)}" - stored_state = unquote(redis_client.get(state_key).decode("utf8")) - if state != stored_state: - current_app.logger.error(f"State Error: {state} != {stored_state}") - abort(403) + try: + state_key = f"login-state-{unquote(state)}" + stored_state = unquote(redis_client.get(state_key).decode("utf8")) + if state != stored_state: + current_app.logger.error(f"State Error: {state} != {stored_state}") + abort(403) + except AttributeError: # There is no stored state + verify_key = f"login-verify_email-{unquote(state)}" + verify_path = bool(redis_client.get(verify_key)) + if not verify_path: + current_app.logger.error("Not verify_email path, no state found.") + abort(403) # activate the user try: @@ -135,6 +142,10 @@ def _do_login_dot_gov(): # $ pragma: no cover user["email_access_validated_at"], 90 ) if not is_fresh_email: + # send email verify + ttl = 24 * 60 * 60 + verify_key = f"login-verify_email-{unquote(state)}" + redis_client.set(verify_key, state, ex=ttl) return verify_email(user, redirect_url) usr = User.from_email_address(user["email_address"]) @@ -209,17 +220,19 @@ def sign_in(): # pragma: no cover return redirect(redirect_url) return redirect(url_for("main.show_accounts_or_dashboard")) + ttl = 24 * 60 * 60 + state = generate_token( str(request.remote_addr), current_app.config["SECRET_KEY"], current_app.config["DANGEROUS_SALT"], ) state_key = f"login-state-{unquote(state)}" - redis_client.set(state_key, state) + redis_client.set(state_key, state, ex=ttl) nonce = secrets.token_urlsafe() nonce_key = f"login-nonce-{unquote(nonce)}" - redis_client.set(nonce_key, nonce) + redis_client.set(nonce_key, nonce, ex=ttl) url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") # handle unit tests diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 39cf7dbce..4ed5eee11 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -41,6 +41,8 @@ class InviteApiClient(NotifyAdminAPIClient): } data = _attach_current_user(data) + ttl = 24 * 60 * 60 + # make and store the state state = generate_token( str(request.remote_addr), @@ -48,12 +50,12 @@ class InviteApiClient(NotifyAdminAPIClient): current_app.config["DANGEROUS_SALT"], ) state_key = f"login-state-{unquote(state)}" - redis_client.set(state_key, state) + redis_client.set(state_key, state, ex=ttl) # make and store the nonce nonce = secrets.token_urlsafe() nonce_key = f"login-nonce-{unquote(nonce)}" - redis_client.set(nonce_key, nonce) # save the nonce to redis. + redis_client.set(nonce_key, nonce, ex=ttl) # save the nonce to redis. data["nonce"] = nonce # This is passed to api for the invite url. data["state"] = state # This is passed to api for the invite url. @@ -64,7 +66,7 @@ class InviteApiClient(NotifyAdminAPIClient): invite_data_key = f"invitedata-{unquote(state)}" redis_invite_data = resp["invite"] redis_invite_data = json.dumps(redis_invite_data) - redis_client.set(invite_data_key, redis_invite_data) + redis_client.set(invite_data_key, redis_invite_data, ex=ttl) return resp_data @@ -97,6 +99,8 @@ class InviteApiClient(NotifyAdminAPIClient): self.post(url=f"/service/{service_id}/invite/{invited_user_id}", data=data) def resend_invite(self, service_id, invited_user_id): + ttl = 24 * 60 * 60 + # make and store the state state = generate_token( str(request.remote_addr), @@ -104,12 +108,12 @@ class InviteApiClient(NotifyAdminAPIClient): current_app.config["DANGEROUS_SALT"], ) state_key = f"login-state-{unquote(state)}" - redis_client.set(state_key, state) + redis_client.set(state_key, state, ex=ttl) # make and store the nonce nonce = secrets.token_urlsafe() nonce_key = f"login-nonce-{unquote(nonce)}" - redis_client.set(nonce_key, nonce) + redis_client.set(nonce_key, nonce, ex=ttl) data = { "nonce": nonce, @@ -122,7 +126,7 @@ class InviteApiClient(NotifyAdminAPIClient): invite_data_key = f"invitedata-{unquote(state)}" redis_invite_data = resp["invite"] redis_invite_data = json.dumps(redis_invite_data) - redis_client.set(invite_data_key, redis_invite_data) + redis_client.set(invite_data_key, redis_invite_data, ex=ttl) @cache.delete("service-{service_id}") @cache.delete("user-{invited_user_id}") diff --git a/app/notify_client/user_api_client.py b/app/notify_client/user_api_client.py index 3514a0d6e..4a41ac28f 100644 --- a/app/notify_client/user_api_client.py +++ b/app/notify_client/user_api_client.py @@ -116,7 +116,7 @@ class UserApiClient(NotifyAdminAPIClient): data["next"] = next_string if code_type == "email": data["email_auth_link_host"] = self.admin_url - endpoint = "/user/{0}/{1}-code".format(user_id, code_type) + endpoint = f"/user/{user_id}/{code_type}-code" current_app.logger.warn(hilite(f"Sending verify_code {code_type} to {user_id}")) self.post(endpoint, data=data) From 683bf893c1d637ab05fa843ed61f7a60cb919ecd Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 13 Nov 2024 14:34:34 -0500 Subject: [PATCH 14/17] fixing things. Signed-off-by: Cliff Hill --- app/main/views/sign_in.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 061d30d22..3f4023f03 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -108,18 +108,15 @@ def _do_login_dot_gov(): # $ pragma: no cover ) raise Exception(f"Could not login with login.gov {login_gov_error}") elif code and state: - try: + verify_key = f"login-verify_email-{unquote(state)}" + verify_path = bool(redis_client.get(verify_key)) + + if not verify_path: state_key = f"login-state-{unquote(state)}" stored_state = unquote(redis_client.get(state_key).decode("utf8")) if state != stored_state: current_app.logger.error(f"State Error: {state} != {stored_state}") abort(403) - except AttributeError: # There is no stored state - verify_key = f"login-verify_email-{unquote(state)}" - verify_path = bool(redis_client.get(verify_key)) - if not verify_path: - current_app.logger.error("Not verify_email path, no state found.") - abort(403) # activate the user try: From 49932f6942398a1cf3e4c9273a8b1443845e6857 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 13 Nov 2024 17:18:51 -0500 Subject: [PATCH 15/17] Ok, commenting out the check for emails for now. Signed-off-by: Cliff Hill --- app/main/views/sign_in.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 3f4023f03..5e42ed879 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -134,16 +134,17 @@ def _do_login_dot_gov(): # $ pragma: no cover f"Retrieved user {user['id']} from db #notify-admin-1505" ) - # Check if the email needs to be revalidated - is_fresh_email = is_less_than_days_ago( - user["email_access_validated_at"], 90 - ) - if not is_fresh_email: - # send email verify - ttl = 24 * 60 * 60 - verify_key = f"login-verify_email-{unquote(state)}" - redis_client.set(verify_key, state, ex=ttl) - return verify_email(user, redirect_url) + # Temporary disabling of this until we figure out what is happening. + # # Check if the email needs to be revalidated + # is_fresh_email = is_less_than_days_ago( + # user["email_access_validated_at"], 90 + # ) + # if not is_fresh_email: + # # send email verify + # ttl = 24 * 60 * 60 + # verify_key = f"login-verify_email-{unquote(state)}" + # redis_client.set(verify_key, state, ex=ttl) + # return verify_email(user, redirect_url) usr = User.from_email_address(user["email_address"]) current_app.logger.info(f"activating user {usr.id} #notify-admin-1505") From d678659cbecd7fceab1c67e5a46078ee8b6ed370 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 13 Nov 2024 17:23:57 -0500 Subject: [PATCH 16/17] Flake8 is annoying. Signed-off-by: Cliff Hill --- app/main/views/sign_in.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 5e42ed879..2451c9ac3 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -25,7 +25,7 @@ from app.main.views.verify import activate_user from app.models.user import User from app.utils import hide_from_search_engines from app.utils.login import get_id_token, is_safe_redirect_url -from app.utils.time import is_less_than_days_ago +# from app.utils.time import is_less_than_days_ago from app.utils.user import is_gov_user from notifications_utils.url_safe_token import generate_token From 9796d424b503ed3fd3b71d8068b8adb271c22fc3 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 13 Nov 2024 17:27:52 -0500 Subject: [PATCH 17/17] Flake8 is dumb. Signed-off-by: Cliff Hill --- app/main/views/sign_in.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 2451c9ac3..004dce2ae 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -25,6 +25,7 @@ from app.main.views.verify import activate_user from app.models.user import User from app.utils import hide_from_search_engines from app.utils.login import get_id_token, is_safe_redirect_url + # from app.utils.time import is_less_than_days_ago from app.utils.user import is_gov_user from notifications_utils.url_safe_token import generate_token