From c3bec521c78a66ce828eae79592cc79e09fc7e26 Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:16:36 +0100 Subject: [PATCH 1/9] Add maintenance page --- app/config/__init__.py | 1 + app/main/routes.py | 14 ++++++++++++++ app/templates/main/maintenance-mode.html | 14 ++++++++++++++ helm_deploy/laa-access-civil-legal-aid/values.yaml | 7 ++++++- 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 app/templates/main/maintenance-mode.html diff --git a/app/config/__init__.py b/app/config/__init__.py index 41546868c..3894185e7 100644 --- a/app/config/__init__.py +++ b/app/config/__init__.py @@ -20,3 +20,4 @@ class Config(object): SESSION_COOKIE_HTTPONLY = True SENTRY_DSN = os.environ.get("SENTRY_DSN") LANGUAGES = {"en": "English", "cy": "Welsh"} + MAINTENANCE_MODE = os.environ.get("MAINTENANCE_MODE", "False").lower() == "true" diff --git a/app/main/routes.py b/app/main/routes.py index 87cab6bc9..31c80280d 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -9,6 +9,7 @@ request, current_app, abort, + url_for, ) from flask_wtf.csrf import CSRFError from werkzeug.exceptions import HTTPException @@ -45,6 +46,12 @@ def set_locale(locale): ) return response +@bp.route("/maintenance-mode", methods=["GET"]) +def maintenance_mode_page(): + if not current_app.config["MAINTENANCE_MODE"]: + return redirect(url_for("main.index")) + return render_template("maintenance-mode.html"), 503 + @bp.route("/accessibility", methods=["GET"]) def accessibility(): @@ -100,3 +107,10 @@ def http_exception(error): def csrf_error(error): flash("The form you were submitting has expired. Please try again.") return redirect(request.full_path) + + +@bp.before_request +def maintenance_mode_middleware(): + maintenance_url = url_for("main.maintenance_mode_page") + if current_app.config["MAINTENANCE_MODE"] and request.path != maintenance_url: + return redirect(maintenance_url) diff --git a/app/templates/main/maintenance-mode.html b/app/templates/main/maintenance-mode.html new file mode 100644 index 000000000..1ab514497 --- /dev/null +++ b/app/templates/main/maintenance-mode.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block pageTitle %}This service is currently down for maintenance{% endblock %} + +{% set mainClasses = "govuk-main-wrapper--l" %} + +{% block content %} +
+
+

This service is currently down for maintenance

+

'If you were part way through the service, you will have to start again when the service becomes available.

+
+
+{% endblock %} diff --git a/helm_deploy/laa-access-civil-legal-aid/values.yaml b/helm_deploy/laa-access-civil-legal-aid/values.yaml index b68824cf0..c793294f8 100644 --- a/helm_deploy/laa-access-civil-legal-aid/values.yaml +++ b/helm_deploy/laa-access-civil-legal-aid/values.yaml @@ -67,4 +67,9 @@ envVars: SENTRY_DSN: secret: name: sentry - key: dsn \ No newline at end of file + key: dsn + MAINTENANCE_MODE: + configmap: + name: maintenance-mode + key: enabled + optional: true \ No newline at end of file From a7e2acf16eb1cd734ff81fb7c19b7a021e34bde8 Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:27:21 +0100 Subject: [PATCH 2/9] exempt /status from maintenance redirect --- app/main/routes.py | 10 ++++++- app/templates/main/maintenance-mode.html | 27 ++++++++++++++++++- .../templates/deployment.yaml | 4 +-- .../templates/ingress.yaml | 1 + 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/app/main/routes.py b/app/main/routes.py index 31c80280d..610a48a6e 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -46,6 +46,10 @@ def set_locale(locale): ) return response +@bp.route("/status", methods=["GET"]) +def status(): + return "OK" + @bp.route("/maintenance-mode", methods=["GET"]) def maintenance_mode_page(): if not current_app.config["MAINTENANCE_MODE"]: @@ -112,5 +116,9 @@ def csrf_error(error): @bp.before_request def maintenance_mode_middleware(): maintenance_url = url_for("main.maintenance_mode_page") - if current_app.config["MAINTENANCE_MODE"] and request.path != maintenance_url: + exempt_urls = [ + maintenance_url, + url_for("main.status"), + ] + if current_app.config["MAINTENANCE_MODE"] and request.path not in exempt_urls: return redirect(maintenance_url) diff --git a/app/templates/main/maintenance-mode.html b/app/templates/main/maintenance-mode.html index 1ab514497..ba39f4731 100644 --- a/app/templates/main/maintenance-mode.html +++ b/app/templates/main/maintenance-mode.html @@ -8,7 +8,32 @@

This service is currently down for maintenance

-

'If you were part way through the service, you will have to start again when the service becomes available.

+

If you were part way through the service, you will have to start again when the service becomes available.

+ +

Contact the Civil Legal Advice Helpline if you need urgent information or advice.

+

Telephone:
+ 0345 345 4345 +

+ +

Textphone:
+ 0845 609 6677 +

+ +
+

+ Calls will cost approximately 9p per minute from landline. Calls from mobiles may cost more. +

+

+ If you are worried about the cost, you can request a call-back within 24 hours by either calling the helpline or texting ‘legal aid’ and your name to 80010. +

+
+

Opening times:
+ + Monday to Friday: 9am to 5pm
+ Saturday: 9am to 12.30pm +
+

+
{% endblock %} diff --git a/helm_deploy/laa-access-civil-legal-aid/templates/deployment.yaml b/helm_deploy/laa-access-civil-legal-aid/templates/deployment.yaml index 833c0b305..81883dd42 100644 --- a/helm_deploy/laa-access-civil-legal-aid/templates/deployment.yaml +++ b/helm_deploy/laa-access-civil-legal-aid/templates/deployment.yaml @@ -44,9 +44,9 @@ spec: protocol: TCP livenessProbe: httpGet: - path: / + path: /status port: http readinessProbe: httpGet: - path: / + path: /status port: http diff --git a/helm_deploy/laa-access-civil-legal-aid/templates/ingress.yaml b/helm_deploy/laa-access-civil-legal-aid/templates/ingress.yaml index 82ec81bcc..259e4561b 100644 --- a/helm_deploy/laa-access-civil-legal-aid/templates/ingress.yaml +++ b/helm_deploy/laa-access-civil-legal-aid/templates/ingress.yaml @@ -13,6 +13,7 @@ metadata: labels: {{- include "laa-access-civil-legal-aid.labels" . | nindent 4 }} annotations: + nginx.ingress.kubernetes.io/custom-http-errors: "413,502,504" {{- if .Values.ingress.cluster.name }} external-dns.alpha.kubernetes.io/set-identifier: "{{ $fullName }}-{{ .Release.Namespace }}-{{- .Values.ingress.cluster.name -}}" external-dns.alpha.kubernetes.io/aws-weight: "{{- .Values.ingress.cluster.weight -}}" From 47c34e50561470d46441db9ad5b8b15ef2c171d7 Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:24:09 +0100 Subject: [PATCH 3/9] Adding tests for maintenance mode pages --- .github/workflows/test.yml | 6 ++++++ tests/functional_tests/test_accessibility.py | 5 ++++- tests/unit_tests/test_example.py | 4 ---- tests/unit_tests/test_pages.py | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) delete mode 100644 tests/unit_tests/test_example.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e258e57be..e02080571 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,7 @@ on: workflow_call env: SECRET_KEY: "TEST_KEY" + ENVIRONMENT: CI jobs: @@ -23,12 +24,17 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -r requirements/generated/requirements-development.txt + - name: Unit test with pytest run: | # Remove this after we move from build assets in-app to esbuild npm install pip install pytest pytest-cov + # This is required because at the moment the assets are being built in the app + # When the app tries to access sass files in node_modules it will fail unless this is included + npm install + coverage run -m pytest tests/unit_tests coverage xml diff --git a/tests/functional_tests/test_accessibility.py b/tests/functional_tests/test_accessibility.py index e4104211d..7216606f4 100644 --- a/tests/functional_tests/test_accessibility.py +++ b/tests/functional_tests/test_accessibility.py @@ -5,6 +5,8 @@ from axe_core_python.sync_playwright import Axe import json import os +import shutil + ACCESSIBILITY_STANDARDS = ["wcag2a", "wcag2aa"] @@ -45,7 +47,8 @@ def check_accessibility(page: Page): @pytest.mark.usefixtures("live_server") def test_all_page_accessibility(app, page: Page): - ignored_routes = ["static", "/", "main.set_locale"] + ignored_routes = ["static", "/", "main.status"] + shutil.rmtree("tests/functional_tests/accessibility_output", ignore_errors=True) routes = app.view_functions for route in routes: if route not in ignored_routes: diff --git a/tests/unit_tests/test_example.py b/tests/unit_tests/test_example.py deleted file mode 100644 index 02dbb2a90..000000000 --- a/tests/unit_tests/test_example.py +++ /dev/null @@ -1,4 +0,0 @@ -def test_coverage(): - # Test Pytest coverage - assert 1 + 1 == 2 - pass diff --git a/tests/unit_tests/test_pages.py b/tests/unit_tests/test_pages.py index a6d6eb9b5..355b51aff 100644 --- a/tests/unit_tests/test_pages.py +++ b/tests/unit_tests/test_pages.py @@ -1,3 +1,4 @@ + def test_set_locale(app, client): response = client.get("/locale/cy", headers={"referer": "http://localhost/privacy"}) assert response.status_code == 302 @@ -9,3 +10,20 @@ def test_set_locale(app, client): def test_set_locale_invalid(app, client): response = client.get("/locale/de", headers={"referer": "http://localhost/privacy"}) assert response.status_code == 404, f"Expecting 404 got {response.status_code}" + + +def test_maintenance_page_on(app, client): + app.config["MAINTENANCE_MODE"] = True + response = client.get("/") + assert response.status_code == 302 + assert response.headers["location"] == "/maintenance-mode" + response = client.get("/", follow_redirects=True) + assert response.status_code == 503 + assert response.request.path == "/maintenance-mode" + + +def test_maintenance_page_off(app, client): + app.config["MAINTENANCE_MODE"] = False + response = client.get("/maintenance-mode", follow_redirects=True) + assert response.status_code == 200 + assert response.request.path == "/" From cadb7974623e60a42ac61f31813ad6e3d894c60c Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:48:12 +0100 Subject: [PATCH 4/9] Rename maintenance-mode to service-unavailable --- app/config/__init__.py | 2 +- app/main/routes.py | 20 ++++++------ app/templates/main/503.html | 26 ++++++++++++++-- app/templates/main/maintenance-mode.html | 39 ------------------------ tests/unit_tests/test_pages.py | 15 +++++---- 5 files changed, 42 insertions(+), 60 deletions(-) delete mode 100644 app/templates/main/maintenance-mode.html diff --git a/app/config/__init__.py b/app/config/__init__.py index 3894185e7..85b5e5b61 100644 --- a/app/config/__init__.py +++ b/app/config/__init__.py @@ -20,4 +20,4 @@ class Config(object): SESSION_COOKIE_HTTPONLY = True SENTRY_DSN = os.environ.get("SENTRY_DSN") LANGUAGES = {"en": "English", "cy": "Welsh"} - MAINTENANCE_MODE = os.environ.get("MAINTENANCE_MODE", "False").lower() == "true" + SERVICE_UNAVAILABLE = os.environ.get("MAINTENANCE_MODE", "False").lower() == "true" diff --git a/app/main/routes.py b/app/main/routes.py index 610a48a6e..f9b55746a 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -10,6 +10,7 @@ current_app, abort, url_for, + abort, ) from flask_wtf.csrf import CSRFError from werkzeug.exceptions import HTTPException @@ -50,11 +51,12 @@ def set_locale(locale): def status(): return "OK" -@bp.route("/maintenance-mode", methods=["GET"]) -def maintenance_mode_page(): - if not current_app.config["MAINTENANCE_MODE"]: + +@bp.route("/service-unavailable", methods=["GET"]) +def service_unavailable_page(): + if not current_app.config["SERVICE_UNAVAILABLE"]: return redirect(url_for("main.index")) - return render_template("maintenance-mode.html"), 503 + abort(503) @bp.route("/accessibility", methods=["GET"]) @@ -114,11 +116,11 @@ def csrf_error(error): @bp.before_request -def maintenance_mode_middleware(): - maintenance_url = url_for("main.maintenance_mode_page") +def service_unavailable_middleware(): + service_unavailable_url = url_for("main.service_unavailable_page") exempt_urls = [ - maintenance_url, + service_unavailable_url, url_for("main.status"), ] - if current_app.config["MAINTENANCE_MODE"] and request.path not in exempt_urls: - return redirect(maintenance_url) + if current_app.config["SERVICE_UNAVAILABLE"] and request.path not in exempt_urls: + return redirect(service_unavailable_url) diff --git a/app/templates/main/503.html b/app/templates/main/503.html index a08854aad..53f397020 100644 --- a/app/templates/main/503.html +++ b/app/templates/main/503.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block pageTitle %}Sorry, the service is unavailable – {{config['SERVICE_NAME']}} – GOV.UK{% endblock %} +{% block pageTitle %}Sorry, the service is unavailable{% endblock %} {% set mainClasses = "govuk-main-wrapper--l" %} @@ -8,7 +8,27 @@

Sorry, the service is unavailable

-

You will be able to use the service from 9am on Monday 19 November 2018.

+

The service will be available again soon - try in the next hour.

+ +

If you already started using the service, your answers will not be saved.

+

If you need urgent help

+

Contact the Civil Legal Advice (CLA) helpline.

+

+ Telephone: 0345 345 4345
+ Relay UK (textphone and app): 18001 then 0345 345 4345 +

+

+ Monday to Friday, 9am to 8pm
+ Saturday, 9am to 12:30pm
+ Find out about call charges +

+

+ If you’re worried about the cost of a call: +

+

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/app/templates/main/maintenance-mode.html b/app/templates/main/maintenance-mode.html deleted file mode 100644 index ba39f4731..000000000 --- a/app/templates/main/maintenance-mode.html +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "base.html" %} - -{% block pageTitle %}This service is currently down for maintenance{% endblock %} - -{% set mainClasses = "govuk-main-wrapper--l" %} - -{% block content %} -
-
-

This service is currently down for maintenance

-

If you were part way through the service, you will have to start again when the service becomes available.

- -

Contact the Civil Legal Advice Helpline if you need urgent information or advice.

-

Telephone:
- 0345 345 4345 -

- -

Textphone:
- 0845 609 6677 -

- -
-

- Calls will cost approximately 9p per minute from landline. Calls from mobiles may cost more. -

-

- If you are worried about the cost, you can request a call-back within 24 hours by either calling the helpline or texting ‘legal aid’ and your name to 80010. -

-
-

Opening times:
- - Monday to Friday: 9am to 5pm
- Saturday: 9am to 12.30pm -
-

- -
-
-{% endblock %} diff --git a/tests/unit_tests/test_pages.py b/tests/unit_tests/test_pages.py index 355b51aff..48dafbf87 100644 --- a/tests/unit_tests/test_pages.py +++ b/tests/unit_tests/test_pages.py @@ -1,4 +1,3 @@ - def test_set_locale(app, client): response = client.get("/locale/cy", headers={"referer": "http://localhost/privacy"}) assert response.status_code == 302 @@ -12,18 +11,18 @@ def test_set_locale_invalid(app, client): assert response.status_code == 404, f"Expecting 404 got {response.status_code}" -def test_maintenance_page_on(app, client): - app.config["MAINTENANCE_MODE"] = True +def test_service_unavailable_on(app, client): + app.config["SERVICE_UNAVAILABLE"] = True response = client.get("/") assert response.status_code == 302 - assert response.headers["location"] == "/maintenance-mode" + assert response.headers["location"] == "/service-unavailable" response = client.get("/", follow_redirects=True) assert response.status_code == 503 - assert response.request.path == "/maintenance-mode" + assert response.request.path == "/service-unavailable" -def test_maintenance_page_off(app, client): - app.config["MAINTENANCE_MODE"] = False - response = client.get("/maintenance-mode", follow_redirects=True) +def test_service_unavailable_off(app, client): + app.config["SERVICE_UNAVAILABLE"] = False + response = client.get("/service-unavailable", follow_redirects=True) assert response.status_code == 200 assert response.request.path == "/" From ef71398627cc650933cb21e97008a9be1155390c Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:19:03 +0100 Subject: [PATCH 5/9] Make service-unavailable page content translatable --- app/templates/main/503.html | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/templates/main/503.html b/app/templates/main/503.html index 53f397020..6cf13c23e 100644 --- a/app/templates/main/503.html +++ b/app/templates/main/503.html @@ -7,26 +7,26 @@ {% block content %}
-

Sorry, the service is unavailable

-

The service will be available again soon - try in the next hour.

+

{% trans %}Sorry, the service is unavailable{% endtrans%}

+

{% trans %}The service will be available again soon - try in the next hour.{% endtrans%}

-

If you already started using the service, your answers will not be saved.

-

If you need urgent help

-

Contact the Civil Legal Advice (CLA) helpline.

+

{% trans %}If you already started using the service, your answers will not be saved.{% endtrans%}

+

{% trans %}If you need urgent help{% endtrans%}

+

{% trans %}Contact the Civil Legal Advice (CLA) helpline.{% endtrans%}

- Telephone: 0345 345 4345
- Relay UK (textphone and app): 18001 then 0345 345 4345 + {% trans %}Telephone{% endtrans%}: 0345 345 4345
+ {% trans %}Relay UK{% endtrans%} {% trans %}(textphone and app): 18001 then 0345 345 4345{% endtrans%}

- Monday to Friday, 9am to 8pm
- Saturday, 9am to 12:30pm
- Find out about call charges + {% trans %}Monday to Friday, 9am to 8pm{% endtrans%}
+ {% trans %}Saturday, 9am to 12:30pm{% endtrans%}
+ {% trans %}Find out about call charges{% endtrans%}

- If you’re worried about the cost of a call: + {% trans %}If you’re worried about the cost of a call{% endtrans%}:

From 3ea38fe5a7ff8ab91b67bd1c227f12c6d446eb24 Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:35:59 +0100 Subject: [PATCH 6/9] Ignore main.set_locale when doing accessibility testing --- app/main/routes.py | 2 +- app/templates/main/503.html | 2 +- tests/functional_tests/test_accessibility.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/main/routes.py b/app/main/routes.py index f9b55746a..75c856c89 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -8,7 +8,6 @@ render_template, request, current_app, - abort, url_for, abort, ) @@ -47,6 +46,7 @@ def set_locale(locale): ) return response + @bp.route("/status", methods=["GET"]) def status(): return "OK" diff --git a/app/templates/main/503.html b/app/templates/main/503.html index 6cf13c23e..67a17b730 100644 --- a/app/templates/main/503.html +++ b/app/templates/main/503.html @@ -26,7 +26,7 @@

{% trans %}If you need urgent help{% endtrans%}

{% trans %}If you’re worried about the cost of a call{% endtrans%}:

diff --git a/tests/functional_tests/test_accessibility.py b/tests/functional_tests/test_accessibility.py index 7216606f4..e78d26e53 100644 --- a/tests/functional_tests/test_accessibility.py +++ b/tests/functional_tests/test_accessibility.py @@ -47,7 +47,7 @@ def check_accessibility(page: Page): @pytest.mark.usefixtures("live_server") def test_all_page_accessibility(app, page: Page): - ignored_routes = ["static", "/", "main.status"] + ignored_routes = ["static", "/", "main.status", "main.set_locale"] shutil.rmtree("tests/functional_tests/accessibility_output", ignore_errors=True) routes = app.view_functions for route in routes: From 7d30b06d9ca55f1aeeeae56e75ba52eac8fa3888 Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:41:17 +0100 Subject: [PATCH 7/9] return early in service_unavailable_middleware --- app/main/routes.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/main/routes.py b/app/main/routes.py index 75c856c89..35715827b 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -117,10 +117,13 @@ def csrf_error(error): @bp.before_request def service_unavailable_middleware(): + if not current_app.config["SERVICE_UNAVAILABLE"]: + return + service_unavailable_url = url_for("main.service_unavailable_page") exempt_urls = [ service_unavailable_url, url_for("main.status"), ] - if current_app.config["SERVICE_UNAVAILABLE"] and request.path not in exempt_urls: + if request.path not in exempt_urls: return redirect(service_unavailable_url) From fe4489b0fe7dbe24b9eda492fe83203884e640dd Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:06:24 +0100 Subject: [PATCH 8/9] Update page title to include the service name --- app/templates/main/503.html | 2 +- compose.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/templates/main/503.html b/app/templates/main/503.html index 67a17b730..c1a793a96 100644 --- a/app/templates/main/503.html +++ b/app/templates/main/503.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block pageTitle %}Sorry, the service is unavailable{% endblock %} +{% block pageTitle %}{% trans %}Sorry, the service is unavailable{% endtrans %} – {{ config.SERVICE_NAME }} – GOV.UK{% endblock %} {% set mainClasses = "govuk-main-wrapper--l" %} diff --git a/compose.yml b/compose.yml index ffb759a2d..972bf8bcb 100644 --- a/compose.yml +++ b/compose.yml @@ -10,6 +10,7 @@ services: restart: always environment: - SECRET_KEY=CHANGE_ME + - MAINTENANCE_MODE=FALSE - FLASK_RUN_PORT=8020 - SENTRY_DSN=${SENTRY_DSN:-} ports: From 8b729452e22390af0e10ac161b2d3c213753c0ee Mon Sep 17 00:00:00 2001 From: said-moj <45761276+said-moj@users.noreply.github.com> Date: Fri, 27 Sep 2024 15:45:11 +0100 Subject: [PATCH 9/9] Exclude all footer links from service unavailable redirect --- app/main/routes.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/main/routes.py b/app/main/routes.py index 35715827b..043037a2f 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -124,6 +124,11 @@ def service_unavailable_middleware(): exempt_urls = [ service_unavailable_url, url_for("main.status"), + url_for("main.cookies"), + url_for("main.accessibility"), + url_for("main.privacy"), + url_for("main.set_locale", locale="en"), + url_for("main.set_locale", locale="cy"), ] if request.path not in exempt_urls: return redirect(service_unavailable_url)