Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: error pages #1536

Merged
merged 11 commits into from
Jul 18, 2023
23 changes: 19 additions & 4 deletions benefits/core/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@
from django.http import HttpResponse
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.decorators import decorator_from_middleware
from django.utils.deprecation import MiddlewareMixin
from django.views import i18n

from . import analytics, recaptcha, session, viewmodels
from . import analytics, recaptcha, session


logger = logging.getLogger(__name__)

HEALTHCHECK_PATH = "/healthcheck"
ROUTE_INDEX = "core:index"
TEMPLATE_USER_ERROR = "200-user-error.html"


def user_error(request):
page = viewmodels.ErrorPage.user_error()

return TemplateResponse(request, TEMPLATE_USER_ERROR, page.context_dict())
return TemplateResponse(request, TEMPLATE_USER_ERROR)


class AgencySessionRequired(MiddlewareMixin):
Expand Down Expand Up @@ -144,3 +145,17 @@ def process_request(self, request):
"site_key": settings.RECAPTCHA_SITE_KEY,
}
return None


class IndexOrAgencyIndexOrigin(MiddlewareMixin):
"""Middleware sets the session.origin to either the core:index or core:agency_index depending on agency config."""

def process_request(self, request):
if session.active_agency(request):
session.update(request, origin=session.agency(request).index_url)
else:
session.update(request, origin=reverse(ROUTE_INDEX))
return None
angela-tran marked this conversation as resolved.
Show resolved Hide resolved


index_or_agencyindex_origin_decorator = decorator_from_middleware(IndexOrAgencyIndexOrigin)
4 changes: 2 additions & 2 deletions benefits/core/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ def oauth_claim(request):


def origin(request):
"""Get the origin for the request's session, or None."""
"""Get the origin for the request's session, or the default core:index."""
logger.debug("Get session origin")
return request.session.get(_ORIGIN)
return request.session.get(_ORIGIN, reverse("core:index"))


def reset(request):
Expand Down
57 changes: 1 addition & 56 deletions benefits/core/viewmodels.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
The core application: view model definitions for the root of the webapp.
"""
from django.utils.translation import pgettext, gettext_lazy as _
from django.utils.translation import gettext_lazy as _

from benefits.core import models

Expand Down Expand Up @@ -130,61 +130,6 @@ def context_dict(self):
return {"page": self}


class ErrorPage(Page):
"""
Represents an error page:
* title: str
* icon: core.viewmodels.Icon
* headline: str
* paragraphs: str[]
* button: core.viewmodels.Button
"""

def __init__(self, **kwargs):
super().__init__(
title=kwargs.get("title", _("core.pages.error.title")),
icon=kwargs.get("icon", Icon("sadbus", pgettext("image alt text", "core.icons.sadbus"))),
headline=kwargs.get("headline", _("core.pages.error.title")),
paragraphs=kwargs.get("paragraphs", [_("core.pages.server_error.headline")]),
button=kwargs.get("button"),
)

@staticmethod
def user_error(
title=_("core.pages.user_error.title"),
headline=_("core.pages.user_error.headline"),
paragraphs=[_("core.pages.user_error.p[0]")],
**kwargs,
):
"""Create a new core.viewmodels.ErrorPage instance with defaults for a user error."""
return ErrorPage(title=title, headline=headline, paragraphs=paragraphs, **kwargs)

@staticmethod
def server_error(
title=_("core.pages.server_error.title"),
headline=_("core.pages.server_error.title"),
paragraphs=[_("core.pages.server_error.p[0]")],
**kwargs,
):
"""Create a new core.viewmodels.ErrorPage instance with defaults for a generic server error."""
return ErrorPage(title=title, headline=headline, paragraphs=paragraphs, **kwargs)

@staticmethod
def not_found(
title=_("core.pages.not_found.title"),
headline=_("core.pages.not_found.headline"),
paragraphs=[_("core.pages.not_found.p[0]")],
**kwargs,
):
"""Create a new core.viewmodels.ErrorPage with defaults for a 404."""
path = kwargs.pop("path", None)
if path and title:
title = f"{title}: {path}"
elif path and not title:
title = path
return ErrorPage(title=title, headline=headline, paragraphs=paragraphs, **kwargs)


class TransitAgency:
"""
Represents a core.models.TransitAgency:
Expand Down
52 changes: 17 additions & 35 deletions benefits/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
from django.utils.translation import pgettext, gettext as _

from . import models, session, viewmodels
from .middleware import pageview_decorator
from .middleware import pageview_decorator, index_or_agencyindex_origin_decorator

ROUTE_INDEX = "core:index"
ROUTE_ELIGIBILITY = "eligibility:index"
ROUTE_HELP = "core:help"
ROUTE_LOGGED_OUT = "core:logged_out"
Expand All @@ -20,6 +19,10 @@
TEMPLATE_HELP = "core/help.html"
TEMPLATE_LOGGED_OUT = "core/logged-out.html"

TEMPLATE_BAD_REQUEST = "400.html"
TEMPLATE_NOT_FOUND = "404.html"
TEMPLATE_SERVER_ERROR = "500.html"


@pageview_decorator
def index(request):
Expand Down Expand Up @@ -74,62 +77,41 @@ def help(request):


@pageview_decorator
def bad_request(request, exception, template_name="400.html"):
@index_or_agencyindex_origin_decorator
def bad_request(request, exception, template_name=TEMPLATE_BAD_REQUEST):
"""View handler for HTTP 400 Bad Request responses."""
if session.active_agency(request):
session.update(request, origin=session.agency(request).index_url)
else:
session.update(request, origin=reverse(ROUTE_INDEX))

page = viewmodels.ErrorPage.server_error()
t = loader.get_template(template_name)

return HttpResponseBadRequest(t.render(page.context_dict()))
return HttpResponseBadRequest(t.render(request=request))


@pageview_decorator
@index_or_agencyindex_origin_decorator
def csrf_failure(request, reason):
"""
View handler for CSRF_FAILURE_VIEW with custom data.
"""
if session.active_agency(request):
session.update(request, origin=session.agency(request).index_url)
else:
session.update(request, origin=reverse(ROUTE_INDEX))

page = viewmodels.ErrorPage.not_found(path=request.path)
t = loader.get_template("400.html")
t = loader.get_template(TEMPLATE_BAD_REQUEST)

return HttpResponseNotFound(t.render(page.context_dict()))
return HttpResponseNotFound(t.render(request=request))


@pageview_decorator
def page_not_found(request, exception, template_name="404.html"):
@index_or_agencyindex_origin_decorator
def page_not_found(request, exception, template_name=TEMPLATE_NOT_FOUND):
"""View handler for HTTP 404 Not Found responses."""
if session.active_agency(request):
session.update(request, origin=session.agency(request).index_url)
else:
session.update(request, origin=reverse(ROUTE_INDEX))

# show a more user-friendly message instead of not_found
page = viewmodels.ErrorPage.user_error(path=request.path)
angela-tran marked this conversation as resolved.
Show resolved Hide resolved
t = loader.get_template(template_name)

return HttpResponseNotFound(t.render(page.context_dict()))
return HttpResponseNotFound(t.render(request=request))


@pageview_decorator
def server_error(request, template_name="500.html"):
@index_or_agencyindex_origin_decorator
def server_error(request, template_name=TEMPLATE_SERVER_ERROR):
"""View handler for HTTP 500 Server Error responses."""
if session.active_agency(request):
session.update(request, origin=session.agency(request).index_url)
else:
session.update(request, origin=reverse(ROUTE_INDEX))

page = viewmodels.ErrorPage.server_error()
t = loader.get_template(template_name)

return HttpResponseServerError(t.render(page.context_dict()))
return HttpResponseServerError(t.render(request=request))


def logged_out(request):
Expand Down
3 changes: 1 addition & 2 deletions benefits/eligibility/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ def index(request, agency=None):
# see if session has an agency
agency = session.agency(request)
if agency is None:
page = viewmodels.ErrorPage.user_error(path=request.path)
return TemplateResponse(request, "200-user-error.html", page.context_dict())
return TemplateResponse(request, "200-user-error.html")
else:
session.update(request, eligibility_types=[], origin=agency.index_url)
else:
Expand Down
75 changes: 34 additions & 41 deletions benefits/locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://github.com/cal-itp/benefits/issues \n"
"POT-Creation-Date: 2023-07-14 21:06+0000\n"
"POT-Creation-Date: 2023-07-16 22:50+0000\n"
"Language: English\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -267,46 +267,6 @@ msgstr "Thank you for using Cal-ITP Benefits!"
msgid "eligibility.pages.index.label"
msgstr "Which transit benefit would you like to enroll in?"

msgid "core.pages.error.title"
msgstr "Error"

msgctxt "image alt text"
msgid "core.icons.sadbus"
msgstr "Bus icon with flat tire"

msgid "core.pages.server_error.headline"
msgstr "Sorry! Service for this site is down."

msgid "core.pages.user_error.title"
msgstr "Invalid state"

msgid "core.pages.user_error.headline"
msgstr "You may have reached this page on accident."

msgid "core.pages.user_error.p[0]"
msgstr ""
"To get started with Cal-ITP Benefits please click the button below, and you "
"will be directed to the beginning of the enrollment process. "

msgid "core.pages.server_error.title"
msgstr "Sorry! Service for this site is down."

msgid "core.pages.server_error.p[0]"
msgstr ""
"We should be back in operation soon. Please refresh the page in a few "
"minutes."

msgid "core.pages.not_found.title"
msgstr "Page not found"

msgid "core.pages.not_found.headline"
msgstr "Sorry! We can’t find that page."

msgid "core.pages.not_found.p[0]"
msgstr ""
"The page you are looking for might be somewhere else or may not exist "
"anymore."

msgid "core.pages.index.title"
msgstr "Choose Provider"

Expand Down Expand Up @@ -645,3 +605,36 @@ msgstr ""

msgid "core.buttons.retry"
msgstr "Try again"

msgid "core.pages.user_error.title"
msgstr "Invalid state"

msgid "core.pages.user_error.headline"
msgstr "You may have reached this page on accident."

msgid "core.pages.user_error.p[0]"
msgstr ""
"To get started with Cal-ITP Benefits please click the button below, and you "
"will be directed to the beginning of the enrollment process. "

msgid "core.pages.server_error.title"
msgstr "Sorry! Service for this site is down."

msgid "core.pages.server_error.p[0]"
msgstr ""
"We should be back in operation soon. Please refresh the page in a few "
"minutes."

msgid "core.pages.not_found.title"
msgstr "Page not found"

msgid "core.pages.not_found.headline"
msgstr "Sorry! We can’t find that page."

msgid "core.pages.not_found.p[0]"
msgstr ""
"The page you are looking for might be somewhere else or may not exist "
"anymore."

msgid "core.icons.sadbus"
msgstr "Bus icon with flat tire"