From 9e12645b8c77af4ea99ce6671259c81ecd1b5296 Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Tue, 30 Apr 2024 22:11:54 +0000 Subject: [PATCH 1/8] refactor: show system enrollment error page if 500 during linking --- .../templates/enrollment/system_error.html | 0 benefits/enrollment/views.py | 10 +++++++ tests/pytest/enrollment/test_views.py | 29 +++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 benefits/enrollment/templates/enrollment/system_error.html diff --git a/benefits/enrollment/templates/enrollment/system_error.html b/benefits/enrollment/templates/enrollment/system_error.html new file mode 100644 index 000000000..e69de29bb diff --git a/benefits/enrollment/views.py b/benefits/enrollment/views.py index dab1e56ee..aa55298d9 100644 --- a/benefits/enrollment/views.py +++ b/benefits/enrollment/views.py @@ -24,6 +24,7 @@ ROUTE_TOKEN = "enrollment:token" TEMPLATE_RETRY = "enrollment/retry.html" +TEMPLATE_SYSTEM_ERROR = "enrollment/system_error.html" logger = logging.getLogger(__name__) @@ -87,6 +88,9 @@ def index(request): if e.response.status_code == 409: analytics.returned_success(request, eligibility.group_id) return success(request) + elif e.response.status_code >= 500: + analytics.returned_error(request, str(e)) + return system_error(request) else: analytics.returned_error(request, str(e)) raise Exception(f"{e}: {e.response.json()}") @@ -144,6 +148,12 @@ def retry(request): return TemplateResponse(request, TEMPLATE_RETRY) +@decorator_from_middleware(EligibleSessionRequired) +def system_error(request): + """View handler for an enrollment system error.""" + return TemplateResponse(request, TEMPLATE_SYSTEM_ERROR) + + @pageview_decorator @decorator_from_middleware(VerifierSessionRequired) def success(request): diff --git a/tests/pytest/enrollment/test_views.py b/tests/pytest/enrollment/test_views.py index 056373c44..8df0bd4e2 100644 --- a/tests/pytest/enrollment/test_views.py +++ b/tests/pytest/enrollment/test_views.py @@ -14,6 +14,7 @@ ROUTE_RETRY, ROUTE_SUCCESS, ROUTE_TOKEN, + TEMPLATE_SYSTEM_ERROR, TEMPLATE_RETRY, ) @@ -124,12 +125,36 @@ def test_index_eligible_post_invalid_form(client, invalid_form_data): @pytest.mark.django_db +@pytest.mark.parametrize("status_code", [500, 501, 502, 503, 504]) @pytest.mark.usefixtures("mocked_session_agency", "mocked_session_eligibility") -def test_index_eligible_post_valid_form_http_error(mocker, client, card_tokenize_form_data): +def test_index_eligible_post_valid_form_http_error_500( + mocker, client, mocked_analytics_module, card_tokenize_form_data, status_code +): + mock_client_cls = mocker.patch("benefits.enrollment.views.Client") + mock_client = mock_client_cls.return_value + + mock_error = {"message": "Mock error message"} + mock_error_response = mocker.Mock(status_code=status_code, **mock_error) + mock_error_response.json.return_value = mock_error + mock_client.link_concession_group_funding_source.side_effect = HTTPError( + response=mock_error_response, + ) + + path = reverse(ROUTE_INDEX) + response = client.post(path, card_tokenize_form_data) + + assert response.status_code == 200 + assert response.template_name == TEMPLATE_SYSTEM_ERROR + mocked_analytics_module.returned_error.assert_called_once() + + +@pytest.mark.django_db +@pytest.mark.usefixtures("mocked_session_agency", "mocked_session_eligibility") +def test_index_eligible_post_valid_form_http_error_400(mocker, client, card_tokenize_form_data): mock_client_cls = mocker.patch("benefits.enrollment.views.Client") mock_client = mock_client_cls.return_value - # any status_code that isn't 409 is considered an error + # any 400 level status_code that isn't 409 is considered an error mock_error = {"message": "Mock error message"} mock_error_response = mocker.Mock(status_code=400, **mock_error) mock_error_response.json.return_value = mock_error From 9605c5d07a1929754664a0442ddbc0e5cf7a31a7 Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Mon, 13 May 2024 17:47:41 +0000 Subject: [PATCH 2/8] chore: remove style class that no longer exists --- benefits/templates/error.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benefits/templates/error.html b/benefits/templates/error.html index 4ec55f37b..677c9dda1 100644 --- a/benefits/templates/error.html +++ b/benefits/templates/error.html @@ -8,7 +8,7 @@ {% block main-content %}
-

+

{% include "core/includes/icon.html" with name="sadbus" %} {% block headline %} {% endblock headline %} From 8dee229fcf789d0e340f891ec8e46a504ecc9548 Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Mon, 13 May 2024 21:31:07 +0000 Subject: [PATCH 3/8] feat: implement system enrollment error page template follows implementation of retry page template. CTA goes to agency index. --- .../templates/enrollment/system_error.html | 43 +++++++++++++++++++ benefits/enrollment/views.py | 3 ++ benefits/static/css/styles.css | 5 ++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/benefits/enrollment/templates/enrollment/system_error.html b/benefits/enrollment/templates/enrollment/system_error.html index e69de29bb..3ca701390 100644 --- a/benefits/enrollment/templates/enrollment/system_error.html +++ b/benefits/enrollment/templates/enrollment/system_error.html @@ -0,0 +1,43 @@ +{% extends "core/base.html" %} +{% load i18n %} + +{% block classes %} + {{ block.super | add:" system-enrollment-error" }} +{% endblock classes %} + +{% block page-title %} + {% translate "System enrollment error" %} +{% endblock page-title %} + +{% block main-content %} +
+

+ {% include "core/includes/icon.html" with name="bankcardquestion" %} + {% translate "Our enrollment system is not working right now." %} +

+ +
+
+

{% translate "We’re working to solve the problem. Please wait 48 hours and try to enroll again, or contact your transit agency for help." %}

+
+
+ +
+
{% include "core/includes/agency-links.html" %}
+
+ +
+
+ {% if authentication and authentication.sign_out_link_template %} + {% url "oauth:logout" as sign_out_url %} + {% translate "Sign out of" as button_text %} + + {% else %} + {% include "core/includes/button--origin.html" %} + {% endif %} +
+
+
+{% endblock main-content %} diff --git a/benefits/enrollment/views.py b/benefits/enrollment/views.py index aa55298d9..73592c0b7 100644 --- a/benefits/enrollment/views.py +++ b/benefits/enrollment/views.py @@ -90,6 +90,9 @@ def index(request): return success(request) elif e.response.status_code >= 500: analytics.returned_error(request, str(e)) + + # overwrite origin so that CTA takes user to agency index + session.update(request, origin=agency.index_url) return system_error(request) else: analytics.returned_error(request, str(e)) diff --git a/benefits/static/css/styles.css b/benefits/static/css/styles.css index 6927754d9..91b71c0b3 100644 --- a/benefits/static/css/styles.css +++ b/benefits/static/css/styles.css @@ -470,9 +470,10 @@ footer .footer-links li a.footer-link:visited { } } -/* Sign in with Login.gov (white logo) on Eligibility Start */ +/* Sign in with Login.gov (white logo) on Eligibility Start, System Enrollment Error */ -.eligibility-start .btn.btn-lg.btn-primary.login { +.eligibility-start .btn.btn-lg.btn-primary.login, +.system-enrollment-error .btn.btn-lg.btn-primary.login { padding: 10px 0; } From d8c2e700cc478d8a4a0a237005e77d1a307f04fd Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Mon, 13 May 2024 21:47:55 +0000 Subject: [PATCH 4/8] feat(sentry): ensure 500 error during link still sends Sentry event --- benefits/enrollment/views.py | 2 ++ tests/pytest/enrollment/test_views.py | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/benefits/enrollment/views.py b/benefits/enrollment/views.py index 73592c0b7..7d35f18ea 100644 --- a/benefits/enrollment/views.py +++ b/benefits/enrollment/views.py @@ -10,6 +10,7 @@ from django.utils.decorators import decorator_from_middleware from littlepay.api.client import Client from requests.exceptions import HTTPError +import sentry_sdk from benefits.core import session from benefits.core.middleware import EligibleSessionRequired, VerifierSessionRequired, pageview_decorator @@ -90,6 +91,7 @@ def index(request): return success(request) elif e.response.status_code >= 500: analytics.returned_error(request, str(e)) + sentry_sdk.capture_exception(e) # overwrite origin so that CTA takes user to agency index session.update(request, origin=agency.index_url) diff --git a/tests/pytest/enrollment/test_views.py b/tests/pytest/enrollment/test_views.py index 8df0bd4e2..41066589f 100644 --- a/tests/pytest/enrollment/test_views.py +++ b/tests/pytest/enrollment/test_views.py @@ -34,6 +34,11 @@ def mocked_analytics_module(mocked_analytics_module): return mocked_analytics_module(benefits.enrollment.views) +@pytest.fixture +def mocked_sentry_sdk_module(mocker): + return mocker.patch.object(benefits.enrollment.views, "sentry_sdk") + + @pytest.fixture def mocked_funding_source(): return FundingSourceResponse( @@ -128,7 +133,7 @@ def test_index_eligible_post_invalid_form(client, invalid_form_data): @pytest.mark.parametrize("status_code", [500, 501, 502, 503, 504]) @pytest.mark.usefixtures("mocked_session_agency", "mocked_session_eligibility") def test_index_eligible_post_valid_form_http_error_500( - mocker, client, mocked_analytics_module, card_tokenize_form_data, status_code + mocker, client, mocked_analytics_module, mocked_sentry_sdk_module, card_tokenize_form_data, status_code ): mock_client_cls = mocker.patch("benefits.enrollment.views.Client") mock_client = mock_client_cls.return_value @@ -146,6 +151,7 @@ def test_index_eligible_post_valid_form_http_error_500( assert response.status_code == 200 assert response.template_name == TEMPLATE_SYSTEM_ERROR mocked_analytics_module.returned_error.assert_called_once() + mocked_sentry_sdk_module.capture_exception.assert_called_once() @pytest.mark.django_db From 852416ba63cd259c64db4d3660c110453d179e9a Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Tue, 14 May 2024 16:00:26 +0000 Subject: [PATCH 5/8] chore: run makemessages helper script --- benefits/locale/en/LC_MESSAGES/django.po | 14 ++++++++++++++ benefits/locale/es/LC_MESSAGES/django.po | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/benefits/locale/en/LC_MESSAGES/django.po b/benefits/locale/en/LC_MESSAGES/django.po index 381a429cd..cb8caceeb 100644 --- a/benefits/locale/en/LC_MESSAGES/django.po +++ b/benefits/locale/en/LC_MESSAGES/django.po @@ -706,6 +706,20 @@ msgstr "" msgid "If you are on a public or shared computer, don’t forget to sign out of " msgstr "" +msgid "System enrollment error" +msgstr "" + +msgid "Our enrollment system is not working right now." +msgstr "" + +msgid "" +"We’re working to solve the problem. Please wait 48 hours and try to enroll " +"again, or contact your transit agency for help." +msgstr "" + +msgid "Sign out of" +msgstr "" + msgid "Start over" msgstr "" diff --git a/benefits/locale/es/LC_MESSAGES/django.po b/benefits/locale/es/LC_MESSAGES/django.po index 191a90987..9ac16f18a 100644 --- a/benefits/locale/es/LC_MESSAGES/django.po +++ b/benefits/locale/es/LC_MESSAGES/django.po @@ -897,6 +897,20 @@ msgid "If you are on a public or shared computer, don’t forget to sign out of msgstr "" "Si está en una computadora pública o compartida, no olvide cerrar sesión en " +msgid "System enrollment error" +msgstr "" + +msgid "Our enrollment system is not working right now." +msgstr "" + +msgid "" +"We’re working to solve the problem. Please wait 48 hours and try to enroll " +"again, or contact your transit agency for help." +msgstr "" + +msgid "Sign out of" +msgstr "" + msgid "Start over" msgstr "Comenzar de nuevo" From 1138b278641de4ee55e37d65f46c2b17435e5bfc Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Tue, 14 May 2024 18:51:10 +0000 Subject: [PATCH 6/8] test: add coverage for session origin getting updated --- tests/pytest/enrollment/test_views.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/pytest/enrollment/test_views.py b/tests/pytest/enrollment/test_views.py index 41066589f..49e25c708 100644 --- a/tests/pytest/enrollment/test_views.py +++ b/tests/pytest/enrollment/test_views.py @@ -131,10 +131,19 @@ def test_index_eligible_post_invalid_form(client, invalid_form_data): @pytest.mark.django_db @pytest.mark.parametrize("status_code", [500, 501, 502, 503, 504]) -@pytest.mark.usefixtures("mocked_session_agency", "mocked_session_eligibility") +@pytest.mark.usefixtures("mocked_session_eligibility") def test_index_eligible_post_valid_form_http_error_500( - mocker, client, mocked_analytics_module, mocked_sentry_sdk_module, card_tokenize_form_data, status_code + mocker, + client, + mocked_session_agency, + mocked_analytics_module, + mocked_sentry_sdk_module, + card_tokenize_form_data, + status_code, ): + mock_session = mocker.patch("benefits.enrollment.views.session") + mock_session.agency.return_value = mocked_session_agency.return_value + mock_client_cls = mocker.patch("benefits.enrollment.views.Client") mock_client = mock_client_cls.return_value @@ -150,6 +159,7 @@ def test_index_eligible_post_valid_form_http_error_500( assert response.status_code == 200 assert response.template_name == TEMPLATE_SYSTEM_ERROR + assert {"origin": mocked_session_agency.return_value.index_url} in mock_session.update.call_args mocked_analytics_module.returned_error.assert_called_once() mocked_sentry_sdk_module.capture_exception.assert_called_once() From deb9f68272493f1893641125a2e87e4536978be8 Mon Sep 17 00:00:00 2001 From: Angela Tran Date: Tue, 14 May 2024 18:53:47 +0000 Subject: [PATCH 7/8] refactor: move session update into system_error view function we always want the agency index URL to be the origin when returning this template. --- benefits/enrollment/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/benefits/enrollment/views.py b/benefits/enrollment/views.py index 7d35f18ea..ee81973ab 100644 --- a/benefits/enrollment/views.py +++ b/benefits/enrollment/views.py @@ -93,8 +93,6 @@ def index(request): analytics.returned_error(request, str(e)) sentry_sdk.capture_exception(e) - # overwrite origin so that CTA takes user to agency index - session.update(request, origin=agency.index_url) return system_error(request) else: analytics.returned_error(request, str(e)) @@ -156,6 +154,11 @@ def retry(request): @decorator_from_middleware(EligibleSessionRequired) def system_error(request): """View handler for an enrollment system error.""" + + # overwrite origin so that CTA takes user to agency index + agency = session.agency(request) + session.update(request, origin=agency.index_url) + return TemplateResponse(request, TEMPLATE_SYSTEM_ERROR) From 95ec1066f193891a09e27f8e1d2b11090e9aa1fc Mon Sep 17 00:00:00 2001 From: Kegan Maher Date: Mon, 20 May 2024 21:50:00 +0000 Subject: [PATCH 8/8] chore(copy): update page title, translations for system enrollment error --- .../templates/enrollment/system_error.html | 10 ++++++---- benefits/locale/en/LC_MESSAGES/django.po | 4 ++-- benefits/locale/es/LC_MESSAGES/django.po | 13 ++++++++----- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/benefits/enrollment/templates/enrollment/system_error.html b/benefits/enrollment/templates/enrollment/system_error.html index 3ca701390..3324701cd 100644 --- a/benefits/enrollment/templates/enrollment/system_error.html +++ b/benefits/enrollment/templates/enrollment/system_error.html @@ -6,7 +6,7 @@ {% endblock classes %} {% block page-title %} - {% translate "System enrollment error" %} + {% translate "Enrollment system down" %} {% endblock page-title %} {% block main-content %} @@ -18,12 +18,14 @@

-

{% translate "We’re working to solve the problem. Please wait 48 hours and try to enroll again, or contact your transit agency for help." %}

+

+ {% translate "We’re working to solve the problem. Please wait 48 hours and try to enroll again, or contact your transit agency for help." %} +

-
{% include "core/includes/agency-links.html" %}
+
{% include "core/includes/agency-links.html" %}
@@ -32,7 +34,7 @@

{% url "oauth:logout" as sign_out_url %} {% translate "Sign out of" as button_text %} {% else %} {% include "core/includes/button--origin.html" %} diff --git a/benefits/locale/en/LC_MESSAGES/django.po b/benefits/locale/en/LC_MESSAGES/django.po index cb8caceeb..9bcdc3a4e 100644 --- a/benefits/locale/en/LC_MESSAGES/django.po +++ b/benefits/locale/en/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: https://github.com/cal-itp/benefits/issues \n" -"POT-Creation-Date: 2024-05-16 19:45+0000\n" +"POT-Creation-Date: 2024-05-20 21:48+0000\n" "Language: English\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -706,7 +706,7 @@ msgstr "" msgid "If you are on a public or shared computer, don’t forget to sign out of " msgstr "" -msgid "System enrollment error" +msgid "Enrollment system down" msgstr "" msgid "Our enrollment system is not working right now." diff --git a/benefits/locale/es/LC_MESSAGES/django.po b/benefits/locale/es/LC_MESSAGES/django.po index 9ac16f18a..527cde109 100644 --- a/benefits/locale/es/LC_MESSAGES/django.po +++ b/benefits/locale/es/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: https://github.com/cal-itp/benefits/issues \n" -"POT-Creation-Date: 2024-05-16 19:45+0000\n" +"POT-Creation-Date: 2024-05-20 21:48+0000\n" "Language: Español\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -897,19 +897,22 @@ msgid "If you are on a public or shared computer, don’t forget to sign out of msgstr "" "Si está en una computadora pública o compartida, no olvide cerrar sesión en " -msgid "System enrollment error" -msgstr "" +msgid "Enrollment system down" +msgstr "El sistema de inscripción no funciona" msgid "Our enrollment system is not working right now." -msgstr "" +msgstr "Nuestro sistema de inscripción no está funcionando en este momento." msgid "" "We’re working to solve the problem. Please wait 48 hours and try to enroll " "again, or contact your transit agency for help." msgstr "" +"Estamos trabajando para resolver el problema. Espere 48 horas e intente " +"inscribirse nuevamente, o contacte a su agencia de tránsito para obtener " +"ayuda." msgid "Sign out of" -msgstr "" +msgstr "Cierre sesión de" msgid "Start over" msgstr "Comenzar de nuevo"