diff --git a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/host_editions_table_component.rb b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/host_editions_table_component.rb index ed3e9a51174..5f56dbe7dc8 100644 --- a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/host_editions_table_component.rb +++ b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/host_editions_table_component.rb @@ -3,12 +3,13 @@ class ContentBlockManager::ContentBlock::Document::Show::HostEditionsTableComponent < ViewComponent::Base TABLE_ID = "host_editions" - def initialize(caption:, host_content_items:, is_preview: false, current_page: nil, order: nil) + def initialize(caption:, host_content_items:, content_block_edition:, is_preview: false, current_page: nil, order: nil) @caption = caption @host_content_items = host_content_items @is_preview = is_preview @current_page = current_page.presence || 1 @order = order.presence || ContentBlockManager::GetHostContentItems::DEFAULT_ORDER + @content_block_edition = content_block_edition end def current_page @@ -25,7 +26,7 @@ def base_pagination_path private - attr_reader :caption, :host_content_items, :order + attr_reader :caption, :host_content_items, :order, :content_block_edition def rows return [] unless host_content_items @@ -81,7 +82,7 @@ def users def frontend_path(content_item) if @is_preview - Plek.external_url_for("draft-origin") + content_item.base_path + helpers.content_block_manager.content_block_manager_content_block_host_content_preview_path(id: content_block_edition.id, host_content_id: content_item.host_content_id) else Plek.website_root + content_item.base_path end diff --git a/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/host_content_controller.rb b/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/host_content_controller.rb new file mode 100644 index 00000000000..9d8ca3f5dff --- /dev/null +++ b/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/host_content_controller.rb @@ -0,0 +1,7 @@ +class ContentBlockManager::ContentBlock::Editions::HostContentController < ContentBlockManager::BaseController + def preview + host_content_id = params[:host_content_id] + content_block_edition = ContentBlockManager::ContentBlock::Edition.find(params[:id]) + @preview_content = ContentBlockManager::GetPreviewContent.for_content_id(content_id: host_content_id, content_block_edition:) + end +end diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/host_content_item.rb b/lib/engines/content_block_manager/app/models/content_block_manager/host_content_item.rb index c9b71b08430..41b11c94bf1 100644 --- a/lib/engines/content_block_manager/app/models/content_block_manager/host_content_item.rb +++ b/lib/engines/content_block_manager/app/models/content_block_manager/host_content_item.rb @@ -9,6 +9,7 @@ class HostContentItem < Data.define( :last_edited_at, :unique_pageviews, :instances, + :host_content_id, ) def last_edited_at diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/preview_content.rb b/lib/engines/content_block_manager/app/models/content_block_manager/preview_content.rb new file mode 100644 index 00000000000..822e61fe9ad --- /dev/null +++ b/lib/engines/content_block_manager/app/models/content_block_manager/preview_content.rb @@ -0,0 +1,4 @@ +module ContentBlockManager + class PreviewContent < Data.define(:title, :html) + end +end diff --git a/lib/engines/content_block_manager/app/services/content_block_manager/get_host_content_items.rb b/lib/engines/content_block_manager/app/services/content_block_manager/get_host_content_items.rb index d06af4456b3..554f2bc9547 100644 --- a/lib/engines/content_block_manager/app/services/content_block_manager/get_host_content_items.rb +++ b/lib/engines/content_block_manager/app/services/content_block_manager/get_host_content_items.rb @@ -30,6 +30,7 @@ def items last_edited_at: item["last_edited_at"], unique_pageviews: item["unique_pageviews"], instances: item["instances"], + host_content_id: item["host_content_id"], ) end diff --git a/lib/engines/content_block_manager/app/services/content_block_manager/get_preview_content.rb b/lib/engines/content_block_manager/app/services/content_block_manager/get_preview_content.rb new file mode 100644 index 00000000000..cd270302725 --- /dev/null +++ b/lib/engines/content_block_manager/app/services/content_block_manager/get_preview_content.rb @@ -0,0 +1,83 @@ +require "net/http" +require "json" +require "uri" + +module ContentBlockManager + class GetPreviewContent + def self.for_content_id(content_id:, content_block_edition:) + new(content_id:, content_block_edition:).for_content_id + end + + def for_content_id + ContentBlockManager::PreviewContent.new(title: content_item["title"], html:) + end + + private + + def initialize(content_id:, content_block_edition:) + @content_id = content_id + @content_block_edition = content_block_edition + end + + def html + @html ||= preview_html + end + + def content_item + @content_item ||= begin + response = Services.publishing_api.get_content(@content_id) + response.parsed_content + end + end + + def frontend_base_path + Rails.env.development? ? Plek.external_url_for("government-frontend") : Plek.website_root + end + + def frontend_path + frontend_base_path + content_item["base_path"] + end + + def preview_html + uri = URI(frontend_path) + nokogiri_html = html_snapshot_from_frontend(uri) + replace_existing_content_blocks(nokogiri_html) + end + + def replace_existing_content_blocks(nokogiri_html) + replace_blocks(nokogiri_html) + style_blocks(nokogiri_html) + nokogiri_html + end + + def replace_blocks(nokogiri_html) + @preview_content_block_render ||= @content_block_edition.render + content_block_spans(nokogiri_html).each do |span| + span.replace @preview_content_block_render + end + end + + BLOCK_STYLE = "background-color: yellow;".freeze + + def style_blocks(nokogiri_html) + content_block_spans(nokogiri_html).each do |span| + span["style"] = BLOCK_STYLE + end + end + + def content_block_spans(nokogiri_html) + nokogiri_html.css("span[data-content-id=\"#{@content_block_edition.document.content_id}\"]") + end + + ERROR_HTML = "
Preview not found
".freeze + + def html_snapshot_from_frontend(uri) + begin + raw_html = Net::HTTP.get(uri) + rescue StandardError + raw_html = ERROR_HTML + end + Nokogiri::HTML.parse(raw_html) + end + end +end diff --git a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/show.html.erb b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/show.html.erb index eb3879fadcc..30b83d3ab34 100644 --- a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/show.html.erb +++ b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/show.html.erb @@ -25,6 +25,7 @@ host_content_items: @host_content_items, current_page: @page, order: @order, + content_block_edition: @content_block_document.latest_edition, ), ) %> diff --git a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/editions/host_content/preview.html.erb b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/editions/host_content/preview.html.erb new file mode 100644 index 00000000000..5126c7bb2ae --- /dev/null +++ b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/editions/host_content/preview.html.erb @@ -0,0 +1,16 @@ +<% content_for :page_title, "Preview content block in host document" %> +<% content_for :context, "Preview content block" %> +<% content_for :title, @preview_content.title %> +<% content_for :title_margin_bottom, 0 %> + +Document title: <%= @preview_content.title %>
+title
", + }, + title: @current_host_document["title"], + document_type: "news_story", + base_path: @current_host_document["base_path"], + publishing_app: "test", + }.to_json, + ) + + stub_request( + :get, + Plek.website_root + @current_host_document["base_path"], + ).to_return( + status: 200, + body: "iframe preview
", + ) + + click_on @current_host_document["title"] +end + +Then("The preview page opens in a new tab") do + page.switch_to_window(page.windows.last) + assert_text "Preview content block" + within_frame "preview" do + assert_text @current_host_document["title"] + end end When(/^I save and continue$/) do diff --git a/lib/engines/content_block_manager/test/components/content_block/document/show/host_editions_table_component_test.rb b/lib/engines/content_block_manager/test/components/content_block/document/show/host_editions_table_component_test.rb index 8aee3d11199..82884197dd8 100644 --- a/lib/engines/content_block_manager/test/components/content_block/document/show/host_editions_table_component_test.rb +++ b/lib/engines/content_block_manager/test/components/content_block/document/show/host_editions_table_component_test.rb @@ -2,7 +2,7 @@ class ContentBlockManager::ContentBlock::Document::Show::HostEditionsTableComponentTest < ViewComponent::TestCase extend Minitest::Spec::DSL - include Rails.application.routes.url_helpers + include ContentBlockManager::Engine.routes.url_helpers include ActionView::Helpers::DateHelper let(:described_class) { ContentBlockManager::ContentBlock::Document::Show::HostEditionsTableComponent } @@ -28,6 +28,7 @@ class ContentBlockManager::ContentBlock::Document::Show::HostEditionsTableCompon "last_edited_at" => Time.zone.now.to_s, "publishing_organisation" => publishing_organisation, "unique_pageviews" => unique_pageviews, + "host_content_id" => SecureRandom.uuid, "instances" => 1, ) end @@ -40,12 +41,17 @@ class ContentBlockManager::ContentBlock::Document::Show::HostEditionsTableCompon ) end + let(:content_block_edition) do + build(:content_block_edition, :email_address, id: SecureRandom.uuid) + end + def self.it_returns_unknown_user it "returns Unknown user" do render_inline( described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -54,7 +60,7 @@ def self.it_returns_unknown_user end around do |test| - with_request_url content_block_manager_path do + with_request_url content_block_manager_root_path do test.call end end @@ -65,6 +71,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -91,6 +98,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) assert_no_selector "tbody .govuk-table__cell a", text: host_content_item.publishing_organisation["title"] @@ -101,12 +109,13 @@ def self.it_returns_unknown_user it "links to the organisation instead of printing the name" do organisation = create(:organisation, content_id: host_content_item.publishing_organisation["content_id"], name: host_content_item.publishing_organisation["title"]) - expected_href = admin_organisation_path(organisation) + expected_href = Rails.application.routes.url_helpers.admin_organisation_path(organisation) render_inline( described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) assert_selector "tbody .govuk-table__cell a", @@ -130,6 +139,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -165,6 +175,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -179,10 +190,11 @@ def self.it_returns_unknown_user is_preview: true, caption:, host_content_items:, + content_block_edition:, ), ) - assert_selector "a[href='#{Plek.external_url_for('draft-origin') + host_content_item.base_path}']", text: host_content_item.title + assert_selector "a[href='#{content_block_manager_content_block_host_content_preview_path(id: content_block_edition.id, host_content_id: host_content_item.host_content_id)}']", text: host_content_item.title end end @@ -192,6 +204,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -203,6 +216,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -223,6 +237,7 @@ def self.it_returns_unknown_user caption:, host_content_items:, order:, + content_block_edition:, ), ) @@ -235,6 +250,7 @@ def self.it_returns_unknown_user caption:, host_content_items:, order: "-#{order}", + content_block_edition:, ), ) @@ -259,6 +275,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -281,6 +298,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -293,6 +311,7 @@ def self.it_returns_unknown_user described_class.new( caption:, host_content_items:, + content_block_edition:, ), ) @@ -306,6 +325,7 @@ def self.it_returns_unknown_user caption:, host_content_items:, current_page: 2, + content_block_edition:, ), ) diff --git a/lib/engines/content_block_manager/test/factories/host_content_item.rb b/lib/engines/content_block_manager/test/factories/host_content_item.rb index 03fc23659fe..267bd5e8482 100644 --- a/lib/engines/content_block_manager/test/factories/host_content_item.rb +++ b/lib/engines/content_block_manager/test/factories/host_content_item.rb @@ -9,6 +9,7 @@ last_edited_at { 2.days.ago.to_s } unique_pageviews { 123 } instances { 1 } + host_content_id { SecureRandom.uuid } initialize_with do new(title:, @@ -19,6 +20,7 @@ last_edited_by_editor_id:, last_edited_at:, unique_pageviews:, + host_content_id:, instances:) end end diff --git a/lib/engines/content_block_manager/test/factories/preview_content.rb b/lib/engines/content_block_manager/test/factories/preview_content.rb new file mode 100644 index 00000000000..4288e1b535f --- /dev/null +++ b/lib/engines/content_block_manager/test/factories/preview_content.rb @@ -0,0 +1,10 @@ +FactoryBot.define do + factory :preview_content, class: "ContentBlockManager::PreviewContent" do + title { "Example Title" } + html { "Example HTML
" } + + initialize_with do + new(title:, html:) + end + end +end diff --git a/lib/engines/content_block_manager/test/unit/app/models/preview_content_test.rb b/lib/engines/content_block_manager/test/unit/app/models/preview_content_test.rb new file mode 100644 index 00000000000..93bfb75fe59 --- /dev/null +++ b/lib/engines/content_block_manager/test/unit/app/models/preview_content_test.rb @@ -0,0 +1,14 @@ +require "test_helper" + +class ContentBlockManager::PreviewContentTest < ActiveSupport::TestCase + extend Minitest::Spec::DSL + + let(:title) { "Ministry of Example" } + let(:html) { "Ministry of Example
" } + let(:preview_content) { build(:preview_content, title:, html:) } + + it "returns title and html" do + assert_equal preview_content.title, title + assert_equal preview_content.html, html + end +end diff --git a/lib/engines/content_block_manager/test/unit/app/services/get_host_content_items_test.rb b/lib/engines/content_block_manager/test/unit/app/services/get_host_content_items_test.rb index 5946d0a2f1c..5d00aa1f4a8 100644 --- a/lib/engines/content_block_manager/test/unit/app/services/get_host_content_items_test.rb +++ b/lib/engines/content_block_manager/test/unit/app/services/get_host_content_items_test.rb @@ -7,6 +7,8 @@ class ContentBlockManager::GetHostContentItemsTest < ActiveSupport::TestCase let(:target_content_id) { SecureRandom.uuid } + let(:host_content_id) { SecureRandom.uuid } + let(:response_body) do { "content_id" => SecureRandom.uuid, @@ -22,6 +24,7 @@ class ContentBlockManager::GetHostContentItemsTest < ActiveSupport::TestCase "last_edited_at" => "2023-01-01T08:00:00.000Z", "unique_pageviews" => 123, "instances" => 1, + "host_content_id" => host_content_id, "primary_publishing_organisation" => { "content_id" => SecureRandom.uuid, "title" => "bar", @@ -110,6 +113,7 @@ class ContentBlockManager::GetHostContentItemsTest < ActiveSupport::TestCase assert_equal result[0].last_edited_at, Time.zone.parse(response_body["results"][0]["last_edited_at"]) assert_equal result[0].unique_pageviews, response_body["results"][0]["unique_pageviews"] assert_equal result[0].instances, response_body["results"][0]["instances"] + assert_equal result[0].host_content_id, response_body["results"][0]["host_content_id"] assert_equal result[0].publishing_organisation, expected_publishing_organisation end diff --git a/lib/engines/content_block_manager/test/unit/app/services/get_preview_content_test.rb b/lib/engines/content_block_manager/test/unit/app/services/get_preview_content_test.rb new file mode 100644 index 00000000000..c36075e7d4a --- /dev/null +++ b/lib/engines/content_block_manager/test/unit/app/services/get_preview_content_test.rb @@ -0,0 +1,75 @@ +require "test_helper" + +class ContentBlockManager::GetPreviewContentTest < ActiveSupport::TestCase + extend Minitest::Spec::DSL + + let(:described_class) { ContentBlockManager::GetPreviewContent } + let(:host_content_id) { SecureRandom.uuid } + let(:preview_content_id) { SecureRandom.uuid } + let(:host_title) { "Test" } + let(:host_base_path) { "/test" } + let(:uri_mock) { mock } + let(:fake_frontend_response) do + "test
" + end + let(:block_render) do + " " + end + let(:block_render_with_style) do + " " + end + let(:expected_html) do + "test
#{block_render_with_style}" + end + let(:error_html) do + "Preview not found
" + end + let(:document) do + build(:content_block_document, :email_address, content_id: preview_content_id) + end + let(:block_to_preview) do + build(:content_block_edition, :email_address, document:, details: { "email_address" => "new@new.com" }) + end + + describe "#for_content_id" do + setup do + stub_publishing_api_has_item(content_id: host_content_id, title: host_title, base_path: host_base_path) + block_to_preview.expects(:render).returns(block_render) + end + + it "returns the title and preview HTML for a document" do + Net::HTTP.expects(:get).with(URI(Plek.website_root + host_base_path)).returns(fake_frontend_response) + + expected_content = { + title: host_title, + html: Nokogiri::HTML.parse(expected_html), + } + + actual_content = ContentBlockManager::GetPreviewContent.for_content_id( + content_id: host_content_id, + content_block_edition: block_to_preview, + ) + + assert_equal expected_content[:title], actual_content.title + assert_equal expected_content[:html].to_s, actual_content.html.to_s + end + + it "shows an error template when the request to the frontend throws an error" do + exception = StandardError.new("Something went wrong") + Net::HTTP.expects(:get).with(URI(Plek.website_root + host_base_path)).raises(exception) + + expected_content = { + title: host_title, + html: Nokogiri::HTML.parse(error_html), + } + + actual_content = ContentBlockManager::GetPreviewContent.for_content_id( + content_id: host_content_id, + content_block_edition: block_to_preview, + ) + + assert_equal expected_content[:title], actual_content.title + assert_equal expected_content[:html].to_s, actual_content.html.to_s + end + end +end