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/app/config/__init__.py b/app/config/__init__.py
index 41546868c..85b5e5b61 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"}
+ SERVICE_UNAVAILABLE = os.environ.get("MAINTENANCE_MODE", "False").lower() == "true"
diff --git a/app/main/routes.py b/app/main/routes.py
index 87cab6bc9..043037a2f 100644
--- a/app/main/routes.py
+++ b/app/main/routes.py
@@ -8,6 +8,7 @@
render_template,
request,
current_app,
+ url_for,
abort,
)
from flask_wtf.csrf import CSRFError
@@ -46,6 +47,18 @@ def set_locale(locale):
return response
+@bp.route("/status", methods=["GET"])
+def status():
+ return "OK"
+
+
+@bp.route("/service-unavailable", methods=["GET"])
+def service_unavailable_page():
+ if not current_app.config["SERVICE_UNAVAILABLE"]:
+ return redirect(url_for("main.index"))
+ abort(503)
+
+
@bp.route("/accessibility", methods=["GET"])
def accessibility():
return render_template("accessibility.html")
@@ -100,3 +113,22 @@ 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 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"),
+ 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)
diff --git a/app/templates/main/503.html b/app/templates/main/503.html
index a08854aad..c1a793a96 100644
--- a/app/templates/main/503.html
+++ b/app/templates/main/503.html
@@ -1,14 +1,34 @@
{% extends "base.html" %}
-{% block pageTitle %}Sorry, the service is unavailable – {{config['SERVICE_NAME']}} – GOV.UK{% endblock %}
+{% block pageTitle %}{% trans %}Sorry, the service is unavailable{% endtrans %} – {{ config.SERVICE_NAME }} – GOV.UK{% endblock %}
{% set mainClasses = "govuk-main-wrapper--l" %}
{% block content %}
-
Sorry, the service is unavailable
-
You will be able to use the service from 9am on Monday 19 November 2018.
+
{% trans %}Sorry, the service is unavailable{% endtrans%}
+
{% trans %}The service will be available again soon - try in the next hour.{% endtrans%}
+
+
{% 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%}
+
+ {% trans %}Telephone{% endtrans%}: 0345 345 4345
+ {% trans %}Relay UK{% endtrans%} {% trans %}(textphone and app): 18001 then 0345 345 4345{% endtrans%}
+
+
+ {% trans %}Monday to Friday, 9am to 8pm{% endtrans%}
+ {% trans %}Saturday, 9am to 12:30pm{% endtrans%}
+ {% trans %}Find out about call charges{% endtrans%}
+
+
+ {% trans %}If you’re worried about the cost of a call{% endtrans%}:
+
+ - {% trans %}ask the helpline to call you back, or{% endtrans%}
+ - {% trans %}text ‘legalaid’ and your name to 80010 for a call back within 24 hours{% endtrans %}
+
+
-{% endblock %}
\ No newline at end of file
+{% endblock %}
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:
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 -}}"
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
diff --git a/tests/functional_tests/test_accessibility.py b/tests/functional_tests/test_accessibility.py
index e4104211d..e78d26e53 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", "main.set_locale"]
+ 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..48dafbf87 100644
--- a/tests/unit_tests/test_pages.py
+++ b/tests/unit_tests/test_pages.py
@@ -9,3 +9,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_service_unavailable_on(app, client):
+ app.config["SERVICE_UNAVAILABLE"] = True
+ response = client.get("/")
+ assert response.status_code == 302
+ assert response.headers["location"] == "/service-unavailable"
+ response = client.get("/", follow_redirects=True)
+ assert response.status_code == 503
+ assert response.request.path == "/service-unavailable"
+
+
+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 == "/"