From c2d7828138de56c48fd78661a1faee5b0da24374 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 13 Feb 2024 17:48:06 -0800 Subject: [PATCH 01/55] created an alert for confirmation during send flow --- app/__init__.py | 2 ++ app/formatters.py | 6 +++++ app/templates/partials/jobs/status.html | 27 ++++++++++++++++--- .../views/notifications/notification.html | 20 +++++++------- tests/app/main/views/test_jobs.py | 14 ++++++---- tests/app/main/views/test_notifications.py | 16 ++++++++--- 6 files changed, 62 insertions(+), 23 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 3f008f7a1..e0bde1e4e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -53,6 +53,7 @@ from app.formatters import ( format_datetime_normal, format_datetime_relative, format_datetime_short, + format_datetime_short_12h, format_datetime_short_america, format_day_of_week, format_delta, @@ -549,6 +550,7 @@ def add_template_filters(application): format_datetime_24h, format_datetime_normal, format_datetime_short, + format_datetime_short_12h, format_datetime_short_america, valid_phone_number, linkable_name, diff --git a/app/formatters.py b/app/formatters.py index 543167d9c..6638160d0 100644 --- a/app/formatters.py +++ b/app/formatters.py @@ -98,6 +98,12 @@ def format_datetime_short(date): ) +def format_datetime_short_12h(date): + return "{} at {} {}".format( + format_date_short(date), format_time_12h(date), get_user_preferred_timezone() + ) + + def format_datetime_short_america(date): return "{} at {}".format(format_date_numeric_america(date), format_time_12h(date)) diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 703050e8d..fb72c8382 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -2,12 +2,33 @@

{% if job.scheduled_for %} {% if job.processing_started %} - Sent by {{ job.created_by.name }} on {{ job.processing_started|format_datetime_short }} +

+
+

{{ job.template_name }} - {{ current_service.name }}

+

+ Was sent on {{ job.created_at|format_datetime_short_12h }} by {{ job.created_by.name }} +

+
+
{% else %} - Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }} +
+
+

{{ job.template_name }} - {{ current_service.name }}

+

+ Was scheduled on {{ job.scheduled_for|format_datetime_short_12h }} by {{ job.created_by.name }} +

+
+
{% endif %} {% else %} - Sent by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }} +
+
+

{{ job.template_name }} - {{ current_service.name }}

+

+ Was sent on {{ job.created_at|format_datetime_short_12h }} by {{ job.created_by.name }} +

+
+
{% endif %}

{% if job.status == 'sending limits exceeded'%} diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html index cf61250ed..9c921729d 100644 --- a/app/templates/views/notifications/notification.html +++ b/app/templates/views/notifications/notification.html @@ -24,18 +24,16 @@ {% if help %} ‘{{ template.name }}’ {% else %} - ‘{{ template.name }}’ + {% endif %} - was sent - {% if job and job.original_file_name != 'Report' %} - {% set destination = - {'email': 'an email address', 'sms': 'a phone number'} %} - to {{ destination[template.template_type] }} from - {{ job.original_file_name }} - {% elif created_by %} - by {{ created_by.name }} - {% endif %} - {{ created_at|format_datetime_human }} +
+
+

{{ template.name }} - {{ current_service.name }}

+

+ Was sent on {{ created_at|format_datetime_short_12h }} by {{ created_by.name }} +

+
+

diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index 323a1fe00..74fd6371a 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -237,11 +237,11 @@ def test_should_show_job_with_sending_limit_exceeded_status( job_id=fake_uuid, ) - assert normalize_spaces(page.select("main p")[1].text) == ( + assert normalize_spaces(page.select("main p")[2].text) == ( "Notify cannot send these messages because you have reached a limit. " "You can only send 1,000 messages per day and 250,000 messages in total." ) - assert normalize_spaces(page.select("main p")[2].text) == ( + assert normalize_spaces(page.select("main p")[3].text) == ( "Upload this spreadsheet again tomorrow or contact the Notify.gov team to raise the limit." ) @@ -350,7 +350,7 @@ def test_should_show_scheduled_job( ) assert normalize_spaces(page.select("main div p")[1].text) == ( - "Sending Two week reminder today at 00:00 US/Eastern" + "Was scheduled on 2 January at 12:00 AM US/Eastern by Test User" ) assert page.select("main p a")[0]["href"] == url_for( @@ -425,7 +425,9 @@ def test_should_show_updates_for_one_job_as_json( assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] assert "00:00" in content["notifications"] - assert "Sent by Test User on 1 January at 00:00" in content["status"] + assert ( + "Was sent on 1 January at 12:00 AM US/Eastern by Test User" in content["status"] + ) @freeze_time("2016-01-01 05:00:00.000001") @@ -467,7 +469,9 @@ def test_should_show_updates_for_scheduled_job_as_json( assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] assert "00:00" in content["notifications"] - assert "Sent by Test User on 1 June at 16:00" in content["status"] + assert ( + "Was sent on 1 January at 12:00 AM US/Eastern by Test User" in content["status"] + ) @pytest.mark.parametrize( diff --git a/tests/app/main/views/test_notifications.py b/tests/app/main/views/test_notifications.py index 7020cd3e0..61a7f495d 100644 --- a/tests/app/main/views/test_notifications.py +++ b/tests/app/main/views/test_notifications.py @@ -226,22 +226,30 @@ def test_notification_status_shows_expected_back_link( [ ( "2012-01-01 06:01", - ("‘sample template’ was sent by Test User today at 01:01 US/Eastern"), + ( + "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " + "by Test User" + ), ), ( "2012-01-02 06:01", - ("‘sample template’ was sent by Test User yesterday at 01:01 US/Eastern"), + ( + "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " + "by Test User" + ), ), ( "2012-01-03 06:01", ( - "‘sample template’ was sent by Test User on 1 January at 01:01 US/Eastern" + "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " + "by Test User" ), ), ( "2013-01-03 06:01", ( - "‘sample template’ was sent by Test User on 1 January 2012 at 01:01 US/Eastern" + "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " + "by Test User" ), ), ], From 4eb886d8c026d780bc8dd241fe256b694bdbfe5d Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 13 Feb 2024 18:18:13 -0800 Subject: [PATCH 02/55] update test --- .../views/notifications/notification.html | 28 ++++++++----------- tests/app/main/views/test_notifications.py | 18 ++++-------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html index 9c921729d..5a03daf3d 100644 --- a/app/templates/views/notifications/notification.html +++ b/app/templates/views/notifications/notification.html @@ -20,26 +20,20 @@ {{ page_header( 1|message_count_label(template.template_type, suffix='') | capitalize ) }} -

- {% if help %} - ‘{{ template.name }}’ - {% else %} - - {% endif %} -

-
-

{{ template.name }} - {{ current_service.name }}

-

- Was sent on {{ created_at|format_datetime_short_12h }} by {{ created_by.name }} -

-
+ {% if help %} +

‘{{ template.name }}’

+ {% endif %} +
+
+

{{ template.name }} - {{ current_service.name }}

+

+ Was sent on {{ created_at|format_datetime_short_12h }} by {{ created_by.name }} +

-

- -
- {{ template|string }}
+ {{ template|string }} + {% if template.template_type == 'email' %}
{{ ajax_block(partials, updates_url, 'status', finished=finished) }} diff --git a/tests/app/main/views/test_notifications.py b/tests/app/main/views/test_notifications.py index 61a7f495d..ce7bcab63 100644 --- a/tests/app/main/views/test_notifications.py +++ b/tests/app/main/views/test_notifications.py @@ -227,29 +227,25 @@ def test_notification_status_shows_expected_back_link( ( "2012-01-01 06:01", ( - "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " - "by Test User" + "Was sent on 1 January at 01:01 AM US/Eastern by Test User" ), ), ( "2012-01-02 06:01", ( - "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " - "by Test User" + "Was sent on 1 January at 01:01 AM US/Eastern by Test User" ), ), ( "2012-01-03 06:01", ( - "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " - "by Test User" + "Was sent on 1 January at 01:01 AM US/Eastern by Test User" ), ), ( "2013-01-03 06:01", ( - "‘sample template’ sample template - service one Was sent on 1 January at 01:01 AM US/Eastern " - "by Test User" + "Was sent on 1 January at 01:01 AM US/Eastern by Test User" ), ), ], @@ -275,10 +271,8 @@ def test_notification_page_doesnt_link_to_template_in_tour( notification_id=fake_uuid, help=3, ) - - assert normalize_spaces(page.select("main p:nth-of-type(1)")[0].text) == ( - expected_message - ) + p_text = normalize_spaces(page.select_one(".usa-alert__text").text) + assert p_text == normalize_spaces(expected_message) assert len(page.select("main p:nth-of-type(1) a")) == 0 From 1e60da1a3736583b1194e13bf57738b8eb649a03 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Thu, 22 Feb 2024 11:59:12 -0800 Subject: [PATCH 03/55] add job status --- app/assets/sass/uswds/_legacy-styles.scss | 6 ++- app/formatters.py | 5 ++- app/main/views/jobs.py | 5 +++ app/templates/partials/jobs/status.html | 55 ++++++++++++++--------- app/templates/views/jobs/job.html | 19 ++------ 5 files changed, 51 insertions(+), 39 deletions(-) diff --git a/app/assets/sass/uswds/_legacy-styles.scss b/app/assets/sass/uswds/_legacy-styles.scss index 3b09e2218..b62c15c36 100644 --- a/app/assets/sass/uswds/_legacy-styles.scss +++ b/app/assets/sass/uswds/_legacy-styles.scss @@ -62,6 +62,10 @@ margin: -20px units(1) 20px units(1); } +h2.sms-message-header { + margin-bottom: 0.5rem; +} + .sms-message-status-outbound { text-align: right; } @@ -131,7 +135,7 @@ &-label, &-button-label { font-weight: bold; - font-size: 19px; + font-size: 19px; display: block; margin: 0 0 10px 0; } diff --git a/app/formatters.py b/app/formatters.py index 6638160d0..db9f8dc04 100644 --- a/app/formatters.py +++ b/app/formatters.py @@ -99,8 +99,9 @@ def format_datetime_short(date): def format_datetime_short_12h(date): + # example: February 20, 2024 at 07:00 PM US/Eastern return "{} at {} {}".format( - format_date_short(date), format_time_12h(date), get_user_preferred_timezone() + format_date_normal(date), format_time_12h(date), get_user_preferred_timezone() ) @@ -192,7 +193,7 @@ def format_date(date): def format_date_normal(date): date = parse_naive_dt(date) - return date.strftime("%d %B %Y").lstrip("0") + return date.strftime("%B %d, %Y").lstrip("0") def format_date_short(date): diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index ed8f051a3..8f856f867 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -10,6 +10,7 @@ from flask import ( redirect, render_template, request, + session, stream_with_context, url_for, ) @@ -369,6 +370,9 @@ def get_job_partials(job): job.template_type ) + session['came_from_preview_page'] = 'check' in request.referrer + came_from_preview_page_url = session.get('came_from_preview_page', False) + return { "counts": counts, "notifications": render_template( @@ -392,6 +396,7 @@ def get_job_partials(job): "status": render_template( "partials/jobs/status.html", job=job, + came_from_preview_page_url=came_from_preview_page_url ), } diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index fb72c8382..15703b01c 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -1,34 +1,49 @@

- {% if job.scheduled_for %} - {% if job.processing_started %} -

-
-

{{ job.template_name }} - {{ current_service.name }}

-

- Was sent on {{ job.created_at|format_datetime_short_12h }} by {{ job.created_by.name }} -

+ {% set display_message_status %} + {% if job.template.content %} +

Message

+
{{ current_service.name }}: {{job.template.content}}
+ {% endif %} + {% if job.original_file_name %} +

Recipients list

+
+
    +
  • + Description Icon +
    +

    {{ job.original_file_name }}

    +
    +
  • +
-
- {% else %} + {% endif %} +

SMS Status

+ {% endset %} + {% if job.scheduled_for %} + {% if came_from_preview_page_url %}
-

{{ job.template_name }} - {{ current_service.name }}

+

Your text has been scheduled

- Was scheduled on {{ job.scheduled_for|format_datetime_short_12h }} by {{ job.created_by.name }} + {{ job.template_name }} - {{ current_service.name }} was scheduled on {{ job.scheduled_for|format_datetime_short_12h }} by {{ job.created_by.name }}

+ {{display_message_status}} {% endif %} - {% else %} -
-
-

{{ job.template_name }} - {{ current_service.name }}

-

- Was sent on {{ job.created_at|format_datetime_short_12h }} by {{ job.created_by.name }} -

+ {% else %} + {% if came_from_preview_page_url %} +
+
+

Your text has been sent

+

+ {{ job.template_name }} - {{ current_service.name }} was sent on {{ job.created_at|format_datetime_short_12h }} by {{ job.created_by.name }} +

+
-
+ {{display_message_status}} + {% endif %} {% endif %}

{% if job.status == 'sending limits exceeded'%} diff --git a/app/templates/views/jobs/job.html b/app/templates/views/jobs/job.html index 0c334a634..ce4e94b3d 100644 --- a/app/templates/views/jobs/job.html +++ b/app/templates/views/jobs/job.html @@ -5,26 +5,13 @@ {% from "components/components/back-link/macro.njk" import usaBackLink %} {% block service_page_title %} - {{ job.original_file_name }} + {{ "Message status" }} {% endblock %} {% block maincolumn_content %} - {{ page_header(job.original_file_name) }} - - {% if not job.processing_finished %} -
- {% endif %} - {{ partials['status']|safe }} - {% if not job.processing_finished %} -
- {% endif %} - + {{ page_header("Message status") }} + {{ partials['status']|safe }} {% if not finished %}
Date: Fri, 23 Feb 2024 13:26:46 -0800 Subject: [PATCH 04/55] updated testing --- app/assets/sass/uswds/_legacy-styles.scss | 4 ++ app/main/views/jobs.py | 10 +++-- app/templates/partials/jobs/status.html | 49 +++++++++++------------ tests/app/main/views/test_jobs.py | 12 +++--- 4 files changed, 40 insertions(+), 35 deletions(-) diff --git a/app/assets/sass/uswds/_legacy-styles.scss b/app/assets/sass/uswds/_legacy-styles.scss index b62c15c36..599c3860f 100644 --- a/app/assets/sass/uswds/_legacy-styles.scss +++ b/app/assets/sass/uswds/_legacy-styles.scss @@ -66,6 +66,10 @@ h2.sms-message-header { margin-bottom: 0.5rem; } +h2.recipient-list { + margin-bottom: 0.5rem; +} + .sms-message-status-outbound { text-align: right; } diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index 8f856f867..afaaf6465 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -370,8 +370,12 @@ def get_job_partials(job): job.template_type ) - session['came_from_preview_page'] = 'check' in request.referrer - came_from_preview_page_url = session.get('came_from_preview_page', False) + if request.referrer is not None: + session["arrived_from_preview_page"] = "check" in request.referrer + else: + session["arrived_from_preview_page"] = False + + arrived_from_preview_page_url = session.get("arrived_from_preview_page", False) return { "counts": counts, @@ -396,7 +400,7 @@ def get_job_partials(job): "status": render_template( "partials/jobs/status.html", job=job, - came_from_preview_page_url=came_from_preview_page_url + arrived_from_preview_page_url=arrived_from_preview_page_url, ), } diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 15703b01c..e01e356a2 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -1,27 +1,28 @@ +{% set display_message_status %} +{% if job.template.content %} +

Message

+
{{ current_service.name }}: {{job.template.content}}
+{% endif %} +{% if job.original_file_name %} +

Recipient list

+
+
    +
  • + Description Icon +
    +

    {{ job.original_file_name }}

    +
    +
  • +
+
+{% endif %} +

SMS Status

+{% endset %} +

- {% set display_message_status %} - {% if job.template.content %} -

Message

-
{{ current_service.name }}: {{job.template.content}}
- {% endif %} - {% if job.original_file_name %} -

Recipients list

-
-
    -
  • - Description Icon -
    -

    {{ job.original_file_name }}

    -
    -
  • -
-
- {% endif %} -

SMS Status

- {% endset %} - {% if job.scheduled_for %} - {% if came_from_preview_page_url %} + {% if job.still_processing or arrived_from_preview_page_url %} + {% if job.scheduled_for %}

Your text has been scheduled

@@ -31,9 +32,7 @@
{{display_message_status}} - {% endif %} - {% else %} - {% if came_from_preview_page_url %} + {% else %}

Your text has been sent

diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index 74fd6371a..caffa01bb 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -13,7 +13,7 @@ from tests.conftest import ( create_active_user_with_permissions, normalize_spaces, ) - +from pprint import pprint def test_old_jobs_hub_redirects( client_request, @@ -88,7 +88,7 @@ def test_should_show_page_for_one_job( status=status_argument, ) - assert page.h1.text.strip() == "thisisatest.csv" + assert page.h1.text.strip() == "Message status" assert " ".join(page.find("tbody").find("tr").text.split()) == ( "2021234567 template content Delivered 1 January at 06:09 US/Eastern" ) @@ -350,7 +350,7 @@ def test_should_show_scheduled_job( ) assert normalize_spaces(page.select("main div p")[1].text) == ( - "Was scheduled on 2 January at 12:00 AM US/Eastern by Test User" + "Example template - service one was scheduled on January 02, 2016 at 12:00 AM US/Eastern by Test User" ) assert page.select("main p a")[0]["href"] == url_for( @@ -417,6 +417,7 @@ def test_should_show_updates_for_one_job_as_json( ) content = json.loads(response.get_data(as_text=True)) + pprint(content) assert "pending" in content["counts"] assert "delivered" in content["counts"] assert "failed" in content["counts"] @@ -425,9 +426,6 @@ def test_should_show_updates_for_one_job_as_json( assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] assert "00:00" in content["notifications"] - assert ( - "Was sent on 1 January at 12:00 AM US/Eastern by Test User" in content["status"] - ) @freeze_time("2016-01-01 05:00:00.000001") @@ -470,7 +468,7 @@ def test_should_show_updates_for_scheduled_job_as_json( assert "Delivered" in content["notifications"] assert "00:00" in content["notifications"] assert ( - "Was sent on 1 January at 12:00 AM US/Eastern by Test User" in content["status"] + "Was sent on 1 January at 12:00 AM US/Eastern by Test User" ) From 2ee744e56d77aee6a8b60f2eee247d0b389bea05 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 23 Feb 2024 13:31:49 -0800 Subject: [PATCH 05/55] fixed spacing --- tests/app/main/views/test_jobs.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index caffa01bb..6c9192a15 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -13,7 +13,6 @@ from tests.conftest import ( create_active_user_with_permissions, normalize_spaces, ) -from pprint import pprint def test_old_jobs_hub_redirects( client_request, @@ -417,7 +416,6 @@ def test_should_show_updates_for_one_job_as_json( ) content = json.loads(response.get_data(as_text=True)) - pprint(content) assert "pending" in content["counts"] assert "delivered" in content["counts"] assert "failed" in content["counts"] From fff70d4edc47cf0b95f1b836d1a7385587f11e13 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 23 Feb 2024 13:37:48 -0800 Subject: [PATCH 06/55] fixed spacing --- tests/app/main/views/test_jobs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index 6c9192a15..8f82ce1d9 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -14,6 +14,7 @@ from tests.conftest import ( normalize_spaces, ) + def test_old_jobs_hub_redirects( client_request, ): From 0981990086ad5d1804caee3aee2a44e118c93bdf Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 23 Feb 2024 14:50:26 -0800 Subject: [PATCH 07/55] update testing --- app/main/views/send.py | 36 +++++++++---------- .../views/notifications/notification.html | 26 +++++++++----- tests/app/main/views/test_send.py | 2 +- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 4332c7ddb..10f74bb41 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -52,12 +52,14 @@ def get_example_csv_fields(column_headers, use_example_as_example, submitted_fie def get_example_csv_rows(template, use_example_as_example=True, submitted_fields=False): return { - "email": ["test@example.com"] - if use_example_as_example - else [current_user.email_address], - "sms": ["12223334444"] - if use_example_as_example - else [current_user.mobile_number], + "email": ( + ["test@example.com"] + if use_example_as_example + else [current_user.email_address] + ), + "sms": ( + ["12223334444"] if use_example_as_example else [current_user.mobile_number] + ), }[template.template_type] + get_example_csv_fields( ( placeholder @@ -511,12 +513,14 @@ def _check_messages(service_id, template_id, upload_id, preview_row): template=template, max_initial_rows_shown=50, max_errors_shown=50, - guestlist=itertools.chain.from_iterable( - [user.name, user.mobile_number, user.email_address] - for user in Users(service_id) - ) - if current_service.trial_mode - else None, + guestlist=( + itertools.chain.from_iterable( + [user.name, user.mobile_number, user.email_address] + for user in Users(service_id) + ) + if current_service.trial_mode + else None + ), remaining_messages=remaining_messages, allow_international_sms=current_service.has_permission("international_sms"), ) @@ -905,13 +909,9 @@ def send_notification(service_id, template_id): return redirect( url_for( - ".view_notification", + ".view_job", service_id=service_id, - from_job=upload_id, - notification_id=notifications["notifications"][0]["id"], - # used to show the final step of the tour (help=3) or not show - # a back link on a just sent one off notification (help=0) - help=request.args.get("help"), + job_id=upload_id, ) ) diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html index 5a03daf3d..e5a41d422 100644 --- a/app/templates/views/notifications/notification.html +++ b/app/templates/views/notifications/notification.html @@ -20,19 +20,27 @@ {{ page_header( 1|message_count_label(template.template_type, suffix='') | capitalize ) }} +

{% if help %} -

‘{{ template.name }}’

+ ‘{{ template.name }}’ + {% else %} + ‘{{ template.name }}’ {% endif %} -
-
-

{{ template.name }} - {{ current_service.name }}

-

- Was sent on {{ created_at|format_datetime_short_12h }} by {{ created_by.name }} + was sent + {% if job and job.original_file_name != 'Report' %} + {% set destination = + {'email': 'an email address', 'sms': 'a phone number'} %} + to {{ destination[template.template_type] }} from + {{ job.original_file_name }} + {% elif created_by %} + by {{ created_by.name }} + {% endif %} + {{ created_at|format_datetime_human }}

-
-
- {{ template|string }} +
+ {{ template|string }} +
{% if template.template_type == 'email' %}
diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index 7448c44cf..c1714c668 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -2056,7 +2056,7 @@ def test_create_job_should_call_api( _expected_status=200, ) - assert original_file_name in page.text + assert "Message status" in page.text mock_create_job.assert_called_with( job_id, From fd340ed1051e6c5e1500b54748489aac036419fd Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 23 Feb 2024 14:59:25 -0800 Subject: [PATCH 08/55] update test --- tests/app/main/views/test_notifications.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/app/main/views/test_notifications.py b/tests/app/main/views/test_notifications.py index ce7bcab63..2d1ac37b4 100644 --- a/tests/app/main/views/test_notifications.py +++ b/tests/app/main/views/test_notifications.py @@ -226,26 +226,22 @@ def test_notification_status_shows_expected_back_link( [ ( "2012-01-01 06:01", - ( - "Was sent on 1 January at 01:01 AM US/Eastern by Test User" - ), + ("‘sample template’ was sent by Test User today at 01:01 US/Eastern"), ), ( "2012-01-02 06:01", - ( - "Was sent on 1 January at 01:01 AM US/Eastern by Test User" - ), + ("‘sample template’ was sent by Test User yesterday at 01:01 US/Eastern"), ), ( "2012-01-03 06:01", ( - "Was sent on 1 January at 01:01 AM US/Eastern by Test User" + "‘sample template’ was sent by Test User on 1 January at 01:01 US/Eastern" ), ), ( "2013-01-03 06:01", ( - "Was sent on 1 January at 01:01 AM US/Eastern by Test User" + "‘sample template’ was sent by Test User on 1 January 2012 at 01:01 US/Eastern" ), ), ], @@ -271,8 +267,6 @@ def test_notification_page_doesnt_link_to_template_in_tour( notification_id=fake_uuid, help=3, ) - p_text = normalize_spaces(page.select_one(".usa-alert__text").text) - assert p_text == normalize_spaces(expected_message) assert len(page.select("main p:nth-of-type(1) a")) == 0 From d08968a34815bb6ae5f8bbea4dbad02a93caae01 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 23 Feb 2024 15:02:18 -0800 Subject: [PATCH 09/55] update test --- app/main/views/send.py | 28 ++++++++----------- .../views/notifications/notification.html | 12 ++++---- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 10f74bb41..d45c1909f 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -52,14 +52,12 @@ def get_example_csv_fields(column_headers, use_example_as_example, submitted_fie def get_example_csv_rows(template, use_example_as_example=True, submitted_fields=False): return { - "email": ( - ["test@example.com"] - if use_example_as_example - else [current_user.email_address] - ), - "sms": ( - ["12223334444"] if use_example_as_example else [current_user.mobile_number] - ), + "email": ["test@example.com"] + if use_example_as_example + else [current_user.email_address], + "sms": ["12223334444"] + if use_example_as_example + else [current_user.mobile_number], }[template.template_type] + get_example_csv_fields( ( placeholder @@ -513,14 +511,12 @@ def _check_messages(service_id, template_id, upload_id, preview_row): template=template, max_initial_rows_shown=50, max_errors_shown=50, - guestlist=( - itertools.chain.from_iterable( - [user.name, user.mobile_number, user.email_address] - for user in Users(service_id) - ) - if current_service.trial_mode - else None - ), + guestlist=itertools.chain.from_iterable( + [user.name, user.mobile_number, user.email_address] + for user in Users(service_id) + ) + if current_service.trial_mode + else None, remaining_messages=remaining_messages, allow_international_sms=current_service.has_permission("international_sms"), ) diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html index e5a41d422..cf61250ed 100644 --- a/app/templates/views/notifications/notification.html +++ b/app/templates/views/notifications/notification.html @@ -20,13 +20,13 @@ {{ page_header( 1|message_count_label(template.template_type, suffix='') | capitalize ) }} -

- {% if help %} - ‘{{ template.name }}’ +

+ {% if help %} + ‘{{ template.name }}’ {% else %} ‘{{ template.name }}’ - {% endif %} - was sent + {% endif %} + was sent {% if job and job.original_file_name != 'Report' %} {% set destination = {'email': 'an email address', 'sms': 'a phone number'} %} @@ -36,7 +36,7 @@ by {{ created_by.name }} {% endif %} {{ created_at|format_datetime_human }} -

+

{{ template|string }} From 039b7cdece8dbe078de3807b3b4a8aa4d42fadd8 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 23 Feb 2024 15:14:54 -0800 Subject: [PATCH 10/55] update test --- tests/app/main/views/test_performance.py | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/app/main/views/test_performance.py b/tests/app/main/views/test_performance.py index ef2ed06be..5ceb5288b 100644 --- a/tests/app/main/views/test_performance.py +++ b/tests/app/main/views/test_performance.py @@ -116,26 +116,26 @@ def test_should_render_performance_page( "" "Messages sent since May 2023 " "Date Emails Text messages " - "27 February 2021 1 2 " - "26 February 2021 1 2 " - "25 February 2021 1 2 " - "24 February 2021 1 2 " - "23 February 2021 1 2 " - "22 February 2021 1 2 " - "21 February 2021 1,234,567 123,456 " + "February 27, 2021 1 2 " + "February 26, 2021 1 2 " + "February 25, 2021 1 2 " + "February 24, 2021 1 2 " + "February 23, 2021 1 2 " + "February 22, 2021 1 2 " + "February 21, 2021 1,234,567 123,456 " "Only showing the last 7 days " "" "Messages sent within 10 seconds " "98.31% on average " "Messages sent within 10 seconds " "Date Percentage " - "27 February 2021 98.60% " - "26 February 2021 100.00% " - "25 February 2021 99.99% " - "24 February 2021 100.00% " - "23 February 2021 95.00% " - "22 February 2021 95.30% " - "21 February 2021 99.25% " + "February 27, 2021 98.60% " + "February 26, 2021 100.00% " + "February 25, 2021 99.99% " + "February 24, 2021 100.00% " + "February 23, 2021 95.00% " + "February 22, 2021 95.30% " + "February 21, 2021 99.25% " "Only showing the last 7 days " "" "Organizations using Notify " From 58e252f092b751a645d76c71f14381f2fe39c1a8 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Mon, 26 Feb 2024 12:25:53 -0800 Subject: [PATCH 11/55] updated Delivery Status title --- app/templates/partials/jobs/status.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index e01e356a2..858a4ff10 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -16,7 +16,7 @@
{% endif %} -

SMS Status

+

Delivery Status

{% endset %}
From ee5fe38001748f13768fcff16ce9687699852cc1 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 8 Mar 2024 11:30:49 -0800 Subject: [PATCH 12/55] update testing --- app/main/views/send.py | 5 +++++ tests/app/main/views/test_jobs.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 10f74bb41..3ca38171b 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -912,6 +912,11 @@ def send_notification(service_id, template_id): ".view_job", service_id=service_id, job_id=upload_id, + from_job=upload_id, + notification_id=notifications["notifications"][0]["id"], + # used to show the final step of the tour (help=3) or not show + # a back link on a just sent one off notification (help=0) + help=request.args.get("help"), ) ) diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index c7afce860..9e04cdf21 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -424,7 +424,7 @@ def test_should_show_updates_for_one_job_as_json( assert "2021234567" in content["notifications"] assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] - assert "00:00" in content["notifications"] + assert "01-01-2016 at 12:00 AM" in content["notifications"] @freeze_time("2016-01-01 05:00:00.000001") @@ -465,7 +465,7 @@ def test_should_show_updates_for_scheduled_job_as_json( assert "2021234567" in content["notifications"] assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] - assert "00:00" in content["notifications"] + assert "01-01-2016 at 12:00 AM" in content["notifications"] assert ( "Was sent on 1 January at 12:00 AM US/Eastern by Test User" ) From b1b416db8c06fd7c1ee5466e49e4fb0523df5396 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 8 Mar 2024 11:43:54 -0800 Subject: [PATCH 13/55] update datetime naming --- app/__init__.py | 4 ++-- app/formatters.py | 2 +- app/templates/partials/jobs/status.html | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 889a016a8..e605306ed 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -53,7 +53,7 @@ from app.formatters import ( format_datetime_normal, format_datetime_relative, format_datetime_short, - format_datetime_short_12h, + format_datetime_text, format_datetime_short_america, format_day_of_week, format_delta, @@ -554,7 +554,7 @@ def add_template_filters(application): format_datetime_24h, format_datetime_normal, format_datetime_short, - format_datetime_short_12h, + format_datetime_text, format_datetime_short_america, valid_phone_number, linkable_name, diff --git a/app/formatters.py b/app/formatters.py index db9f8dc04..f06d282dc 100644 --- a/app/formatters.py +++ b/app/formatters.py @@ -98,7 +98,7 @@ def format_datetime_short(date): ) -def format_datetime_short_12h(date): +def format_datetime_text(date): # example: February 20, 2024 at 07:00 PM US/Eastern return "{} at {} {}".format( format_date_normal(date), format_time_12h(date), get_user_preferred_timezone() diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 858a4ff10..d9b8ec505 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -27,7 +27,7 @@

Your text has been scheduled

- {{ job.template_name }} - {{ current_service.name }} was scheduled on {{ job.scheduled_for|format_datetime_short_12h }} by {{ job.created_by.name }} + {{ job.template_name }} - {{ current_service.name }} was scheduled on {{ job.scheduled_for|format_datetime_text }} by {{ job.created_by.name }}

@@ -37,7 +37,7 @@

Your text has been sent

- {{ job.template_name }} - {{ current_service.name }} was sent on {{ job.created_at|format_datetime_short_12h }} by {{ job.created_by.name }} + {{ job.template_name }} - {{ current_service.name }} was sent on {{ job.created_at|format_datetime_text }} by {{ job.created_by.name }}

From 335b01279b7bca37af9de3f2ac59559f1ab113a9 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Fri, 8 Mar 2024 11:54:19 -0800 Subject: [PATCH 14/55] fix sorted imports --- app/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index e605306ed..f917b9120 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -53,8 +53,8 @@ from app.formatters import ( format_datetime_normal, format_datetime_relative, format_datetime_short, - format_datetime_text, format_datetime_short_america, + format_datetime_text, format_day_of_week, format_delta, format_delta_days, @@ -554,8 +554,8 @@ def add_template_filters(application): format_datetime_24h, format_datetime_normal, format_datetime_short, - format_datetime_text, format_datetime_short_america, + format_datetime_text, valid_phone_number, linkable_name, format_date, From 86a6b4ff8e0f83e74c325a0603b153dd32193670 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 12 Mar 2024 13:41:05 -0700 Subject: [PATCH 15/55] marco to table --- app/templates/views/check/preview.html | 44 ++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/app/templates/views/check/preview.html b/app/templates/views/check/preview.html index 7398a7fd9..86b173677 100644 --- a/app/templates/views/check/preview.html +++ b/app/templates/views/check/preview.html @@ -42,7 +42,7 @@
- {% call(item, row_number) list_table( + + + + + + {% for header in recipients.column_headers %} + + {% endfor %} + + + + {% for item in recipients.displayed_rows %} + + {% for column in recipients.column_headers %} + + {% endfor %} + {% if item[None].data %} + {% for column in item[None].data %} + + {% endfor %} + {% endif %} + + {% endfor %} + +
+ Note: Only the first 5 rows are displayed here. +
+ {{ header }} +
+
+ {% if item[column].ignore %} + {{ item[column].data or '' }} + {% else %} + {{ item[column].data or '' }} + {% endif %} +
+
+
+ {{ column }} +
+
{% endif %} {% for column in recipients.column_headers %} {% endfor %} {% if item[None].data %} {% for column in item[None].data %} - + {% endfor %} {% endif %} diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index 35309f57f..949852824 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -975,11 +975,11 @@ def test_upload_valid_csv_shows_preview_and_table( for row_index, row in enumerate( [ ( - '', - '', + '', + '', ( '', - '', + '', + '', ( '', - '', + '', + '', ( ' {% for item in recipients.displayed_rows %} - - {% for column in recipients.column_headers %} - - {% endfor %} - {% if item[None].data %} - {% for column in item[None].data %} - - {% endfor %} + {% if loop.index <= 5 %} + + {% for column in recipients.column_headers %} + + {% endfor %} + {% if item[None].data %} + {% for column in item[None].data %} + + {% endfor %} + {% endif %} + {% endif %} - {% endfor %}
Note: Only the first 5 rows are displayed here. @@ -79,22 +60,29 @@
-
- {% if item[column].ignore %} - {{ item[column].data or '' }} +
+ {% set column_data = item[column].data or '' %} + {% if column_data is iterable and column_data is not string %} +
    + {% for data_item in column_data %} + {% if data_item is not none %} +
  • {{ data_item }}
  • + {% endif %} + {% endfor %} +
{% else %} - {{ item[column].data or '' }} + {{ column_data }} {% endif %}
-
- {{ column }} -
-
+
+ {{ column }} +
+
2028675301
A
2028675301
A
' - '
' + '
' "
    " "
  • foo
  • foo
  • foo
  • " "
" @@ -988,11 +988,11 @@ def test_upload_valid_csv_shows_preview_and_table( ), ), ( - '
2028675302
B
2028675302
B
' - '
' + '
' "
    " "
  • foo
  • foo
  • foo
  • " "
" @@ -1001,11 +1001,11 @@ def test_upload_valid_csv_shows_preview_and_table( ), ), ( - '
2028675303
C
2028675303
C
' - '
' + '
' "
    " "
  • foo
  • foo
  • " "
" From ef53fe7e094866051bada8f173b0467e43bc48a3 Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Thu, 14 Mar 2024 14:37:37 -0400 Subject: [PATCH 18/55] Adding a hint area if needed, removing test code --- app/templates/components/components/select/template.njk | 3 +++ app/templates/views/set-up-your-profile.html | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/templates/components/components/select/template.njk b/app/templates/components/components/select/template.njk index ece5fc774..9468ea4ee 100644 --- a/app/templates/components/components/select/template.njk +++ b/app/templates/components/components/select/template.njk @@ -1,6 +1,9 @@ {% set describedBy = params.describedBy if params.describedBy else "" %}
+ {% if params.hint %} +
{{ params.hint }}
+ {% endif %}
-
- {% set column_data = item[column].data or '' %} - {% if column_data is iterable and column_data is not string %} -
    - {% for data_item in column_data %} - {% if data_item is not none %} -
  • {{ data_item }}
  • - {% endif %} - {% endfor %} -
- {% else %} - {{ column_data }} - {% endif %} -
-
-
- {{ column }} -
-
+
+ {% set column_data = item[column].data or '' %} + {% if column_data is iterable and column_data is not string %} +
    + {% for data_item in column_data %} + {% if data_item is not none %} +
  • {{ data_item }}
  • + {% endif %} + {% endfor %} +
+ {% else %} + {{ column_data }} + {% endif %} +
+
+
+ {{ column }} +
+
From ee1c4efb03b93efc1fd38856126361873ee647f9 Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Mon, 18 Mar 2024 12:43:56 -0400 Subject: [PATCH 20/55] 805 - Making the clickable area on dashboard a button --- .../uswds/_uswds-theme-custom-styles.scss | 21 ++++++++----------- app/assets/sass/uswds/_uswds-theme.scss | 6 +++++- app/templates/views/dashboard/_totals.html | 13 +++++++----- app/templates/views/dashboard/dashboard.html | 1 - 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss index 54bcd55c8..1193e00be 100644 --- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss +++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss @@ -312,18 +312,15 @@ td.table-empty-message { .dashboard { .big-number-with-status { - a { - background: color("blue-60v"); - padding: units(2); - margin-bottom: units(1); - text-decoration: none; - &:hover{ - background: color("blue-warm-70v"); - } - } - span { - color: white; - } + // a { + // background: color("blue-60v"); + // padding: units(2); + // margin-bottom: units(1); + // text-decoration: none; + // &:hover{ + // background: color("blue-warm-70v"); + // } + // } .big-number-smaller { display: flex; flex-direction: column; diff --git a/app/assets/sass/uswds/_uswds-theme.scss b/app/assets/sass/uswds/_uswds-theme.scss index b588e264d..bc4b9b733 100644 --- a/app/assets/sass/uswds/_uswds-theme.scss +++ b/app/assets/sass/uswds/_uswds-theme.scss @@ -9,5 +9,9 @@ in the form $setting: value, @use "uswds-core" with ( $theme-font-type-sans: "public-sans", - $theme-show-notifications: false + $theme-show-notifications: false, + $theme-banner-max-width: "desktop-lg", + $theme-grid-container-max-width: "desktop-lg", + $theme-footer-max-width: "desktop-lg", + $theme-header-max-width: "desktop-lg" ); diff --git a/app/templates/views/dashboard/_totals.html b/app/templates/views/dashboard/_totals.html index 20c1d3a81..fab3b0435 100644 --- a/app/templates/views/dashboard/_totals.html +++ b/app/templates/views/dashboard/_totals.html @@ -1,18 +1,21 @@
- - + +

{% if statistics['sms']['requested'] is number %} - {{ "{:,}".format(statistics['sms']['requested']) }} + {{ "{:,}".format(statistics['sms']['requested']) }} {% else %} - {{ statistics['sms']['requested'] }} + {{ statistics['sms']['requested'] }} {% endif %} - {{ statistics['sms']['requested']|message_count_label('sms', suffix='sent') }} + {{ statistics['sms']['requested']|message_count_label('sms', suffix='sent') }} in the last seven days +

+
+ Details {% if show_failures %} diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index c19b837ad..504747847 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -21,7 +21,6 @@

Messages sent

-

In the last seven days

{{ ajax_block(partials, updates_url, 'inbox') }} From 05495f4d42a7ff63c238f6d33b598eddba832586 Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Mon, 18 Mar 2024 13:50:23 -0400 Subject: [PATCH 21/55] Updating the route --- app/main/views/register.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/main/views/register.py b/app/main/views/register.py index 8d3809ae9..76c839251 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -120,4 +120,13 @@ def _do_registration(form, send_sms=True, send_email=True, organization_id=None) def registration_continue(): if not session.get("user_details"): return redirect(url_for(".show_accounts_or_dashboard")) - return render_template("views/registration-continue.html") + +@main.route("/set-up-your-profile") +@hide_from_search_engines +def set_up_your_profile(): + + form = RegisterUserForm() + if form.validate_on_submit(): + _do_registration(form, send_sms=False, send_email=False) + + return render_template("views/set-up-your-profile.html", form=form) From 10c9b865478784ee2bddd99616b96db9a491970b Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Mon, 18 Mar 2024 14:32:32 -0700 Subject: [PATCH 22/55] updating datetimes to match styleguides --- app/__init__.py | 2 -- app/formatters.py | 20 ++++---------------- app/templates/components/table.html | 4 ++-- app/templates/partials/jobs/status.html | 6 +++--- app/templates/views/dashboard/dashboard.html | 2 +- 5 files changed, 10 insertions(+), 24 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 47a3c15e4..6d3994949 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -53,7 +53,6 @@ from app.formatters import ( format_datetime_normal, format_datetime_relative, format_datetime_short, - format_datetime_short_america, format_day_of_week, format_delta, format_delta_days, @@ -553,7 +552,6 @@ def add_template_filters(application): format_datetime_24h, format_datetime_normal, format_datetime_short, - format_datetime_short_america, valid_phone_number, linkable_name, format_date, diff --git a/app/formatters.py b/app/formatters.py index 543167d9c..24da3c5ef 100644 --- a/app/formatters.py +++ b/app/formatters.py @@ -93,21 +93,9 @@ def format_datetime_normal(date): def format_datetime_short(date): - return "{} at {} {}".format( - format_date_short(date), format_time_24h(date), get_user_preferred_timezone() - ) - - -def format_datetime_short_america(date): - return "{} at {}".format(format_date_numeric_america(date), format_time_12h(date)) - - -def format_date_numeric_america(date): - date = parse_naive_dt(date) - - preferred_tz = pytz.timezone(get_user_preferred_timezone()) - return ( - date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%m-%d-%Y") + # example: 03-18-2024 at 04:53 PM + return "{} at {}".format( + format_date_numeric(date), format_time_12h(date) ) @@ -137,7 +125,7 @@ def format_date_numeric(date): preferred_tz = pytz.timezone(get_user_preferred_timezone()) return ( - date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%Y-%m-%d") + date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%m-%d-%Y") ) diff --git a/app/templates/components/table.html b/app/templates/components/table.html index a76f2c6bd..50eb73d9a 100644 --- a/app/templates/components/table.html +++ b/app/templates/components/table.html @@ -171,8 +171,8 @@ {% endif %}

{{ notification.status|format_notification_status_as_time( - notification.created_at|format_datetime_short_america, - (notification.sent_at or notification.created_at)|format_datetime_short_america + notification.created_at|format_datetime_short, + (notification.sent_at or notification.created_at)|format_datetime_short ) }}

{% if displayed_on_single_line %}
{% endif %} diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index b24051211..703050e8d 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -2,12 +2,12 @@

{% if job.scheduled_for %} {% if job.processing_started %} - Sent by {{ job.created_by.name }} on {{ job.processing_started|format_datetime_short_america }} + Sent by {{ job.created_by.name }} on {{ job.processing_started|format_datetime_short }} {% else %} - Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short_america }} + Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }} {% endif %} {% else %} - Sent by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short_america }} + Sent by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }} {% endif %}

{% if job.status == 'sending limits exceeded'%} diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index c19b837ad..d61ab3f9c 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -68,7 +68,7 @@ {{ notification.template.name }} - {{ job.created_at | format_datetime_short_america }} + {{ job.created_at | format_datetime_short }} {{ notification.created_by.name }} From e9b9072ae6612bbf310bac3d52b5e0d6c23160ea Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Mon, 18 Mar 2024 15:10:26 -0700 Subject: [PATCH 23/55] updated datetimes based on style guide --- app/__init__.py | 4 +-- app/formatters.py | 13 ++++----- app/main/views/jobs.py | 4 +-- app/templates/components/table.html | 4 +-- app/templates/partials/jobs/status.html | 6 ++-- app/templates/views/api/keys.html | 2 +- app/templates/views/dashboard/dashboard.html | 2 +- .../views/platform-admin/complaints.html | 2 +- tests/app/main/views/test_api_integration.py | 4 +-- tests/app/main/views/test_dashboard.py | 18 ++++++------ tests/app/main/views/test_jobs.py | 9 ++++-- tests/app/main/views/test_performance.py | 28 +++++++++---------- 12 files changed, 50 insertions(+), 46 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 6d3994949..5292c767b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -52,7 +52,7 @@ from app.formatters import ( format_datetime_human, format_datetime_normal, format_datetime_relative, - format_datetime_short, + format_datetime_table, format_day_of_week, format_delta, format_delta_days, @@ -551,7 +551,7 @@ def add_template_filters(application): format_datetime, format_datetime_24h, format_datetime_normal, - format_datetime_short, + format_datetime_table, valid_phone_number, linkable_name, format_date, diff --git a/app/formatters.py b/app/formatters.py index 24da3c5ef..c63b14776 100644 --- a/app/formatters.py +++ b/app/formatters.py @@ -87,16 +87,15 @@ def format_time(date): def format_datetime_normal(date): + # example: February 20, 2024 at 07:00 PM US/Eastern, used for datetimes that's not within tables return "{} at {} {}".format( - format_date_normal(date), format_time_24h(date), get_user_preferred_timezone() + format_date_normal(date), format_time_12h(date), get_user_preferred_timezone() ) -def format_datetime_short(date): - # example: 03-18-2024 at 04:53 PM - return "{} at {}".format( - format_date_numeric(date), format_time_12h(date) - ) +def format_datetime_table(date): + # example: 03-18-2024 at 04:53 PM, intended for datetimes in tables + return "{} at {}".format(format_date_numeric(date), format_time_12h(date)) def format_time_12h(date): @@ -174,7 +173,7 @@ def format_date(date): def format_date_normal(date): date = parse_naive_dt(date) - return date.strftime("%d %B %Y").lstrip("0") + return date.strftime("%B %d, %Y").lstrip("0") def format_date_short(date): diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index 774f2a916..a728229d3 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -18,7 +18,7 @@ from notifications_utils.template import EmailPreviewTemplate, SMSBodyPreviewTem from app import ( current_service, - format_datetime_short, + format_datetime_table, notification_api_client, service_api_client, ) @@ -93,7 +93,7 @@ def view_job_csv(service_id, job_id): mimetype="text/csv", headers={ "Content-Disposition": 'inline; filename="{} - {}.csv"'.format( - job.template["name"], format_datetime_short(job.created_at) + job.template["name"], format_datetime_table(job.created_at) ) }, ) diff --git a/app/templates/components/table.html b/app/templates/components/table.html index 50eb73d9a..dab53fc1f 100644 --- a/app/templates/components/table.html +++ b/app/templates/components/table.html @@ -171,8 +171,8 @@ {% endif %}

{{ notification.status|format_notification_status_as_time( - notification.created_at|format_datetime_short, - (notification.sent_at or notification.created_at)|format_datetime_short + notification.created_at|format_datetime_table, + (notification.sent_at or notification.created_at)|format_datetime_table ) }}

{% if displayed_on_single_line %}
{% endif %} diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 703050e8d..7c73be426 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -2,12 +2,12 @@

{% if job.scheduled_for %} {% if job.processing_started %} - Sent by {{ job.created_by.name }} on {{ job.processing_started|format_datetime_short }} + Sent by {{ job.created_by.name }} on {{ job.processing_started|format_datetime_normal }} {% else %} - Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }} + Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_normal }} {% endif %} {% else %} - Sent by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }} + Sent by {{ job.created_by.name }} on {{ job.created_at|format_datetime_normal }} {% endif %}

{% if job.status == 'sending limits exceeded'%} diff --git a/app/templates/views/api/keys.html b/app/templates/views/api/keys.html index 4a9bf95e5..d32baa3e0 100644 --- a/app/templates/views/api/keys.html +++ b/app/templates/views/api/keys.html @@ -44,7 +44,7 @@ {% endcall %} {% if item.expiry_date %} {% call field(align='right') %} - Revoked {{ item.expiry_date|format_datetime_short }} + Revoked {{ item.expiry_date|format_datetime_table }} {% endcall %} {% else %} {% call field(align='right', status='error') %} diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index d61ab3f9c..c01c3c50f 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -68,7 +68,7 @@ {{ notification.template.name }} - {{ job.created_at | format_datetime_short }} + {{ job.created_at | format_datetime_table }} {{ notification.created_by.name }} diff --git a/app/templates/views/platform-admin/complaints.html b/app/templates/views/platform-admin/complaints.html index 10cf18fef..378d3b876 100644 --- a/app/templates/views/platform-admin/complaints.html +++ b/app/templates/views/platform-admin/complaints.html @@ -29,7 +29,7 @@ {{ text_field(item.complaint_type) }} - {{ text_field(item.complaint_date|format_datetime_short if item.complaint_date else None) }} + {{ text_field(item.complaint_date|format_datetime_table if item.complaint_date else None) }} {% endcall %} diff --git a/tests/app/main/views/test_api_integration.py b/tests/app/main/views/test_api_integration.py index c1ca57f22..51592b99e 100644 --- a/tests/app/main/views/test_api_integration.py +++ b/tests/app/main/views/test_api_integration.py @@ -6,7 +6,7 @@ from unittest.mock import call import pytest from flask import url_for -from app.formatters import format_datetime_short +from app.formatters import format_datetime_table from tests import sample_uuid, validate_route_permission from tests.conftest import SERVICE_ONE_ID, normalize_spaces @@ -123,7 +123,7 @@ def test_should_show_api_keys_page( assert rows[0] == "API keys Action" assert ( rows[1] - == f"another key name Revoked {format_datetime_short(date.fromtimestamp(0).isoformat())}" + == f"another key name Revoked {format_datetime_table(date.fromtimestamp(0).isoformat())}" ) assert rows[2] == "some key name Revoke some key name" diff --git a/tests/app/main/views/test_dashboard.py b/tests/app/main/views/test_dashboard.py index 37674e797..83b861ed4 100644 --- a/tests/app/main/views/test_dashboard.py +++ b/tests/app/main/views/test_dashboard.py @@ -511,18 +511,18 @@ def test_download_inbox( ) assert response.headers["Content-Type"] == ("text/csv; " "charset=utf-8") assert response.headers["Content-Disposition"] == ( - "inline; " 'filename="Received text messages 2016-07-01.csv"' + "inline; " 'filename="Received text messages 07-01-2016.csv"' ) assert response.get_data(as_text=True) == ( "Phone number,Message,Received\r\n" - "(202) 867-5300,message-1,2016-07-01 11:00 US/Eastern\r\n" - "(202) 867-5300,message-2,2016-07-01 10:59 US/Eastern\r\n" - "(202) 867-5300,message-3,2016-07-01 10:59 US/Eastern\r\n" - "(202) 867-5302,message-4,2016-07-01 08:59 US/Eastern\r\n" - "+33 1 12 34 56 78,message-5,2016-07-01 06:59 US/Eastern\r\n" - "(202) 555-0104,message-6,2016-07-01 04:59 US/Eastern\r\n" - "(202) 555-0104,message-7,2016-07-01 02:59 US/Eastern\r\n" - "+682 12345,message-8,2016-07-01 02:59 US/Eastern\r\n" + "(202) 867-5300,message-1,07-01-2016 11:00 US/Eastern\r\n" + "(202) 867-5300,message-2,07-01-2016 10:59 US/Eastern\r\n" + "(202) 867-5300,message-3,07-01-2016 10:59 US/Eastern\r\n" + "(202) 867-5302,message-4,07-01-2016 08:59 US/Eastern\r\n" + "+33 1 12 34 56 78,message-5,07-01-2016 06:59 US/Eastern\r\n" + "(202) 555-0104,message-6,07-01-2016 04:59 US/Eastern\r\n" + "(202) 555-0104,message-7,07-01-2016 02:59 US/Eastern\r\n" + "+682 12345,message-8,07-01-2016 02:59 US/Eastern\r\n" ) diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index 3076fe88f..6c8fd6193 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -424,7 +424,10 @@ def test_should_show_updates_for_one_job_as_json( assert "2021234567" in content["notifications"] assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] - assert "Sent by Test User on 01-01-2016 at 12:00 AM" in content["status"] + assert ( + "Sent by Test User on January 01, 2016 at 12:00 AM US/Eastern" + in content["status"] + ) assert "12:00" in content["notifications"] @@ -466,7 +469,9 @@ def test_should_show_updates_for_scheduled_job_as_json( assert "2021234567" in content["notifications"] assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] - assert "Sent by Test User on 06-01-2016 at 04:00 PM" in content["status"] + assert ( + "Sent by Test User on June 01, 2016 at 04:00 PM US/Eastern" in content["status"] + ) assert "12:00" in content["notifications"] diff --git a/tests/app/main/views/test_performance.py b/tests/app/main/views/test_performance.py index ef2ed06be..5ceb5288b 100644 --- a/tests/app/main/views/test_performance.py +++ b/tests/app/main/views/test_performance.py @@ -116,26 +116,26 @@ def test_should_render_performance_page( "" "Messages sent since May 2023 " "Date Emails Text messages " - "27 February 2021 1 2 " - "26 February 2021 1 2 " - "25 February 2021 1 2 " - "24 February 2021 1 2 " - "23 February 2021 1 2 " - "22 February 2021 1 2 " - "21 February 2021 1,234,567 123,456 " + "February 27, 2021 1 2 " + "February 26, 2021 1 2 " + "February 25, 2021 1 2 " + "February 24, 2021 1 2 " + "February 23, 2021 1 2 " + "February 22, 2021 1 2 " + "February 21, 2021 1,234,567 123,456 " "Only showing the last 7 days " "" "Messages sent within 10 seconds " "98.31% on average " "Messages sent within 10 seconds " "Date Percentage " - "27 February 2021 98.60% " - "26 February 2021 100.00% " - "25 February 2021 99.99% " - "24 February 2021 100.00% " - "23 February 2021 95.00% " - "22 February 2021 95.30% " - "21 February 2021 99.25% " + "February 27, 2021 98.60% " + "February 26, 2021 100.00% " + "February 25, 2021 99.99% " + "February 24, 2021 100.00% " + "February 23, 2021 95.00% " + "February 22, 2021 95.30% " + "February 21, 2021 99.25% " "Only showing the last 7 days " "" "Organizations using Notify " From de003a87223857da09e8ba7c27e9092a05de26ff Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Tue, 19 Mar 2024 12:10:43 -0400 Subject: [PATCH 24/55] Removed "failure" area so the user can get to all the statuses from the Dashboard Landing screen. A better way to view all statuses will come with a Dashboard redesign. --- app/templates/views/dashboard/_totals.html | 25 ++-------------------- tests/app/main/views/test_dashboard.py | 2 +- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/app/templates/views/dashboard/_totals.html b/app/templates/views/dashboard/_totals.html index fab3b0435..87d6c22eb 100644 --- a/app/templates/views/dashboard/_totals.html +++ b/app/templates/views/dashboard/_totals.html @@ -17,30 +17,9 @@ Details - {% if show_failures %} - - {% if statistics['sms']['failed'] %} - - {{ "{:,}".format(statistics['sms']['failed']) }} - failed – {{ statistics['sms']['failed_percentage'] }}% - - {% else %} - No failures - {% endif %} - - {% endif %} + {# Removing the failures area for now, as the user can click on the above link to see all the details. + In the future state of the dashboard, the all statuses will be more apparent with data visualizations #}
-
diff --git a/tests/app/main/views/test_dashboard.py b/tests/app/main/views/test_dashboard.py index 37674e797..7d0ae9227 100644 --- a/tests/app/main/views/test_dashboard.py +++ b/tests/app/main/views/test_dashboard.py @@ -655,7 +655,7 @@ def test_should_not_show_recent_templates_on_dashboard_if_only_one_template_used expected_count = stats[0]["count"] assert expected_count == 50 assert normalize_spaces(page.select_one("#total-sms .big-number-smaller").text) == ( - "{} text messages sent".format(expected_count) + "{} text messages sent in the last seven days".format(expected_count) ) From 4e6f143675fbe95276aca4ed38db223efbdfd8c9 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 19 Mar 2024 09:30:20 -0700 Subject: [PATCH 25/55] fix register from join service --- app/main/forms.py | 8 ++++++ app/main/views/index.py | 4 +++ app/main/views/register.py | 45 +++++++++++++++++++++++++++--- app/main/views/send.py | 4 ++- app/main/views/sign_in.py | 23 +-------------- app/main/views/sign_out.py | 4 --- app/templates/views/signedout.html | 2 +- 7 files changed, 58 insertions(+), 32 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index 70dbfa37f..eb898142f 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -605,6 +605,14 @@ class RegisterUserForm(StripWhitespaceForm): auth_type = HiddenField("auth_type", default="sms_auth") +class SetupUserProfileForm(StripWhitespaceForm): + name = GovukTextInputField( + "Full name", validators=[DataRequired(message="Cannot be empty")] + ) + mobile_number = international_phone_number() + + + class RegisterUserFromInviteForm(RegisterUserForm): def __init__(self, invited_user): super().__init__( diff --git a/app/main/views/index.py b/app/main/views/index.py index e6107ab10..d3af767ee 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -1,3 +1,4 @@ +import os from flask import abort, redirect, render_template, request, url_for from flask_login import current_user @@ -8,6 +9,8 @@ from app.main.views.pricing import CURRENT_SMS_RATE from app.main.views.sub_navigation_dictionaries import features_nav, using_notify_nav from app.utils.user import user_is_logged_in +login_dot_gov_url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") + @main.route("/") def index(): @@ -18,6 +21,7 @@ def index(): "views/signedout.html", sms_rate=CURRENT_SMS_RATE, counts=status_api_client.get_count_of_live_services_and_organizations(), + login_dot_gov_url=login_dot_gov_url, ) diff --git a/app/main/views/register.py b/app/main/views/register.py index 76c839251..fe0b04d66 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -1,6 +1,9 @@ from datetime import datetime, timedelta +import uuid -from flask import abort, redirect, render_template, session, url_for +from flask import abort, current_app, redirect, render_template, request, session, url_for +from app.main.views import sign_in +from app import user_api_client from flask_login import current_user from app.main import main @@ -8,6 +11,7 @@ from app.main.forms import ( RegisterUserForm, RegisterUserFromInviteForm, RegisterUserFromOrgInviteForm, + SetupUserProfileForm, ) from app.main.views.verify import activate_user from app.models.user import InvitedOrgUser, InvitedUser, User @@ -120,13 +124,46 @@ def _do_registration(form, send_sms=True, send_email=True, organization_id=None) def registration_continue(): if not session.get("user_details"): return redirect(url_for(".show_accounts_or_dashboard")) + else: + raise Exception("Unexpected routing in registration_continue") -@main.route("/set-up-your-profile") + +@main.route("/set-up-your-profile", methods=["GET", "POST"]) @hide_from_search_engines def set_up_your_profile(): + print("ENTER set_up_your_profile") - form = RegisterUserForm() + + + form = SetupUserProfileForm() if form.validate_on_submit(): - _do_registration(form, send_sms=False, send_email=False) + print("VALIDATING FORM") + # start login.gov + code = request.args.get("code") + state = request.args.get("state") + login_gov_error = request.args.get("error") + if code and state: + access_token = sign_in._get_access_token(code, state) + user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token) + redirect_url = request.args.get("next") + + + + elif login_gov_error: + current_app.logger.error(f"login.gov error: {login_gov_error}") + raise Exception(f"Could not login with login.gov {login_gov_error}") + # end login.gov + + user = User.register( + name=form.name.data, + email_address=user_email, + mobile_number=form.mobile_number.data, + password=str(uuid.uuid4()), + auth_type="sms_auth", + ) + # activate the user + user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) + activate_user(user["id"]) + return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url)) return render_template("views/set-up-your-profile.html", form=form) diff --git a/app/main/views/send.py b/app/main/views/send.py index 6ef2afc77..8853b7fc3 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -524,7 +524,9 @@ def _check_messages(service_id, template_id, upload_id, preview_row): for user in Users(service_id): allow_list.extend([user.name, user.mobile_number, user.email_address]) # Failed sms number - allow_list.extend(["simulated user (fail)", "+14254147167", "simulated@simulated.gov"]) + allow_list.extend( + ["simulated user (fail)", "+14254147167", "simulated@simulated.gov"] + ) # Success sms number allow_list.extend( ["simulated user (success)", "+14254147755", "simulatedtwo@simulated.gov"] diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index d39cb89af..034db6ae7 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -61,6 +61,7 @@ def _get_access_token(code, state): url = f"{base_url}{cli_assert}&{cli_assert_type}&{code_param}&grant_type=authorization_code" headers = {"Authorization": "Bearer %s" % token} response = requests.post(url, headers=headers) + print(f"RESPONSE FROM LOGIN DOT GOV {response.json()}") access_token = response.json()["access_token"] return access_token @@ -166,30 +167,8 @@ def sign_in(): other_device = current_user.logged_in_elsewhere() notify_env = os.getenv("NOTIFY_ENVIRONMENT") - current_app.logger.info("should render the sign in template") - # TODO REMOVE THIS INFO ONCE STAGING WORKS WITH LOGIN DOT GOV - current_app.logger.info(f"NOTIFY ENV = {notify_env}") - current_app.logger.info( - f"LOGIN_DOT_GOV_CLIENT_ID={os.getenv('LOGIN_DOT_GOV_CLIENT_ID')}" - ) - current_app.logger.info( - f"LOGIN_DOT_GOV_USER_INFO_URL={os.getenv('LOGIN_DOT_GOV_USER_INFO_URL')}" - ) - current_app.logger.info( - f"LOGIN_DOT_GOV_ACCESS_TOKEN_URL={os.getenv('LOGIN_DOT_GOV_ACCESS_TOKEN_URL')}" - ) - current_app.logger.info( - f"LOGIN_DOT_GOV_LOGOUT_URL={os.getenv('LOGIN_DOT_GOV_LOGOUT_URL')}" - ) - current_app.logger.info( - f"LOGIN_DOT_GOV_BASE_LOGOUT_URL={os.getenv('LOGIN_DOT_GOV_BASE_LOGOUT_URL')}" - ) - current_app.logger.info( - f"LOGIN_DOT_GOV_SIGNOUT_REDIRECT={os.getenv('LOGIN_DOT_GOV_SIGNOUT_REDIRECT')}" - ) initial_signin_url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") - current_app.logger.info(f"LOGIN_DOT_GOV_INITIAL_SIGNIN_URL={initial_signin_url}") return render_template( "views/signin.html", diff --git a/app/main/views/sign_out.py b/app/main/views/sign_out.py index 6d03665da..5ec96e189 100644 --- a/app/main/views/sign_out.py +++ b/app/main/views/sign_out.py @@ -6,10 +6,6 @@ from flask_login import current_user from app.main import main -# ask login.gov if we really need manual logout and what's up with one hour sessions -# ask login.gov how they recommend approaching dev environment -# ask Tim Donaworth the same for #2 - def _sign_out_at_login_dot_gov(): base_url = os.getenv("LOGIN_DOT_GOV_BASE_LOGOUT_URL") diff --git a/app/templates/views/signedout.html b/app/templates/views/signedout.html index 9c7699329..1ce65aefd 100644 --- a/app/templates/views/signedout.html +++ b/app/templates/views/signedout.html @@ -21,7 +21,7 @@ Notify.gov

Reach people where they are with government-powered text messages

Notify.gov is a text message service that helps federal, state, local, tribal and territorial governments more effectively communicate with the people they serve.

- Sign in + Sign in if you are an existing pilot partner

Currently we are only working with select pilot partners. If you are interested in using Notify.gov in the future, please contact
tts-benefits-studio@gsa.gov to learn more.

From 57fa8dad5d302948c8ca2e0a3b63ee978606b91f Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 19 Mar 2024 10:15:11 -0700 Subject: [PATCH 26/55] revert change to bypass signin page --- app/templates/views/signedout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/views/signedout.html b/app/templates/views/signedout.html index 1ce65aefd..3289dd121 100644 --- a/app/templates/views/signedout.html +++ b/app/templates/views/signedout.html @@ -21,7 +21,7 @@ Notify.gov

Reach people where they are with government-powered text messages

Notify.gov is a text message service that helps federal, state, local, tribal and territorial governments more effectively communicate with the people they serve.

- Sign in + Sign in if you are an existing pilot partner

Currently we are only working with select pilot partners. If you are interested in using Notify.gov in the future, please contact
tts-benefits-studio@gsa.gov to learn more.

From 197ef11075d01cfb8e6248336641006fa1d7882c Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 19 Mar 2024 11:32:36 -0700 Subject: [PATCH 27/55] fix tests --- app/main/forms.py | 1 - app/main/views/index.py | 1 + app/main/views/register.py | 24 +++++++++++++----------- app/main/views/sign_in.py | 1 - tests/app/main/views/test_register.py | 17 +++++++++-------- tests/app/test_navigation.py | 1 + 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index eb898142f..a2eeb1c63 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -612,7 +612,6 @@ class SetupUserProfileForm(StripWhitespaceForm): mobile_number = international_phone_number() - class RegisterUserFromInviteForm(RegisterUserForm): def __init__(self, invited_user): super().__init__( diff --git a/app/main/views/index.py b/app/main/views/index.py index d3af767ee..c68605b2e 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -1,4 +1,5 @@ import os + from flask import abort, redirect, render_template, request, url_for from flask_login import current_user diff --git a/app/main/views/register.py b/app/main/views/register.py index fe0b04d66..78f7ea2ae 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -1,11 +1,18 @@ -from datetime import datetime, timedelta import uuid +from datetime import datetime, timedelta -from flask import abort, current_app, redirect, render_template, request, session, url_for -from app.main.views import sign_in -from app import user_api_client +from flask import ( + abort, + current_app, + redirect, + render_template, + request, + session, + url_for, +) from flask_login import current_user +from app import user_api_client from app.main import main from app.main.forms import ( RegisterUserForm, @@ -13,6 +20,7 @@ from app.main.forms import ( RegisterUserFromOrgInviteForm, SetupUserProfileForm, ) +from app.main.views import sign_in from app.main.views.verify import activate_user from app.models.user import InvitedOrgUser, InvitedUser, User from app.utils import hide_from_search_engines @@ -128,16 +136,12 @@ def registration_continue(): raise Exception("Unexpected routing in registration_continue") -@main.route("/set-up-your-profile", methods=["GET", "POST"]) +@main.route("/set-up-your-profile", methods=["GET", "POST"]) @hide_from_search_engines def set_up_your_profile(): - print("ENTER set_up_your_profile") - - form = SetupUserProfileForm() if form.validate_on_submit(): - print("VALIDATING FORM") # start login.gov code = request.args.get("code") @@ -148,8 +152,6 @@ def set_up_your_profile(): user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token) redirect_url = request.args.get("next") - - elif login_gov_error: current_app.logger.error(f"login.gov error: {login_gov_error}") raise Exception(f"Could not login with login.gov {login_gov_error}") diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 034db6ae7..6a805f62c 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -61,7 +61,6 @@ def _get_access_token(code, state): url = f"{base_url}{cli_assert}&{cli_assert_type}&{code_param}&grant_type=authorization_code" headers = {"Authorization": "Bearer %s" % token} response = requests.post(url, headers=headers) - print(f"RESPONSE FROM LOGIN DOT GOV {response.json()}") access_token = response.json()["access_token"] return access_token diff --git a/tests/app/main/views/test_register.py b/tests/app/main/views/test_register.py index e7bfc9327..d5fa744c6 100644 --- a/tests/app/main/views/test_register.py +++ b/tests/app/main/views/test_register.py @@ -30,6 +30,7 @@ def test_logged_in_user_redirects_to_account( ) +@pytest.mark.skip("Deprecated due to change to login-dot-gov-only registration") @pytest.mark.parametrize( "phone_number_to_register_with", [ @@ -75,14 +76,14 @@ def test_register_creates_new_user_and_redirects_to_continue_page( == "An email has been sent to notfound@example.gsa.gov." ) - mock_send_verify_email.assert_called_with(ANY, user_data["email_address"]) - mock_register_user.assert_called_with( - user_data["name"], - user_data["email_address"], - user_data["mobile_number"], - user_data["password"], - user_data["auth_type"], - ) + # mock_send_verify_email.assert_called_with(ANY, user_data["email_address"]) + # mock_register_user.assert_called_with( + # user_data["name"], + # user_data["email_address"], + # user_data["mobile_number"], + # user_data["password"], + # user_data["auth_type"], + # ) def test_register_continue_handles_missing_session_sensibly( diff --git a/tests/app/test_navigation.py b/tests/app/test_navigation.py index 5ee810f33..0732ab7e0 100644 --- a/tests/app/test_navigation.py +++ b/tests/app/test_navigation.py @@ -166,6 +166,7 @@ EXCLUDED_ENDPOINTS = tuple( "send_one_off", "send_one_off_step", "send_one_off_to_myself", + "set_up_your_profile", "service_add_email_reply_to", "service_add_sms_sender", "service_confirm_delete_email_reply_to", From c053cc7402b56d2df5af61c999753852b5898cab Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 19 Mar 2024 13:30:50 -0700 Subject: [PATCH 28/55] change timezone to hidden field with default for now --- app/main/forms.py | 2 ++ app/main/views/register.py | 10 ++-------- app/templates/views/set-up-your-profile.html | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index a2eeb1c63..13a463a51 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -610,6 +610,8 @@ class SetupUserProfileForm(StripWhitespaceForm): "Full name", validators=[DataRequired(message="Cannot be empty")] ) mobile_number = international_phone_number() + # TODO This should be replaced with a select widget when one is available. + preferred_timezone = HiddenField("preferred_timezone", default="US/Eastern") class RegisterUserFromInviteForm(RegisterUserForm): diff --git a/app/main/views/register.py b/app/main/views/register.py index 78f7ea2ae..8a0c884d3 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -141,8 +141,8 @@ def registration_continue(): def set_up_your_profile(): form = SetupUserProfileForm() - if form.validate_on_submit(): + if form.validate_on_submit(): # start login.gov code = request.args.get("code") state = request.args.get("state") @@ -157,13 +157,7 @@ def set_up_your_profile(): raise Exception(f"Could not login with login.gov {login_gov_error}") # end login.gov - user = User.register( - name=form.name.data, - email_address=user_email, - mobile_number=form.mobile_number.data, - password=str(uuid.uuid4()), - auth_type="sms_auth", - ) + # activate the user user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) activate_user(user["id"]) diff --git a/app/templates/views/set-up-your-profile.html b/app/templates/views/set-up-your-profile.html index b6e696c1e..8f37d3617 100644 --- a/app/templates/views/set-up-your-profile.html +++ b/app/templates/views/set-up-your-profile.html @@ -19,7 +19,7 @@ Set up your profile "hint": {"text": "We'll send you a security code by text message"}, }) }}
- {{ usaSelect({ + {{form.auth_type}} {{ page_footer("Save") }} {% endcall %} From b12e638592e824c5ccaf67a37b81961d8dd4c423 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 19 Mar 2024 14:34:41 -0700 Subject: [PATCH 29/55] fix registration --- app/main/views/register.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/main/views/register.py b/app/main/views/register.py index 8a0c884d3..a060fc0eb 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -157,6 +157,17 @@ def set_up_your_profile(): raise Exception(f"Could not login with login.gov {login_gov_error}") # end login.gov + # create the user + # TODO we have to provide something for password until that column goes away + # TODO ideally we would set the user's preferred timezone here as well + user = User.register( + name=form.name.data, + email_address=user_email, + mobile_number=form.mobile_number.data, + password=str(uuid.uuid4()), + auth_type="sms_auth", + ) + # activate the user user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) From 04eaec6dd69843165446b06c01468fcfc07d0e50 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 19 Mar 2024 14:36:43 -0700 Subject: [PATCH 30/55] fix register --- app/main/views/register.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/main/views/register.py b/app/main/views/register.py index a060fc0eb..7069270ea 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -168,7 +168,6 @@ def set_up_your_profile(): auth_type="sms_auth", ) - # activate the user user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) activate_user(user["id"]) From 24a0dd8c3bebfa48639a0343f6d712ac93e717e9 Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Thu, 21 Mar 2024 11:00:44 -0400 Subject: [PATCH 31/55] Few style updates per PR feedback --- .../sass/uswds/_uswds-theme-custom-styles.scss | 13 ++----------- app/templates/views/dashboard/_totals.html | 2 +- app/templates/views/dashboard/dashboard.html | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss index 1193e00be..7f2422064 100644 --- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss +++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss @@ -312,24 +312,15 @@ td.table-empty-message { .dashboard { .big-number-with-status { - // a { - // background: color("blue-60v"); - // padding: units(2); - // margin-bottom: units(1); - // text-decoration: none; - // &:hover{ - // background: color("blue-warm-70v"); - // } - // } .big-number-smaller { display: flex; flex-direction: column; .big-number-number { font-size: units(5); - line-height: units(6); + line-height: units(5); } .big-number-label { - font-size: units(3); + font-size: units(2.5); } } .big-number-status { diff --git a/app/templates/views/dashboard/_totals.html b/app/templates/views/dashboard/_totals.html index 87d6c22eb..9a297bf53 100644 --- a/app/templates/views/dashboard/_totals.html +++ b/app/templates/views/dashboard/_totals.html @@ -1,6 +1,6 @@
-
+

diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index 504747847..fc20af762 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -18,7 +18,7 @@ {{ ajax_block(partials, updates_url, 'upcoming') }} -

+

Messages sent

From 6efb16120d211dbd1119eb0ed1c4dbf7b83d1965 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Mar 2024 09:34:55 -0700 Subject: [PATCH 32/55] Add error handling for successful Login.gov authentications without a Notify account --- app/main/views/sign_in.py | 19 ++++++++++++++----- app/templates/error/401.html | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 5c5cf8a45..8f2b68dd5 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -20,6 +20,7 @@ from flask_login import current_user from app import login_manager, user_api_client from app.main import main from app.main.forms import LoginForm +from app.main.views.index import error from app.main.views.verify import activate_user from app.models.user import InvitedUser, User from app.utils import hide_from_search_engines @@ -77,9 +78,7 @@ def _get_user_email_and_uuid(access_token): return user_email, user_uuid -@main.route("/sign-in", methods=(["GET", "POST"])) -@hide_from_search_engines -def sign_in(): +def _do_login_dot_gov(): # start login.gov code = request.args.get("code") state = request.args.get("state") @@ -90,8 +89,13 @@ def sign_in(): redirect_url = request.args.get("next") # activate the user - user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) - activate_user(user["id"]) + try: + user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) + activate_user(user["id"]) + except BaseException as be: # noqa B036 + current_app.logger.error(be) + error(401) + return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url)) elif login_gov_error: @@ -99,6 +103,11 @@ def sign_in(): raise Exception(f"Could not login with login.gov {login_gov_error}") # end login.gov + +@main.route("/sign-in", methods=(["GET", "POST"])) +@hide_from_search_engines +def sign_in(): + _do_login_dot_gov() redirect_url = request.args.get("next") if os.getenv("NOTIFY_E2E_TEST_EMAIL"): diff --git a/app/templates/error/401.html b/app/templates/error/401.html index 068067e92..e048fecb9 100644 --- a/app/templates/error/401.html +++ b/app/templates/error/401.html @@ -4,6 +4,6 @@

You’re not authorized to see this page

-

Sign in to Notify.gov and try again.

+

If you have been invited to join Notify.gov, Sign in to Notify.gov using your Login.gov account and try again.

{% endblock %} From 099345fe1e0e0c3be169b9a915814535208d28ca Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Mar 2024 10:58:36 -0700 Subject: [PATCH 33/55] Add error handling for successful Login.gov authentications without a Notify account --- app/templates/error/401.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/templates/error/401.html b/app/templates/error/401.html index e048fecb9..01cad95e3 100644 --- a/app/templates/error/401.html +++ b/app/templates/error/401.html @@ -4,6 +4,7 @@

You’re not authorized to see this page

-

If you have been invited to join Notify.gov, Sign in to Notify.gov using your Login.gov account and try again.

+

If you have been invited to join Notify.gov, sign in to Notify.gov using your Login.gov account and try again.

{% endblock %} +e From 7c179cadca69d537ac5192e225c708bfe2338068 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Thu, 21 Mar 2024 21:03:32 -0700 Subject: [PATCH 34/55] header marco to html --- app/templates/new/base.html | 135 +--------------- app/templates/new/components/header.html | 195 +++++++++++++++++++++++ app/templates/new/templates_glossary.md | 12 +- 3 files changed, 204 insertions(+), 138 deletions(-) create mode 100644 app/templates/new/components/header.html diff --git a/app/templates/new/base.html b/app/templates/new/base.html index b175cff51..c55a3edff 100644 --- a/app/templates/new/base.html +++ b/app/templates/new/base.html @@ -67,142 +67,13 @@ }) }} {% endblock %} - + {% block header %} {% if current_user.is_authenticated %} - {% if current_user.platform_admin %} - {% 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.platform_admin_splash_page'), - "text": "Platform admin", - "active": header_navigation.is_selected('platform-admin') - }, - { - "href": url_for('main.support'), - "text": "Contact us", - "active": header_navigation.is_selected('support') - } - ] %} - {% if current_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 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') - }, - { - "href": url_for('main.user_profile'), - "text": "User profile", - "active": header_navigation.is_selected('user-profile') - } - ] %} - {% if current_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 %} - {% endif %} - {% else %} - - {# {% set navigation = [ - { - "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') - }, - { - "href": url_for('main.sign_in'), - "text": "Sign in", - "active": header_navigation.is_selected('sign-in') - } - ] %} #} + {% include "new/components/header.html" %} {% endif %} - - {{ usaHeader({ - "homepageUrl": url_for('main.show_accounts_or_dashboard'), - "productName": "Notify", - "navigation": navigation, - "navigationClasses": "govuk-header__navigation--end", - "secondaryNavigation": secondaryNavigation, - "assetsPath": asset_path + "images" - }) }} {% endblock %} - + {% block main %} diff --git a/app/templates/new/components/header.html b/app/templates/new/components/header.html new file mode 100644 index 000000000..1f559f447 --- /dev/null +++ b/app/templates/new/components/header.html @@ -0,0 +1,195 @@ + + +
+
+
+
+
+ +
+ + +
+
+ +
+
+{% if current_user.platform_admin %} + {% 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.platform_admin_splash_page'), + "text": "Platform admin", + "active": header_navigation.is_selected('platform-admin') + }, + { + "href": url_for('main.support'), + "text": "Contact us", + "active": header_navigation.is_selected('support') + } + ] %} + {% if current_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 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') + }, + { + "href": url_for('main.user_profile'), + "text": "User profile", + "active": header_navigation.is_selected('user-profile') + } + ] %} + {% if current_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 %} +{% endif %} + +
+
+
+ +
+ +
+
diff --git a/app/templates/new/templates_glossary.md b/app/templates/new/templates_glossary.md index 81325e26c..8ee501728 100644 --- a/app/templates/new/templates_glossary.md +++ b/app/templates/new/templates_glossary.md @@ -6,22 +6,22 @@ This document serves as a glossary for the templates directory structure of the ## Directory Structure - `/templates` - - `base.html`: The main base template from which all other templates inherit. This template is a combination of `main_template`, `admin_template`, `withoutnav_template` and `content_template`. - - **/layouts**: Contains base templates and shared layouts used across the site. Simply put, it defines the overall structure or skeleton of the application (less frequently revised). + - `base.html`: The main base template from which all other templates inherit. This template is a combination of `main_template`, `admin_template`, `withoutnav_template`, `settings_templates`, and `content_template`. + - **/layouts**: Contains shared layouts used across the site. Simply put, it defines the overall structure or skeleton of the application (less frequently revised). - `withnav_template.html`: A variation of the base layout that includes a sidebar. - `org_template.html`: A variaton of the withnav_template - - **/components**: Houses reusable UI components that can be included in multiple templates and can be tailored with different content or links depending on the context.(more frequently revised or customized) + - **/components**: Houses reusable UI components that can be included in multiple templates and can be tailored with different content or links depending on the context.(more frequently revised, used or customized) - `header.html`: Template for the site's header, included in `base.html`. - `footer.html`: Template for the site's footer, included in `base.html`. - **/views** (or **/pages**): Individual page templates that use the base layouts, components, and partials to present content. ### Best Practices -- Use **inheritance** (`{% extends %}`) to build on base layouts. -- Employ **components** (`{% include %}`) for reusable UI elements to keep the code DRY and facilitate easier updates. +- Use **inheritance** `{% extends %}` to build on base layouts. +- Employ **components** `{% include %}` for reusable UI elements to keep the code DRY and facilitate easier updates. ### Observation Notes -- The macro-options.json files in the header and footer component act as structural guides. They aren't directly used as data passed to the usaFooter function/macro. Instead, these files outline the expected properties and provide a description of their purpose. The `usaFooter` macro component is currently only invoked in the `admin_template`, which will eventually serve as the `base.html` template. This will simplify the approach when we change the footer macros to componenets by eliminating the need to dynamically pass this data from the base.html template. +- The macro-options.json files in the header and footer component act as structural guides. They aren't directly used as data passed to the usaFooter function/macro. Instead, these files outline the expected properties and provide a description of their purpose. The `usaFooter` macro component is currently only invoked in the `admin_template`, which will eventually serve as the `base.html` template. This will simplify the approach when we change the footer macros to componenets by eliminating the need to dynamically pass this data from the base.html template. This is also true for `usaHeader` macro component. From 8362c6b975cf989e3e43d4e257c55ca05861bc42 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 22 Mar 2024 11:08:49 -0700 Subject: [PATCH 35/55] fix invites for service and organization --- app/main/views/verify.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/main/views/verify.py b/app/main/views/verify.py index 0201edfcc..f6bb47ab7 100644 --- a/app/main/views/verify.py +++ b/app/main/views/verify.py @@ -5,6 +5,7 @@ from itsdangerous import SignatureExpired from notifications_utils.url_safe_token import check_token from app import user_api_client +from app.extensions import redis_client from app.main import main from app.main.forms import TwoFactorForm from app.models.user import InvitedOrgUser, InvitedUser, User @@ -64,20 +65,44 @@ def verify_email(token): def activate_user(user_id): user = User.from_id(user_id) - # the user will have a new current_session_id set by the API - store it in the cookie for future requests + + # This is the login.gov path + login_gov_invite_data = redis_client.get(f"service-invite-{user.email_address}") + if login_gov_invite_data: + login_gov_invite_data = json.loads(login_gov_invite_data.decode("utf8")) + + # This is the deprecated path for organization invites where we get id from session session["current_session_id"] = user.current_session_id organization_id = session.get("organization_id") + activated_user = user.activate() activated_user.login() + # TODO when login.gov is mandatory, get rid of the if clause, it is deprecated. invited_user = InvitedUser.from_session() if invited_user: service_id = _add_invited_user_to_service(invited_user) return redirect(url_for("main.service_dashboard", service_id=service_id)) + elif login_gov_invite_data: + service_id = login_gov_invite_data["service_id"] + user.add_to_service( + service_id, + login_gov_invite_data["permissions"], + login_gov_invite_data["folder_permissions"], + login_gov_invite_data["from_user_id"], + ) + return redirect(url_for("main.service_dashboard", service_id=service_id)) + + # TODO when login.gov is mandatory, git rid of the if clause, it is deprecated. invited_org_user = InvitedOrgUser.from_session() if invited_org_user: user_api_client.add_user_to_organization(invited_org_user.organization, user_id) + elif redis_client.get(f"organization-invite-{user.email_address}"): + organization_id = redis_client.get(f"organization-invite-{user.email_address}") + user_api_client.add_user_to_organization( + organization_id.decode("utf8"), user_id + ) if organization_id: return redirect(url_for("main.organization_dashboard", org_id=organization_id)) From 4428df7dd5bdfe90f1fe43c019a8fbf6fe562007 Mon Sep 17 00:00:00 2001 From: Mitchell Henke Date: Tue, 26 Mar 2024 15:06:26 +0000 Subject: [PATCH 36/55] Reformat nested list --- docs/login_dot_gov.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/login_dot_gov.md b/docs/login_dot_gov.md index 5f985faa4..29b65d989 100644 --- a/docs/login_dot_gov.md +++ b/docs/login_dot_gov.md @@ -4,11 +4,11 @@ How to integrate with the login.gov sandbox: https://dashboard.int.identitysand 1. Create a team and a user over in the login.gov sandbox. 2. Create a test app: - a. you will need to create a unique client id that looks like: urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:test_notify_gov - b. Select OpenIdConnect and private key JWT - c. select authentication only - d. select MFA required + remember device 30 days only (AAL1) - e. set redirect urls like: http://localhost:6012/sign-in + - you will need to create a unique client id that looks like: urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:test_notify_gov + - Select OpenIdConnect and private key JWT + - select authentication only + - select MFA required + remember device 30 days only (AAL1) + - set redirect urls like: http://localhost:6012/sign-in 3. generate a cert: openssl req -nodes -x509 -days 365 -newkey rsa:2048 -keyout private.pem -out public.crt 4. Upload the public.crt to your app in the sandbox 5. put the private.pem contents and public.crt contents in github secrets (?) From 89e7de0ab6cddf9a3e653ed134a015c5e40c2fda Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 26 Mar 2024 12:37:06 -0700 Subject: [PATCH 37/55] fixed the testing --- tests/app/main/views/test_jobs.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index 23eb8fc34..ec63858bc 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -424,11 +424,7 @@ def test_should_show_updates_for_one_job_as_json( assert "2021234567" in content["notifications"] assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] - assert ( - "Sent by Test User on January 01, 2016 at 12:00 AM US/Eastern" - in content["status"] - ) - assert "12:00" in content["notifications"] + assert "01-01-2016 at 12:00 AM" in content["notifications"] @freeze_time("2016-01-01 05:00:00.000001") @@ -469,10 +465,7 @@ def test_should_show_updates_for_scheduled_job_as_json( assert "2021234567" in content["notifications"] assert "Status" in content["notifications"] assert "Delivered" in content["notifications"] - assert ( - "Sent by Test User on June 01, 2016 at 04:00 PM US/Eastern" in content["status"] - ) - assert "12:00" in content["notifications"] + assert "01-01-2016 at 12:00 AM" in content["notifications"] @pytest.mark.parametrize( From 6c1090ecb277c10a79f05bae099dd7bdfd1c272e Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Tue, 26 Mar 2024 16:06:13 -0400 Subject: [PATCH 38/55] 1252 - add back blue boxes for pending and delivered --- app/templates/partials/count.html | 48 ++----------------------------- tests/app/main/views/test_jobs.py | 5 ++-- 2 files changed, 5 insertions(+), 48 deletions(-) diff --git a/app/templates/partials/count.html b/app/templates/partials/count.html index 17321d67f..188884cdf 100644 --- a/app/templates/partials/count.html +++ b/app/templates/partials/count.html @@ -1,49 +1,7 @@ {% from "components/pill.html" import pill %}
- {% if notifications_deleted %} -
- {% for label, query_param, url, count in counts %} - {% if query_param == 'pending' %} -
- - - {% if count is number %} - {% if currency %} - {{ "{}{:,.2f}".format(currency, count) }} - {% else %} - {{ "{:,}".format(count) }} - {% endif %} - {% else %} - {{ count }} - {% endif %} - - {{ query_param }} - -
- {% else %} -
- - - {% if count is number %} - {% if currency %} - {{ "{}{:,.2f}".format(currency, count) }} - {% else %} - {{ "{:,}".format(count) }} - {% endif %} - {% else %} - {{ count }} - {% endif %} - - {{ label }} - -
- {% endif %} - {% endfor %} -
- {% else %} -
- {{ pill(counts, request.args.get('status', '')) }} -
- {% endif %} +
+ {{ pill(counts, request.args.get('status', '')) }} +
diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py index 3076fe88f..cbee48ccc 100644 --- a/tests/app/main/views/test_jobs.py +++ b/tests/app/main/views/test_jobs.py @@ -320,15 +320,14 @@ def test_should_show_old_job( service_id=SERVICE_ONE_ID, job_id=fake_uuid, ) - assert not page.select(".pill") assert not page.select("p.hint") assert not page.select("a[download]") assert page.select_one("tbody").text.strip() == expected_message assert [ - normalize_spaces(column.text) for column in page.select("main .grid-col-3") + normalize_spaces(column.text) for column in page.select("main .pill .pill-item") ] == [ "1 total text messages", - "1 pending", + "1 pending text message", "0 delivered text messages", "0 failed text messages", ] From d8e9aaee0ff2167a51d19d887d42d018e10adfcb Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 26 Mar 2024 18:00:01 -0700 Subject: [PATCH 39/55] updated header nav and seperated out usabanner --- app/templates/new/base.html | 7 +- app/templates/new/components/header.html | 157 +++---------------- app/templates/new/components/usa_banner.html | 44 ++++++ 3 files changed, 66 insertions(+), 142 deletions(-) create mode 100644 app/templates/new/components/usa_banner.html diff --git a/app/templates/new/base.html b/app/templates/new/base.html index f7aa58f68..4d5279342 100644 --- a/app/templates/new/base.html +++ b/app/templates/new/base.html @@ -1,6 +1,5 @@ {% from "../components/banner.html" import banner %} {% from "../components/components/skip-link/macro.njk" import usaSkipLink -%} -{% from "../components/components/header/macro.njk" import usaHeader -%} {% from "../components/components/footer/macro.njk" import usaFooter -%} @@ -25,13 +24,13 @@ }) }} {% endblock %} - + {# region header #} {% block header %} {% if current_user.is_authenticated %} - {% include "new/components/header.html" %} + {% include 'new/components/usa_banner.html' %} + {% include 'new/components/header.html' %} {% endif %} {% endblock %} - {% block main %} diff --git a/app/templates/new/components/header.html b/app/templates/new/components/header.html index 1f559f447..e21963fed 100644 --- a/app/templates/new/components/header.html +++ b/app/templates/new/components/header.html @@ -1,145 +1,26 @@ +{# setting navigation and secondarynavigation #} +{% 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')} +] %} - -
-
-
-
-
- -
- - -
-
- -
-
{% if current_user.platform_admin %} - {% 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.platform_admin_splash_page'), - "text": "Platform admin", - "active": header_navigation.is_selected('platform-admin') - }, - { - "href": url_for('main.support'), - "text": "Contact us", - "active": header_navigation.is_selected('support') - } - ] %} - {% if current_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 %} + {% set navigation = navigation + [{"href": url_for('main.platform_admin_splash_page'), "text": "Platform admin", "active": header_navigation.is_selected('platform-admin')}] %} {% else %} - {% 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') - }, - { - "href": url_for('main.user_profile'), - "text": "User profile", - "active": header_navigation.is_selected('user-profile') - } - ] %} - {% if current_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 %} + {% set navigation = navigation + [{"href": url_for('main.user_profile'), "text": "User profile", "active": header_navigation.is_selected('user-profile')}] %} {% endif %} - + +{% if current_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 %} +{# usa header #}
diff --git a/app/templates/new/components/usa_banner.html b/app/templates/new/components/usa_banner.html new file mode 100644 index 000000000..532a2937a --- /dev/null +++ b/app/templates/new/components/usa_banner.html @@ -0,0 +1,44 @@ + +{# usa banner #} +
+
+
+
+
+ +
+ + +
+
+ +
+
From b29c2a3a623827355ad1533f1d30fd299f4c5da0 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 28 Mar 2024 11:15:10 -0700 Subject: [PATCH 40/55] debug staging --- app/main/views/verify.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/main/views/verify.py b/app/main/views/verify.py index f6bb47ab7..85c138ea9 100644 --- a/app/main/views/verify.py +++ b/app/main/views/verify.py @@ -9,6 +9,7 @@ from app.extensions import redis_client from app.main import main from app.main.forms import TwoFactorForm from app.models.user import InvitedOrgUser, InvitedUser, User +from app.utils import hilite from app.utils.login import redirect_to_sign_in @@ -67,9 +68,10 @@ def activate_user(user_id): user = User.from_id(user_id) # This is the login.gov path - login_gov_invite_data = redis_client.get(f"service-invite-{user.email_address}") + login_gov_invite_data = redis_client.raw_get(f"service-invite-{user.email_address}") if login_gov_invite_data: login_gov_invite_data = json.loads(login_gov_invite_data.decode("utf8")) + current_app.logger.info(hilite(f"LOGIN_GOV_INVITE_DATA {login_gov_invite_data}")) # This is the deprecated path for organization invites where we get id from session session["current_session_id"] = user.current_session_id @@ -85,6 +87,7 @@ def activate_user(user_id): return redirect(url_for("main.service_dashboard", service_id=service_id)) elif login_gov_invite_data: service_id = login_gov_invite_data["service_id"] + current_app.logger.info(hilite(f"SERVICE_ID={service_id}")) user.add_to_service( service_id, @@ -98,8 +101,11 @@ def activate_user(user_id): invited_org_user = InvitedOrgUser.from_session() if invited_org_user: user_api_client.add_user_to_organization(invited_org_user.organization, user_id) - elif redis_client.get(f"organization-invite-{user.email_address}"): - organization_id = redis_client.get(f"organization-invite-{user.email_address}") + elif redis_client.raw_get(f"organization-invite-{user.email_address}"): + organization_id = redis_client.raw_get( + f"organization-invite-{user.email_address}" + ) + current_app.logger.info(hilite(f"ORGANIZATION_ID FROM REDIS {organization_id}")) user_api_client.add_user_to_organization( organization_id.decode("utf8"), user_id ) From 9b1c9b8ccf0b30655a1ede7fb15fd2cf0e7b9830 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 28 Mar 2024 11:35:25 -0700 Subject: [PATCH 41/55] ugh --- app/main/views/verify.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/main/views/verify.py b/app/main/views/verify.py index 85c138ea9..1250db150 100644 --- a/app/main/views/verify.py +++ b/app/main/views/verify.py @@ -68,7 +68,7 @@ def activate_user(user_id): user = User.from_id(user_id) # This is the login.gov path - login_gov_invite_data = redis_client.raw_get(f"service-invite-{user.email_address}") + login_gov_invite_data = redis_client.get(f"service-invite-{user.email_address}") if login_gov_invite_data: login_gov_invite_data = json.loads(login_gov_invite_data.decode("utf8")) current_app.logger.info(hilite(f"LOGIN_GOV_INVITE_DATA {login_gov_invite_data}")) @@ -101,7 +101,7 @@ def activate_user(user_id): invited_org_user = InvitedOrgUser.from_session() if invited_org_user: user_api_client.add_user_to_organization(invited_org_user.organization, user_id) - elif redis_client.raw_get(f"organization-invite-{user.email_address}"): + elif redis_client.get(f"organization-invite-{user.email_address}"): organization_id = redis_client.raw_get( f"organization-invite-{user.email_address}" ) From 2c57d0d373ae56c5aace1eb446402ae70be1a2ff Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Thu, 28 Mar 2024 15:58:02 -0400 Subject: [PATCH 42/55] 1213 - Removed the Usage page and updated the Dashboard Landing page --- app/templates/main_nav.html | 2 +- app/templates/views/dashboard/_usage.html | 2 +- app/templates/views/dashboard/dashboard.html | 34 ++++--------------- app/templates/views/usage.html | 14 ++------ tests/app/main/test_permissions.py | 1 - .../views/accounts/test_choose_accounts.py | 2 +- tests/app/main/views/test_activity.py | 2 +- tests/app/main/views/test_dashboard.py | 22 ++---------- tests/app/test_navigation.py | 2 +- 9 files changed, 18 insertions(+), 63 deletions(-) diff --git a/app/templates/main_nav.html b/app/templates/main_nav.html index 2f7306f09..4aac354d9 100644 --- a/app/templates/main_nav.html +++ b/app/templates/main_nav.html @@ -14,7 +14,7 @@
  • Sent messages
  • {% endif %} {% if current_user.has_permissions('manage_service', allow_org_user=True) %} -
  • Usage
  • + {#
  • Usage
  • #} {% endif %}