From f21a0badf630bff04cf9376dcfb900d7faff8c55 Mon Sep 17 00:00:00 2001 From: Bruce Bolt Date: Mon, 13 Mar 2023 08:30:55 +0000 Subject: [PATCH] Refactor Get Involved This page was created differently to all the other content types. Refactoring so it is the same as everything else. Co-authored-by: Jon Hallam --- app/controllers/get_involved_controller.rb | 141 ------------------ app/helpers/get_involved_helper.rb | 28 ---- app/presenters/get_involved_presenter.rb | 109 ++++++++++++++ app/views/content_items/get_involved.html.erb | 36 ++--- config/routes.rb | 2 - .../get_involved_controller_test.rb | 119 --------------- test/integration/get_involved_test.rb | 60 ++++++++ 7 files changed, 181 insertions(+), 314 deletions(-) delete mode 100644 app/controllers/get_involved_controller.rb delete mode 100644 app/helpers/get_involved_helper.rb delete mode 100644 test/controllers/get_involved_controller_test.rb create mode 100644 test/integration/get_involved_test.rb diff --git a/app/controllers/get_involved_controller.rb b/app/controllers/get_involved_controller.rb deleted file mode 100644 index 422c2d3b5..000000000 --- a/app/controllers/get_involved_controller.rb +++ /dev/null @@ -1,141 +0,0 @@ -class GetInvolvedController < ContentItemsController - attr_accessor :content_item - - def show - load_content_item - load_get_involved_data - @do_not_show_breadcrumbs = true - @recently_opened = filtered_links(@recently_opened_consultations, t("get_involved.closes")) - @recent_outcomes = filtered_links(@recent_consultation_outcomes, t("get_involved.closed")) - render template: "content_items/get_involved" - end - - def load_content_item - content_item = get_involved_item - - @content_item = PresenterBuilder.new( - content_item, - content_item_path, - view_context, - ).presenter - end - - def load_get_involved_data - @open_consultation_count = retrieve_open_consultation_count - @closed_consultation_count = retrieve_date_filtered_closed_consultations(12) - @next_closing_consultation = retrieve_next_closing - @recently_opened_consultations = retrieve_new_consultations - @recent_consultation_outcomes = retrieve_consultation_outcomes - @take_part_pages = get_involved_item["links"]["take_part_pages"] - end - - def get_involved_item - @get_involved_item ||= Services.content_store.content_item("/government/get-involved") - end - - def retrieve_open_consultation_count - Services.search_api.search({ filter_content_store_document_type: "open_consultation", count: 0 })["total"] - end - - # Aims to find a count of consultations closed in the last n months. - def retrieve_date_filtered_closed_consultations(months) - cutoff_date = Time.zone.now.prev_month(months) - - query = { - filter_content_store_document_type: "closed_consultation", - filter_end_date: "from: #{cutoff_date}", - count: 0, - } - - Services.search_api.search(query)["total"] - end - - def retrieve_next_closing - # Ensure that on query we're not looking in the past - cutoff_date = Time.zone.now.to_date - - query = { - filter_content_store_document_type: "open_consultation", - filter_end_date: "from: #{cutoff_date}", - fields: "end_date,title,link", - order: "end_date", - count: 1, - } - - Services.search_api.search(query)["results"].first - end - - def retrieve_new_consultations - query = { - filter_content_store_document_type: "open_consultation", - fields: "end_date,title,link,organisations", - order: "-start_date", - count: 3, - } - - Services.search_api.search(query)["results"] - end - - def retrieve_consultation_outcomes - # Ensure that on query we're not looking into the future - cutoff_date = Time.zone.now.to_date - - query = { - filter_content_store_document_type: "consultation_outcome", - filter_end_date: "to: #{cutoff_date}", - fields: "end_date,title,link,organisations", - order: "-end_date", - count: 3, - } - - Services.search_api.search(query)["results"] - end - - def time_until_closure(consultation) - days_left = (consultation["end_date"].to_date - Time.zone.now.to_date).to_i - case days_left - when :negative?.to_proc - t("get_involved.closed") - when :zero?.to_proc - t("get_involved.closing_today") - when 1 - t("get_involved.closing_tomorrow") - else - t("get_involved.days_left", number_of_days: days_left) - end - end - - def date_microformat(attribute_name) - attribute_name.to_date.strftime("%d %B %Y") - end - - def filtered_links(array, close_status) - array.map do |item| - { - link: { - text: item["title"], - path: item["link"], - description: "#{close_status} #{date_microformat(item['end_date'])}", - }, - metadata: { - public_updated_at: Time.zone.parse(org_time(item)), - document_type: org_acronym(item), - }, - } - end - end - -private - - def org_time(item) - item["organisations"].map { |org| - org["public_timestamp"] - }.join(", ") - end - - def org_acronym(item) - item["organisations"].map { |org| - org["acronym"] - }.join(", ") - end -end diff --git a/app/helpers/get_involved_helper.rb b/app/helpers/get_involved_helper.rb deleted file mode 100644 index aa6729285..000000000 --- a/app/helpers/get_involved_helper.rb +++ /dev/null @@ -1,28 +0,0 @@ -module GetInvolvedHelper - # Gets the link to the search page for all consultations - def get_consultations_link(filters = %w[open_consultations closed_consultations]) - "/search/policy-papers-and-consultations?#{filters.to_query('content_store_document_type')}" - end - - def page_title - t("get_involved.page_title") - end - - def page_class(css_class) - content_for(:page_class, css_class) - end - - def time_until_closure(consultation) - days_left = (consultation["end_date"].to_date - Time.zone.now.to_date).to_i - case days_left - when :negative?.to_proc - t("get_involved.closed") - when :zero?.to_proc - t("get_involved.closing_today") - when 1 - t("get_involved.closing_tomorrow") - else - t("get_involved.days_left", number_of_days: days_left) - end - end -end diff --git a/app/presenters/get_involved_presenter.rb b/app/presenters/get_involved_presenter.rb index 4ee435095..5ff0e8e08 100644 --- a/app/presenters/get_involved_presenter.rb +++ b/app/presenters/get_involved_presenter.rb @@ -1,2 +1,111 @@ class GetInvolvedPresenter < ContentItemPresenter + def open_consultation_count + Services.search_api.search({ filter_content_store_document_type: "open_consultation", count: 0 })["total"] + end + + def closed_consultation_count + query = { + filter_content_store_document_type: "closed_consultation", + filter_end_date: "from: #{1.year.ago}", + count: 0, + } + + Services.search_api.search(query)["total"] + end + + def next_closing_consultation + query = { + filter_content_store_document_type: "open_consultation", + filter_end_date: "from: #{Time.zone.now.to_date}", + fields: "end_date,title,link", + order: "end_date", + count: 1, + } + + Services.search_api.search(query)["results"].first + end + + def take_part_pages + content_item.dig("links", "take_part_pages") + end + + def recently_opened + filtered_links(recently_opened_consultations, I18n.t("get_involved.closes")) + end + + def recent_outcomes + filtered_links(recent_consultation_outcomes, I18n.t("get_involved.closed")) + end + + def time_until_closure(consultation) + days_left = (consultation["end_date"].to_date - Time.zone.now.to_date).to_i + case days_left + when :negative?.to_proc + I18n.t("get_involved.closed") + when :zero?.to_proc + I18n.t("get_involved.closing_today") + when 1 + I18n.t("get_involved.closing_tomorrow") + else + I18n.t("get_involved.days_left", number_of_days: days_left) + end + end + + def consultations_link + filters = %w[open_consultations closed_consultations] + "/search/policy-papers-and-consultations?#{filters.to_query('content_store_document_type')}" + end + +private + + def recently_opened_consultations + query = { + filter_content_store_document_type: "open_consultation", + fields: "end_date,title,link,organisations", + order: "-start_date", + count: 3, + } + + Services.search_api.search(query)["results"] + end + + def recent_consultation_outcomes + query = { + filter_content_store_document_type: "consultation_outcome", + filter_end_date: "to: #{Time.zone.now.to_date}", + fields: "end_date,title,link,organisations", + order: "-end_date", + count: 3, + } + + Services.search_api.search(query)["results"] + end + + def filtered_links(array, close_status) + array.map do |item| + { + link: { + text: item["title"], + path: item["link"], + description: "#{close_status} #{item['end_date'].to_date.strftime('%d %B %z')}", + }, + metadata: { + public_updated_at: Time.zone.parse(org_time(item)), + document_type: org_acronym(item), + }, + } + end + end + + def org_time(item) + item["organisations"].map { |org| + org["public_timestamp"] + }.join(", ") + end + + def org_acronym(item) + item["organisations"].map { |org| + org["acronym"] + }.join(", ") + end end diff --git a/app/views/content_items/get_involved.html.erb b/app/views/content_items/get_involved.html.erb index f94bb0c0a..b95de38d8 100644 --- a/app/views/content_items/get_involved.html.erb +++ b/app/views/content_items/get_involved.html.erb @@ -1,15 +1,3 @@ -<% page_title %> -<% page_class "govuk-main-wrapper" %> - <%= render "govuk_publishing_components/components/breadcrumbs", { - collapse_on_mobile: true, - breadcrumbs: [ - { - title: "Home", - url: "/" - } - ] - } %> -
<%= render "govuk_publishing_components/components/title", { @@ -51,32 +39,32 @@
<%= render "govuk_publishing_components/components/big_number", { - number: @open_consultation_count, + number: @content_item.open_consultation_count, label: t('get_involved.open_consultations'), href: "/search/policy-papers-and-consultations?content_store_document_type=open_consultations" } %>
<%= render "govuk_publishing_components/components/big_number", { - number: @closed_consultation_count, + number: @content_item.closed_consultation_count, label: t('get_involved.closed_consultations'), href: "/search/policy-papers-and-consultations?content_store_document_type=closed_consultations" } %>
- <% if @next_closing_consultation %> + <% if @content_item.next_closing_consultation %> <%# Attention to closing consultation %> <%= render "govuk_publishing_components/components/inset_text", { } do %> <%= render "govuk_publishing_components/components/heading", { - text: time_until_closure(@next_closing_consultation), + text: @content_item.time_until_closure(@content_item.next_closing_consultation), heading_level: 3 } %>

- <%= @next_closing_consultation['title'] %> + <%= @content_item.next_closing_consultation['title'] %>

- <%= link_to t('get_involved.read_respond'), @next_closing_consultation['link'], class: "govuk-link" %> + <%= link_to t('get_involved.read_respond'), @content_item.next_closing_consultation['link'], class: "govuk-link" %> <% end %> <% end %>
@@ -93,9 +81,9 @@ margin_bottom: 4 } %> <%= render "govuk_publishing_components/components/document_list", { - items: @recently_opened + items: @content_item.recently_opened } %> - <%= link_to(t('get_involved.search_all'), get_consultations_link, class: "govuk-link" ) %> + <%= link_to(t('get_involved.search_all'), @content_item.consultations_link, class: "govuk-link" ) %>
@@ -111,10 +99,10 @@ } %> <%= render "govuk_publishing_components/components/document_list", { - items: @recent_outcomes + items: @content_item.recent_outcomes } %> - <%= link_to(t('get_involved.search_all'), get_consultations_link, class: "govuk-link" ) %> + <%= link_to(t('get_involved.search_all'), @content_item.consultations_link, class: "govuk-link" ) %> @@ -177,7 +165,7 @@ id: "take-part" } %>
- <% @take_part_pages.each_with_index do |take_part_page, index| %> + <% @content_item.take_part_pages.each_with_index do |take_part_page, index| %> <% if index % 3 == 0 && index != 0 %>
<% end %> <% if index % 3 == 0 %>
@@ -193,7 +181,7 @@ image_loading: "lazy", } %>
- <% if index == @take_part_pages.size-1 %> + <% if index == @content_item.take_part_pages.size-1 %> <% end %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 66b229bb7..9efe420c5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,8 +16,6 @@ get "/government/uploads/*path" => "asset_manager_redirect#show", format: false - get "/government/get-involved" => "get_involved#show" - get "/service-manual/search", to: redirect { |_, request| query = request.query_parameters.merge(filter_manual: "/service-manual").to_query diff --git a/test/controllers/get_involved_controller_test.rb b/test/controllers/get_involved_controller_test.rb deleted file mode 100644 index 0b0c78500..000000000 --- a/test/controllers/get_involved_controller_test.rb +++ /dev/null @@ -1,119 +0,0 @@ -require "test_helper" -require "gds_api/test_helpers/search" - -class GetInvolvedControllerTest < ActionController::TestCase - include GdsApi::TestHelpers::Search - include GdsApi::TestHelpers::ContentStore - - def setup - content_item_body = { - "document_type" => "get_involved", - "schema_name" => "get_involved", - "details" => {}, - "links" => { - "take_part_pages" => [ - { - "title" => "Take part page 1", - "base_path" => "/take-part-1", - "details" => { - "image" => {}, - }, - }, - { - "title" => "Take part page 2", - "base_path" => "/take-part-2", - "details" => { - "image" => {}, - }, - }, - ], - }, - } - - stub_content_store_has_item("/government/get-involved", content_item_body) - - no_results = { "results" => {}, "total" => 0, "start" => 0 } - stub_any_search.to_return("body" => no_results.to_json) - end - - test "returns a 200 response" do - get :show - assert_response :ok - end - - test "showing total number of open consultations" do - stub_search_query(query: hash_including(filter_content_store_document_type: "open_consultation"), - response: { "results" => [], "total" => 83 }) - - get :show - assert_select ".gem-c-big-number", /83.+Open consultations/m - end - - test "showing total number of closed consultations" do - stub_search_query(query: hash_including(filter_content_store_document_type: "closed_consultation"), - response: { "results" => [], "total" => 110 }) - - get :show - assert_select ".gem-c-big-number", /110.+Closed consultations/m - end - - test "showing the next closing consultation" do - Timecop.freeze do - title = "Next closing consultation on time zones" - stub_search_query(query: hash_including(filter_content_store_document_type: "open_consultation", - filter_end_date: "from: #{Time.zone.now.to_date}"), - response: { "results" => [consultation_result(title:)] }) - - get :show - assert_select ".gem-c-inset-text", /#{title}/ - end - end - - test "showing recently opened consultations" do - title = "Open consultation on time zones" - stub_search_query(query: hash_including(filter_content_store_document_type: "open_consultation"), - response: { "results" => [consultation_result(title:)] }) - - get :show - assert response.body.include?(title) - end - - test "showing recent consultation outcomes" do - title = "Consultation outcome on time zones" - stub_search_query(query: hash_including(filter_content_store_document_type: "consultation_outcome"), - response: { "results" => [consultation_result(title:)] }) - - get :show - assert response.body.include?(title) - end - - test "shows the take part pages" do - get :show - assert response.body.include?("Take part page 1") - assert response.body.include?("Take part page 2") - end - -private - - def stub_search_query(query:, response:) - stub_request(:get, /\A#{Plek.new.find('search-api')}\/search.json/) - .with(query:) - .to_return(body: response.to_json) - end - - def consultation_result(title: "Consulting on time zones") - { - "title" => title, - "public_timestamp" => "2022-02-14T00:00:00.000+01:00", - "end_date" => "2022-02-14T00:00:00.000+01:00", - "link" => "/consultation/link", - "organisations" => [{ - "slug" => "ministry-of-justice", - "link" => "/government/organisations/ministry-of-justice", - "title" => "Ministry of Justice", - "acronym" => "MoJ", - "organisation_state" => "live", - }], - } - end -end diff --git a/test/integration/get_involved_test.rb b/test/integration/get_involved_test.rb new file mode 100644 index 000000000..73d8167fe --- /dev/null +++ b/test/integration/get_involved_test.rb @@ -0,0 +1,60 @@ +require "test_helper" +require "gds_api/test_helpers/search" + +class GetInvolvedTest < ActionDispatch::IntegrationTest + include GdsApi::TestHelpers::Search + + setup do + stub_search_query(query: hash_including(filter_content_store_document_type: "open_consultation"), response: { "results" => [], "total" => 83 }) + stub_search_query(query: hash_including(filter_content_store_document_type: "closed_consultation"), response: { "results" => [], "total" => 110 }) + stub_search_query(query: hash_including(filter_content_store_document_type: "consultation_outcome"), response: { "results" => [consultation_result] }) + + setup_and_visit_content_item("get_involved") + end + + test "page has correct title" do + puts page.inspect + assert page.has_title?("Get involved - GOV.UK") + end + + test "includes the correct number of open consultations" do + assert page.has_selector?(".gem-c-big-number", text: /83.+Open consultations/m) + end + + test "includes the correct number of closed consultations" do + assert page.has_selector?(".gem-c-big-number", text: /110.+Closed consultations/m) + end + + test "includes the next closing consultation" do + assert page.has_text?("Consulting on time zones") + end + + test "shows the take part pages" do + assert page.has_text?("Volunteer") + assert page.has_text?("National Citizen Service") + end + +private + + def stub_search_query(query:, response:) + stub_request(:get, /\A#{Plek.new.find('search-api')}\/search.json/) + .with(query:) + .to_return(body: response.to_json) + end + + def consultation_result + { + "title" => "Consulting on time zones", + "public_timestamp" => "2022-02-14T00:00:00.000+01:00", + "end_date" => "2022-02-14T00:00:00.000+01:00", + "link" => "/consultation/link", + "organisations" => [{ + "slug" => "ministry-of-justice", + "link" => "/government/organisations/ministry-of-justice", + "title" => "Ministry of Justice", + "acronym" => "MoJ", + "organisation_state" => "live", + }], + } + end +end