Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions cms/dashboard/management/commands/build_cms_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ def handle(self, *args, **options):
build_cms_site_helpers.create_feedback_page(
name="feedback", parent_page=root_page
)

build_cms_site_helpers.create_authentication_error_page(
name="auth_error_page", parent_page=root_page
)

build_cms_site_helpers.create_menu_snippet()

@classmethod
Expand Down Expand Up @@ -140,8 +145,10 @@ def _build_respiratory_viruses_section(cls, root_page: UKHSARootPage) -> None:
other_respiratory_viruses_page.move(
target=respiratory_viruses_index_page, pos="last-child"
)
influenza_page.move(target=respiratory_viruses_index_page, pos="last-child")
covid_19_page.move(target=respiratory_viruses_index_page, pos="last-child")
influenza_page.move(
target=respiratory_viruses_index_page, pos="last-child")
covid_19_page.move(
target=respiratory_viruses_index_page, pos="last-child")

@classmethod
def _build_cover_section(cls, root_page: UKHSARootPage) -> None:
Expand All @@ -155,7 +162,8 @@ def _build_cover_section(cls, root_page: UKHSARootPage) -> None:
name="childhood_vaccinations_index", parent_page=root_page
)

childhood_vaccinations_page.move(target=cover_index_page, pos="last-child")
childhood_vaccinations_page.move(
target=cover_index_page, pos="last-child")

@classmethod
def _build_common_pages(cls, root_page: UKHSARootPage) -> None:
Expand All @@ -167,7 +175,8 @@ def _build_common_pages(cls, root_page: UKHSARootPage) -> None:
build_cms_site_helpers.create_common_page(
name="whats_coming", parent_page=root_page
)
build_cms_site_helpers.create_common_page(name="cookies", parent_page=root_page)
build_cms_site_helpers.create_common_page(
name="cookies", parent_page=root_page)
build_cms_site_helpers.create_common_page(
name="accessibility_statement", parent_page=root_page
)
Expand All @@ -180,4 +189,5 @@ def _clear_cms() -> None:
# Wipe the existing site, pages & badges
Site.objects.all().delete()
Badge.objects.all().delete()
Page.objects.filter(pk__gte=2).delete() # Wagtail welcome page and all others
# Wagtail welcome page and all others
Page.objects.filter(pk__gte=2).delete()
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
create_whats_new_parent_page,
create_whats_new_child_entry,
create_feedback_page,
create_authentication_error_page,
)
from .menu import create_menu_snippet
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from cms.dashboard.management.commands.build_cms_site_helpers.landing_page import (
create_landing_page_body_wih_page_links,
)
from cms.error.models import ErrorPage, ErrorPageRelatedLink
from cms.forms.models import FormField, FormPage
from cms.home.models import LandingPage
from cms.home.models.landing_page import LandingPageRelatedLink
Expand Down Expand Up @@ -189,6 +190,30 @@ def create_common_page(*, name: str, parent_page: Page) -> CommonPage:
return page


def create_authentication_error_page(*, name: str, parent_page: Page) -> ErrorPage:
data = open_example_page_response(page_name=name)

page = ErrorPage(
body=data["body"],
error_line=data["error_line"],
error_text=data["error_text"],
sub_text=data["sub_text"],
title=data["title"],
slug=data["meta"]["slug"],
seo_title=data["meta"]["seo_title"],
search_description=data["meta"]["search_description"],
)
_add_page_to_parent(page=page, parent_page=parent_page)

_create_related_links(
related_link_class=ErrorPageRelatedLink,
response_data=data,
page=page,
)

return page


def _remove_comment_from_body(*, body: dict[list[dict]]) -> list[dict]:
return [item for item in body if "_comment" not in item]

Expand Down
72 changes: 72 additions & 0 deletions cms/dashboard/templates/cms_starting_pages/auth_error_page.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"id": 243,
"meta": {
"seo_title": "Authentication Error",
"search_description": "",
"type": "error.ErrorPage",
"detail_url": "https://localhost/api/pages/243/",
"html_url": "https://localhost/authentication-error/",
"slug": "authentication-error",
"show_in_menus": false,
"first_published_at": "2026-03-12T11:37:14.391237Z",
"alias_of": null,
"parent": {
"id": 163,
"meta": {
"type": "home.UKHSARootPage",
"detail_url": "https://localhost/api/pages/163/",
"html_url": null
},
"title": "UKHSA Dashboard Root"
}
},
"title": "Failed to sign in",
"body": null,
"seo_change_frequency": 5,
"seo_priority": "0.1",
"last_updated_at": "2026-03-12T14:35:25.243922Z",
"last_published_at": "2026-03-12T14:35:25.243922Z",
"active_announcements": [],
"error_line": "An error occurred that meant we were unable to authenticate you.",
"error_text": "<p data-block-key=\"genyw\">Reason sign in may have failed:</p><ul><li data-block-key=\"7tar0\">You are not authorised to access the data on this dashboard</li><li data-block-key=\"5tvaa\">Your internet connection may have dropped</li><li data-block-key=\"ce6si\">An unknown error occurred during the sign in process</li></ul>",
"sub_text": "<p data-block-key=\"1bc9h\">If you think you have the required authorisation to access the dashboard, please try again and make sure your internet connection is stable. If the problem continues, contact support.</p>",
"related_links_layout": "Sidebar",
"related_links": [
{
"id": 1,
"meta": {
"type": "error.ErrorPageRelatedLink"
},
"title": "Link 1",
"url": "https://www.google.com",
"body": "<p data-block-key=\"yjvpv\">This is a link</p>"
},
{
"id": 2,
"meta": {
"type": "error.ErrorPageRelatedLink"
},
"title": "Link 2",
"url": "https://www.google.com",
"body": "<p data-block-key=\"yjvpv\">sfsfsdf</p>"
},
{
"id": 3,
"meta": {
"type": "error.ErrorPageRelatedLink"
},
"title": "Link 3",
"url": "https://www.google.com",
"body": "<p data-block-key=\"yjvpv\">sdfsdfsdf</p>"
},
{
"id": 4,
"meta": {
"type": "error.ErrorPageRelatedLink"
},
"title": "Link 4",
"url": "https://www.google.com",
"body": "<p data-block-key=\"yjvpv\">sfsdfsdf</p>"
}
]
}
12 changes: 12 additions & 0 deletions cms/dynamic_content/help_texts.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,18 @@
For linking to external url. (Only one of page or external_url must be filled not both).
"""

ERROR_PAGE_LINE_FIELD: str = """
This is the error summary text that will be displayed in red at the top of the error view.
"""

ERROR_PAGE_TEXT_FIELD: str = """
This is a rich text field that can be used to display detailed information about the error that the user is experiencing
"""

ERROR_PAGE_SUB_TEXT_FIELD: str = """
This is a rich text field that can be used to display further information to the user. This text will appear below the error at the top of the page.
"""

PAGE_CLASSIFICATION: str = """
The classification level of all data on this page (only applies to non-public pages). Defaults to `Official-Sensitive`.
"""
Empty file added cms/error/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions cms/error/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ErrorConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "cms.error"
41 changes: 41 additions & 0 deletions cms/error/managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
This file contains the custom QuerySet and Manager classes associated with the `ErrorPage` model.

Note that the application layer should only call into the `Manager` class.
The application should not interact directly with the `QuerySet` class.
"""

from django.db import models
from wagtail.models import PageManager
from wagtail.query import PageQuerySet


class ErrorPageQuerySet(PageQuerySet):
"""Custom queryset which can be used by the `ErrorPageManager`"""

def get_live_pages(self) -> models.QuerySet:
"""Gets the all currently live pages.

Returns:
QuerySet: A queryset of the live pages:
Examples:
`<ErrorPageQuerySet [<ErrorPage: About>, <ErrorPage: Compliance>, ...]>`
"""
return self.filter(live=True)


class ErrorPageManager(PageManager):
"""Custom model manager class for the `ErrorPage` model."""

def get_queryset(self) -> ErrorPageQuerySet:
return ErrorPageQuerySet(model=self.model, using=self.db)

def get_live_pages(self) -> models.QuerySet:
"""Gets the all currently live pages.

Returns:
QuerySet: A queryset of the live pages:
Examples:
`<ErrorPageQuerySet [<ErrorPage: About>, <ErrorPage: Compliance>, ...]>`
"""
return self.get_queryset().get_live_pages()
Loading
Loading