From ee54398a9f38abfda4d05a33a994258168fae876 Mon Sep 17 00:00:00 2001 From: Tony McDonald Date: Mon, 15 Jun 2026 12:00:53 +0100 Subject: [PATCH] Fall back to draft content store for unpublished document collection links Adding a not-yet-published GOV.UK URL to a document collection group failed with "Url must reference a GOV.UK page", because the link validation only queries the live content store, which holds published content only. Fall back to the draft content store when the live content store returns a 404, so unpublished URLs resolve again. The live store is still queried first, preserving locale-agnostic lookups (e.g. Welsh pages), and the draft store handles drafts in any locale. Add Services.draft_content_store, authenticated with a dedicated DRAFT_CONTENT_STORE_BEARER_TOKEN, as the draft content store serves non-public content and requires a Signon bearer token. --- .../govuk_url.rb | 9 +++++++- lib/services.rb | 7 +++++++ .../govuk_url_test.rb | 21 ++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/models/document_collection_non_whitehall_link/govuk_url.rb b/app/models/document_collection_non_whitehall_link/govuk_url.rb index 011cfdebd0a..13bd46fc25b 100644 --- a/app/models/document_collection_non_whitehall_link/govuk_url.rb +++ b/app/models/document_collection_non_whitehall_link/govuk_url.rb @@ -41,7 +41,7 @@ def content_id def content_item_from_content_store path = parsed_url.path - item = Services.content_store.content_item(path).to_h + item = content_item_for(path) if item["base_path"] != path && item["document_type"] != "guide" raise GdsApi::HTTPNotFound, 404 @@ -51,4 +51,11 @@ def content_item_from_content_store rescue GdsApi::ContentStore::ItemNotFound raise GdsApi::HTTPNotFound, 404 end + + def content_item_for(path) + Services.content_store.content_item(path).to_h + rescue GdsApi::ContentStore::ItemNotFound + # Fall back to the draft content store for unpublished content + Services.draft_content_store.content_item(path).to_h + end end diff --git a/lib/services.rb b/lib/services.rb index 08e899db84d..10ce79cc87b 100644 --- a/lib/services.rb +++ b/lib/services.rb @@ -16,6 +16,13 @@ def self.content_store @content_store ||= GdsApi::ContentStore.new(Plek.find("content-store")) end + def self.draft_content_store + @draft_content_store ||= GdsApi::ContentStore.new( + Plek.find("draft-content-store"), + bearer_token: ENV.fetch("DRAFT_CONTENT_STORE_BEARER_TOKEN", "example"), + ) + end + def self.asset_manager @asset_manager ||= GdsApi::AssetManager.new( Plek.find("asset-manager"), diff --git a/test/unit/app/models/document_collection_non_whitehall_link/govuk_url_test.rb b/test/unit/app/models/document_collection_non_whitehall_link/govuk_url_test.rb index 463f8d92d59..8726848c63e 100644 --- a/test/unit/app/models/document_collection_non_whitehall_link/govuk_url_test.rb +++ b/test/unit/app/models/document_collection_non_whitehall_link/govuk_url_test.rb @@ -98,8 +98,27 @@ class DocumentCollectionNonWhitehallLink::GovukUrlTest < ActiveSupport::TestCase assert url.valid? end - test "should be invalid when content store returns a 404" do + test "should be valid for an unpublished URL found only in the draft content store" do + draft_content_id = SecureRandom.uuid + Services.content_store.stubs(:content_item).with("/unpublished").raises(GdsApi::ContentStore::ItemNotFound.new(404)) + Services.draft_content_store.stubs(:content_item).with("/unpublished").returns( + "content_id" => draft_content_id, + "title" => "Unpublished", + "base_path" => "/unpublished", + "publishing_app" => "whitehall", + ) + + url = DocumentCollectionNonWhitehallLink::GovukUrl.new( + url: "https://www.gov.uk/unpublished", + document_collection_group: build(:document_collection_group), + ) + + assert url.valid? + end + + test "should be invalid when neither content store has the path" do Services.content_store.stubs(:content_item).raises(GdsApi::ContentStore::ItemNotFound.new(404)) + Services.draft_content_store.stubs(:content_item).raises(GdsApi::ContentStore::ItemNotFound.new(404)) url = DocumentCollectionNonWhitehallLink::GovukUrl.new( url: "https://www.gov.uk/test",