diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73775bc3fa..a1763844fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,6 +97,8 @@ jobs: - name: Setup Postgres id: setup-postgres-graphql-direct-link-precedence-same-content-id uses: alphagov/govuk-infrastructure/.github/actions/setup-postgres@main + with: + POSTGRES_DB: postgres-graphql-link-precedence - name: Setup Redis uses: alphagov/govuk-infrastructure/.github/actions/setup-redis@main @@ -115,11 +117,17 @@ jobs: TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-direct-link-precedence-same-content-id.outputs.db-url }} run: bundle exec rails db:setup - - name: Run RSpec + - name: Prepare for parallel testing + env: + RAILS_ENV: test + TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-direct-link-precedence-same-content-id.outputs.db-url }} + run: bundle exec rake db:parallel:create db:parallel:prepare + + - name: Run RSpec in parallel env: RAILS_ENV: test TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-direct-link-precedence-same-content-id.outputs.db-url }} - run: bundle exec rspec spec/integration/graphql/link_expansion/direct_link_precedence_with_same_content_ids_spec.rb + run: bundle exec prspec spec/integration/graphql/link_expansion/direct_link_precedence_with_same_content_ids_spec.rb test-graphql-direct-link-precedence-different-content-id: name: "Test GraphQL direct link expansion precedence with different content IDs" @@ -128,6 +136,8 @@ jobs: - name: Setup Postgres id: setup-postgres-graphql-direct-link-precedence-different-content-id uses: alphagov/govuk-infrastructure/.github/actions/setup-postgres@main + with: + POSTGRES_DB: postgres-graphql-link-precedence - name: Setup Redis uses: alphagov/govuk-infrastructure/.github/actions/setup-redis@main @@ -146,11 +156,17 @@ jobs: TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-direct-link-precedence-different-content-id.outputs.db-url }} run: bundle exec rails db:setup - - name: Run RSpec + - name: Prepare for parallel testing + env: + RAILS_ENV: test + TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-direct-link-precedence-different-content-id.outputs.db-url }} + run: bundle exec rake db:parallel:create db:parallel:prepare + + - name: Run RSpec in parallel env: RAILS_ENV: test TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-direct-link-precedence-different-content-id.outputs.db-url }} - run: bundle exec rspec spec/integration/graphql/link_expansion/direct_link_precedence_with_different_content_ids_spec.rb + run: bundle exec prspec spec/integration/graphql/link_expansion/direct_link_precedence_with_different_content_ids_spec.rb test-graphql-reverse-link-precedence-same-content-id: name: "Test GraphQL reverse link expansion precedence with same content ID" @@ -159,6 +175,8 @@ jobs: - name: Setup Postgres id: setup-postgres-graphql-reverse-link-precedence-same-content-id uses: alphagov/govuk-infrastructure/.github/actions/setup-postgres@main + with: + POSTGRES_DB: postgres-graphql-link-precedence - name: Setup Redis uses: alphagov/govuk-infrastructure/.github/actions/setup-redis@main @@ -177,11 +195,17 @@ jobs: TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-reverse-link-precedence-same-content-id.outputs.db-url }} run: bundle exec rails db:setup - - name: Run RSpec + - name: Prepare for parallel testing + env: + RAILS_ENV: test + TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-reverse-link-precedence-same-content-id.outputs.db-url }} + run: bundle exec rake db:parallel:create db:parallel:prepare + + - name: Run RSpec in parallel env: RAILS_ENV: test TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-reverse-link-precedence-same-content-id.outputs.db-url }} - run: bundle exec rspec spec/integration/graphql/link_expansion/reverse_link_precedence_with_same_content_ids_spec.rb + run: bundle exec prspec spec/integration/graphql/link_expansion/reverse_link_precedence_with_same_content_ids_spec.rb test-graphql-reverse-link-precedence-different-content-id: name: "Test GraphQL reverse link expansion precedence with different content IDs" @@ -190,6 +214,8 @@ jobs: - name: Setup Postgres id: setup-postgres-graphql-reverse-link-precedence-different-content-id uses: alphagov/govuk-infrastructure/.github/actions/setup-postgres@main + with: + POSTGRES_DB: postgres-graphql-link-precedence - name: Setup Redis uses: alphagov/govuk-infrastructure/.github/actions/setup-redis@main @@ -208,11 +234,17 @@ jobs: TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-reverse-link-precedence-different-content-id.outputs.db-url }} run: bundle exec rails db:setup - - name: Run RSpec + - name: Prepare for parallel testing + env: + RAILS_ENV: test + TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-reverse-link-precedence-different-content-id.outputs.db-url }} + run: bundle exec rake db:parallel:create db:parallel:prepare + + - name: Run RSpec in parallel env: RAILS_ENV: test TEST_DATABASE_URL: ${{ steps.setup-postgres-graphql-reverse-link-precedence-different-content-id.outputs.db-url }} - run: bundle exec rspec spec/integration/graphql/link_expansion/reverse_link_precedence_with_different_content_ids_spec.rb + run: bundle exec prspec spec/integration/graphql/link_expansion/reverse_link_precedence_with_different_content_ids_spec.rb check-schemas-build: name: Check content schemas are built diff --git a/Gemfile b/Gemfile index 97f6a298ee..acd5b04258 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,7 @@ group :development, :test do gem "govuk_test" gem "pact", require: false gem "pact_broker-client", require: false + gem "parallel_rspec" gem "rspec-rails" gem "rubocop-govuk", require: false gem "simplecov", require: false diff --git a/Gemfile.lock b/Gemfile.lock index 61d1d8f627..a1ce07b737 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -615,6 +615,9 @@ GEM term-ansicolor (~> 1.7) thor (>= 0.20, < 2.0) parallel (1.27.0) + parallel_rspec (3.0.0) + rake (> 10.0) + rspec parser (3.3.10.1) ast (~> 2.4.1) racc @@ -935,6 +938,7 @@ DEPENDENCIES oj pact pact_broker-client + parallel_rspec pg plek prometheus-client diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index 03ea2f25c7..34a71c52fa 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -11,11 +11,52 @@ class GraphqlController < ApplicationController DEFAULT_TTL = ENV.fetch("DEFAULT_TTL", 5.minutes).to_i.seconds MINIMUM_TTL = [DEFAULT_TTL, 5.seconds].min + def draft_content + execute_in_read_replica do + begin + encoded_base_path = Addressable::URI.encode("/#{params[:base_path]}") + edition = EditionFinderService.new(encoded_base_path, with_drafts: true).find + set_cache_headers(edition) + return head :not_found unless edition + + if edition.base_path != encoded_base_path + return redirect_to graphql_draft_content_path(base_path: edition.base_path.gsub(/^\//, "")), status: :see_other + end + + begin + query = File.read(Rails.root.join("app/graphql/queries/#{edition.schema_name}.graphql")) + rescue Errno::ENOENT + return head :not_found + end + + result = PublishingApiSchema.execute(query, variables: { base_path: encoded_base_path, with_drafts: true }).to_hash + report_result(result) + + content_item = GraphqlContentItemService.for_edition(edition).process(result) + + http_status = if content_item["schema_name"] == "gone" && (content_item["details"].nil? || content_item["details"].values.reject(&:blank?).empty?) + 410 + else + 200 + end + + render json: content_item, status: http_status + end + rescue Addressable::URI::InvalidURIError + Rails.logger.warn "Can't encode request_path '#{params[:base_path]}'" + return head :bad_request + rescue StandardError => e + raise e unless Rails.env.development? + + handle_error_in_development(e) + end + end + def live_content execute_in_read_replica do begin encoded_base_path = Addressable::URI.encode("/#{params[:base_path]}") - edition = EditionFinderService.new(encoded_base_path, "live").find + edition = EditionFinderService.new(encoded_base_path).find set_cache_headers(edition) return head :not_found unless edition diff --git a/app/graphql/queries/answer.graphql b/app/graphql/queries/answer.graphql index f74b9decba..d60832a8d9 100644 --- a/app/graphql/queries/answer.graphql +++ b/app/graphql/queries/answer.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query answer($base_path: String!) { - edition(base_path: $base_path) { +query answer($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/calendar.graphql b/app/graphql/queries/calendar.graphql index b6cd27ecb6..a60eb37f42 100644 --- a/app/graphql/queries/calendar.graphql +++ b/app/graphql/queries/calendar.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query calendar($base_path: String!) { - edition(base_path: $base_path) { +query calendar($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/call_for_evidence.graphql b/app/graphql/queries/call_for_evidence.graphql index 178b90e0c1..17f9b5ebf5 100644 --- a/app/graphql/queries/call_for_evidence.graphql +++ b/app/graphql/queries/call_for_evidence.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query call_for_evidence($base_path: String!) { - edition(base_path: $base_path) { +query call_for_evidence($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/case_study.graphql b/app/graphql/queries/case_study.graphql index ceb40deea5..6712f7f41f 100644 --- a/app/graphql/queries/case_study.graphql +++ b/app/graphql/queries/case_study.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query case_study($base_path: String!) { - edition(base_path: $base_path) { +query case_study($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/completed_transaction.graphql b/app/graphql/queries/completed_transaction.graphql index 1a83ec4ce9..b87b340d9c 100644 --- a/app/graphql/queries/completed_transaction.graphql +++ b/app/graphql/queries/completed_transaction.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query completed_transaction($base_path: String!) { - edition(base_path: $base_path) { +query completed_transaction($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/consultation.graphql b/app/graphql/queries/consultation.graphql index 015d0b9795..76aaacc32c 100644 --- a/app/graphql/queries/consultation.graphql +++ b/app/graphql/queries/consultation.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query consultation($base_path: String!) { - edition(base_path: $base_path) { +query consultation($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/coronavirus_landing_page.graphql b/app/graphql/queries/coronavirus_landing_page.graphql index f0559d2f22..c92fef73df 100644 --- a/app/graphql/queries/coronavirus_landing_page.graphql +++ b/app/graphql/queries/coronavirus_landing_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query coronavirus_landing_page($base_path: String!) { - edition(base_path: $base_path) { +query coronavirus_landing_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/corporate_information_page.graphql b/app/graphql/queries/corporate_information_page.graphql index cd20efea5d..5693664cc1 100644 --- a/app/graphql/queries/corporate_information_page.graphql +++ b/app/graphql/queries/corporate_information_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query corporate_information_page($base_path: String!) { - edition(base_path: $base_path) { +query corporate_information_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/detailed_guide.graphql b/app/graphql/queries/detailed_guide.graphql index 339f03b827..f5c94dff3f 100644 --- a/app/graphql/queries/detailed_guide.graphql +++ b/app/graphql/queries/detailed_guide.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query detailed_guide($base_path: String!) { - edition(base_path: $base_path) { +query detailed_guide($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/document_collection.graphql b/app/graphql/queries/document_collection.graphql index 0c08944972..5daa75d796 100644 --- a/app/graphql/queries/document_collection.graphql +++ b/app/graphql/queries/document_collection.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query document_collection($base_path: String!) { - edition(base_path: $base_path) { +query document_collection($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/email_alert_signup.graphql b/app/graphql/queries/email_alert_signup.graphql index bf56337849..69d8f144f5 100644 --- a/app/graphql/queries/email_alert_signup.graphql +++ b/app/graphql/queries/email_alert_signup.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query email_alert_signup($base_path: String!) { - edition(base_path: $base_path) { +query email_alert_signup($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/embassies_index.graphql b/app/graphql/queries/embassies_index.graphql index f0170a216c..c655df52af 100644 --- a/app/graphql/queries/embassies_index.graphql +++ b/app/graphql/queries/embassies_index.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query embassies_index($base_path: String!) { - edition(base_path: $base_path) { +query embassies_index($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/fatality_notice.graphql b/app/graphql/queries/fatality_notice.graphql index 89ce0b4870..42aefa75da 100644 --- a/app/graphql/queries/fatality_notice.graphql +++ b/app/graphql/queries/fatality_notice.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query fatality_notice($base_path: String!) { - edition(base_path: $base_path) { +query fatality_notice($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/field_of_operation.graphql b/app/graphql/queries/field_of_operation.graphql index e67bd29eec..c3c8801b90 100644 --- a/app/graphql/queries/field_of_operation.graphql +++ b/app/graphql/queries/field_of_operation.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query field_of_operation($base_path: String!) { - edition(base_path: $base_path) { +query field_of_operation($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/fields_of_operation.graphql b/app/graphql/queries/fields_of_operation.graphql index b2d1821c12..e498ca3f05 100644 --- a/app/graphql/queries/fields_of_operation.graphql +++ b/app/graphql/queries/fields_of_operation.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query fields_of_operation($base_path: String!) { - edition(base_path: $base_path) { +query fields_of_operation($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/finder.graphql b/app/graphql/queries/finder.graphql index 914395cc72..8dc8f28c95 100644 --- a/app/graphql/queries/finder.graphql +++ b/app/graphql/queries/finder.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query finder($base_path: String!) { - edition(base_path: $base_path) { +query finder($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/finder_email_signup.graphql b/app/graphql/queries/finder_email_signup.graphql index 04b8d704e8..224a1f34d2 100644 --- a/app/graphql/queries/finder_email_signup.graphql +++ b/app/graphql/queries/finder_email_signup.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query finder_email_signup($base_path: String!) { - edition(base_path: $base_path) { +query finder_email_signup($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/generic.graphql b/app/graphql/queries/generic.graphql index e7cc862226..cff68bbfbf 100644 --- a/app/graphql/queries/generic.graphql +++ b/app/graphql/queries/generic.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query generic($base_path: String!) { - edition(base_path: $base_path) { +query generic($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/government.graphql b/app/graphql/queries/government.graphql index 2a66645926..3affb97d4c 100644 --- a/app/graphql/queries/government.graphql +++ b/app/graphql/queries/government.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query government($base_path: String!) { - edition(base_path: $base_path) { +query government($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/guide.graphql b/app/graphql/queries/guide.graphql index a77e7fe6d8..c92dc18fbe 100644 --- a/app/graphql/queries/guide.graphql +++ b/app/graphql/queries/guide.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query guide($base_path: String!) { - edition(base_path: $base_path) { +query guide($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/help_page.graphql b/app/graphql/queries/help_page.graphql index e6d9332ffb..563b65eda3 100644 --- a/app/graphql/queries/help_page.graphql +++ b/app/graphql/queries/help_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query help_page($base_path: String!) { - edition(base_path: $base_path) { +query help_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/historic_appointment.graphql b/app/graphql/queries/historic_appointment.graphql index 041c79b2b4..76a6428386 100644 --- a/app/graphql/queries/historic_appointment.graphql +++ b/app/graphql/queries/historic_appointment.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query historic_appointment($base_path: String!) { - edition(base_path: $base_path) { +query historic_appointment($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/historic_appointments.graphql b/app/graphql/queries/historic_appointments.graphql index 0d676ecff4..f04de9374c 100644 --- a/app/graphql/queries/historic_appointments.graphql +++ b/app/graphql/queries/historic_appointments.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query historic_appointments($base_path: String!) { - edition(base_path: $base_path) { +query historic_appointments($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/history.graphql b/app/graphql/queries/history.graphql index 820bd34c71..00b111bf6c 100644 --- a/app/graphql/queries/history.graphql +++ b/app/graphql/queries/history.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query history($base_path: String!) { - edition(base_path: $base_path) { +query history($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/hmrc_manual.graphql b/app/graphql/queries/hmrc_manual.graphql index 9fff912130..44b27ffd54 100644 --- a/app/graphql/queries/hmrc_manual.graphql +++ b/app/graphql/queries/hmrc_manual.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query hmrc_manual($base_path: String!) { - edition(base_path: $base_path) { +query hmrc_manual($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/hmrc_manual_section.graphql b/app/graphql/queries/hmrc_manual_section.graphql index 141f59a892..24433ec7c1 100644 --- a/app/graphql/queries/hmrc_manual_section.graphql +++ b/app/graphql/queries/hmrc_manual_section.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query hmrc_manual_section($base_path: String!) { - edition(base_path: $base_path) { +query hmrc_manual_section($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/homepage.graphql b/app/graphql/queries/homepage.graphql index 7521938b48..7c14f50416 100644 --- a/app/graphql/queries/homepage.graphql +++ b/app/graphql/queries/homepage.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query homepage($base_path: String!) { - edition(base_path: $base_path) { +query homepage($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/how_government_works.graphql b/app/graphql/queries/how_government_works.graphql index 3666e2777a..5a3197e5e9 100644 --- a/app/graphql/queries/how_government_works.graphql +++ b/app/graphql/queries/how_government_works.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query how_government_works($base_path: String!) { - edition(base_path: $base_path) { +query how_government_works($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/html_publication.graphql b/app/graphql/queries/html_publication.graphql index e88226dcb1..1f7508b92d 100644 --- a/app/graphql/queries/html_publication.graphql +++ b/app/graphql/queries/html_publication.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query html_publication($base_path: String!) { - edition(base_path: $base_path) { +query html_publication($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/landing_page.graphql b/app/graphql/queries/landing_page.graphql index 6cea21fee4..0fa76d959a 100644 --- a/app/graphql/queries/landing_page.graphql +++ b/app/graphql/queries/landing_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query landing_page($base_path: String!) { - edition(base_path: $base_path) { +query landing_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/local_transaction.graphql b/app/graphql/queries/local_transaction.graphql index a21cd1c286..375b6d52ae 100644 --- a/app/graphql/queries/local_transaction.graphql +++ b/app/graphql/queries/local_transaction.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query local_transaction($base_path: String!) { - edition(base_path: $base_path) { +query local_transaction($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/mainstream_browse_page.graphql b/app/graphql/queries/mainstream_browse_page.graphql index f3af0fa5ae..1e813ed700 100644 --- a/app/graphql/queries/mainstream_browse_page.graphql +++ b/app/graphql/queries/mainstream_browse_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query mainstream_browse_page($base_path: String!) { - edition(base_path: $base_path) { +query mainstream_browse_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/manual.graphql b/app/graphql/queries/manual.graphql index 4c2286972d..5b9831b526 100644 --- a/app/graphql/queries/manual.graphql +++ b/app/graphql/queries/manual.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query manual($base_path: String!) { - edition(base_path: $base_path) { +query manual($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/manual_section.graphql b/app/graphql/queries/manual_section.graphql index 9f00614683..cfdd6cf0db 100644 --- a/app/graphql/queries/manual_section.graphql +++ b/app/graphql/queries/manual_section.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query manual_section($base_path: String!) { - edition(base_path: $base_path) { +query manual_section($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/ministers_index.graphql b/app/graphql/queries/ministers_index.graphql index a30e5b1953..6b7c60737e 100644 --- a/app/graphql/queries/ministers_index.graphql +++ b/app/graphql/queries/ministers_index.graphql @@ -1,5 +1,5 @@ -query ministers_index($base_path: String!) { - edition(base_path: $base_path) { +query ministers_index($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on MinistersIndex { base_path content_id diff --git a/app/graphql/queries/news_article.graphql b/app/graphql/queries/news_article.graphql index 205728bc78..a42bcf9d37 100644 --- a/app/graphql/queries/news_article.graphql +++ b/app/graphql/queries/news_article.graphql @@ -1,5 +1,5 @@ -query news_article($base_path: String!) { - edition(base_path: $base_path, content_store: "live") { +query news_article($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { base_path content_id diff --git a/app/graphql/queries/organisation.graphql b/app/graphql/queries/organisation.graphql index bf59951823..0faa7b8b66 100644 --- a/app/graphql/queries/organisation.graphql +++ b/app/graphql/queries/organisation.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query organisation($base_path: String!) { - edition(base_path: $base_path) { +query organisation($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/organisations_homepage.graphql b/app/graphql/queries/organisations_homepage.graphql index 08de2b8479..d733ca7e72 100644 --- a/app/graphql/queries/organisations_homepage.graphql +++ b/app/graphql/queries/organisations_homepage.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query organisations_homepage($base_path: String!) { - edition(base_path: $base_path) { +query organisations_homepage($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/person.graphql b/app/graphql/queries/person.graphql index 5687877d93..4e515fdcf8 100644 --- a/app/graphql/queries/person.graphql +++ b/app/graphql/queries/person.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query person($base_path: String!) { - edition(base_path: $base_path) { +query person($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/place.graphql b/app/graphql/queries/place.graphql index 044f32f639..977034f0f1 100644 --- a/app/graphql/queries/place.graphql +++ b/app/graphql/queries/place.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query place($base_path: String!) { - edition(base_path: $base_path) { +query place($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/publication.graphql b/app/graphql/queries/publication.graphql index 9224b44fe4..5f4ace70d4 100644 --- a/app/graphql/queries/publication.graphql +++ b/app/graphql/queries/publication.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query publication($base_path: String!) { - edition(base_path: $base_path) { +query publication($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/role.graphql b/app/graphql/queries/role.graphql index 06bfee3854..b4eaeb28d3 100644 --- a/app/graphql/queries/role.graphql +++ b/app/graphql/queries/role.graphql @@ -1,5 +1,5 @@ -query role($base_path: String!) { - edition(base_path: $base_path) { +query role($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { base_path content_id diff --git a/app/graphql/queries/service_manual_guide.graphql b/app/graphql/queries/service_manual_guide.graphql index bc78b6a399..ba4a803f2b 100644 --- a/app/graphql/queries/service_manual_guide.graphql +++ b/app/graphql/queries/service_manual_guide.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query service_manual_guide($base_path: String!) { - edition(base_path: $base_path) { +query service_manual_guide($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/service_manual_homepage.graphql b/app/graphql/queries/service_manual_homepage.graphql index 5bcf79955b..6f58cbd221 100644 --- a/app/graphql/queries/service_manual_homepage.graphql +++ b/app/graphql/queries/service_manual_homepage.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query service_manual_homepage($base_path: String!) { - edition(base_path: $base_path) { +query service_manual_homepage($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/service_manual_service_standard.graphql b/app/graphql/queries/service_manual_service_standard.graphql index cf18646605..1a89443125 100644 --- a/app/graphql/queries/service_manual_service_standard.graphql +++ b/app/graphql/queries/service_manual_service_standard.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query service_manual_service_standard($base_path: String!) { - edition(base_path: $base_path) { +query service_manual_service_standard($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/service_manual_service_toolkit.graphql b/app/graphql/queries/service_manual_service_toolkit.graphql index c91b6978c6..d29351c152 100644 --- a/app/graphql/queries/service_manual_service_toolkit.graphql +++ b/app/graphql/queries/service_manual_service_toolkit.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query service_manual_service_toolkit($base_path: String!) { - edition(base_path: $base_path) { +query service_manual_service_toolkit($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/service_manual_topic.graphql b/app/graphql/queries/service_manual_topic.graphql index 5c19d1c2b0..979cc5e371 100644 --- a/app/graphql/queries/service_manual_topic.graphql +++ b/app/graphql/queries/service_manual_topic.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query service_manual_topic($base_path: String!) { - edition(base_path: $base_path) { +query service_manual_topic($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/simple_smart_answer.graphql b/app/graphql/queries/simple_smart_answer.graphql index 8f58fcaa3c..d35d1ad38d 100644 --- a/app/graphql/queries/simple_smart_answer.graphql +++ b/app/graphql/queries/simple_smart_answer.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query simple_smart_answer($base_path: String!) { - edition(base_path: $base_path) { +query simple_smart_answer($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/smart_answer.graphql b/app/graphql/queries/smart_answer.graphql index 5b5dafd2e9..cd023a70e2 100644 --- a/app/graphql/queries/smart_answer.graphql +++ b/app/graphql/queries/smart_answer.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query smart_answer($base_path: String!) { - edition(base_path: $base_path) { +query smart_answer($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/special_route.graphql b/app/graphql/queries/special_route.graphql index 0697dc2e52..2f685f3c25 100644 --- a/app/graphql/queries/special_route.graphql +++ b/app/graphql/queries/special_route.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query special_route($base_path: String!) { - edition(base_path: $base_path) { +query special_route($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/specialist_document.graphql b/app/graphql/queries/specialist_document.graphql index b641135a20..84f643861a 100644 --- a/app/graphql/queries/specialist_document.graphql +++ b/app/graphql/queries/specialist_document.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query specialist_document($base_path: String!) { - edition(base_path: $base_path) { +query specialist_document($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/speech.graphql b/app/graphql/queries/speech.graphql index 75bd371155..548a016982 100644 --- a/app/graphql/queries/speech.graphql +++ b/app/graphql/queries/speech.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query speech($base_path: String!) { - edition(base_path: $base_path) { +query speech($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/statistical_data_set.graphql b/app/graphql/queries/statistical_data_set.graphql index f9f3910068..93bfd94eb2 100644 --- a/app/graphql/queries/statistical_data_set.graphql +++ b/app/graphql/queries/statistical_data_set.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query statistical_data_set($base_path: String!) { - edition(base_path: $base_path) { +query statistical_data_set($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/statistics_announcement.graphql b/app/graphql/queries/statistics_announcement.graphql index e62261dca6..73bf290e52 100644 --- a/app/graphql/queries/statistics_announcement.graphql +++ b/app/graphql/queries/statistics_announcement.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query statistics_announcement($base_path: String!) { - edition(base_path: $base_path) { +query statistics_announcement($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/step_by_step_nav.graphql b/app/graphql/queries/step_by_step_nav.graphql index c63da15376..663fe893f8 100644 --- a/app/graphql/queries/step_by_step_nav.graphql +++ b/app/graphql/queries/step_by_step_nav.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query step_by_step_nav($base_path: String!) { - edition(base_path: $base_path) { +query step_by_step_nav($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/taxon.graphql b/app/graphql/queries/taxon.graphql index cc9131e996..1cdf741773 100644 --- a/app/graphql/queries/taxon.graphql +++ b/app/graphql/queries/taxon.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query taxon($base_path: String!) { - edition(base_path: $base_path) { +query taxon($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/topical_event.graphql b/app/graphql/queries/topical_event.graphql index 3cd577cb16..e1943a84c3 100644 --- a/app/graphql/queries/topical_event.graphql +++ b/app/graphql/queries/topical_event.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query topical_event($base_path: String!) { - edition(base_path: $base_path) { +query topical_event($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/topical_event_about_page.graphql b/app/graphql/queries/topical_event_about_page.graphql index 72ffb42bc2..f436fc4cbf 100644 --- a/app/graphql/queries/topical_event_about_page.graphql +++ b/app/graphql/queries/topical_event_about_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query topical_event_about_page($base_path: String!) { - edition(base_path: $base_path) { +query topical_event_about_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/transaction.graphql b/app/graphql/queries/transaction.graphql index 8e7d15dfca..0732d84811 100644 --- a/app/graphql/queries/transaction.graphql +++ b/app/graphql/queries/transaction.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query transaction($base_path: String!) { - edition(base_path: $base_path) { +query transaction($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/travel_advice.graphql b/app/graphql/queries/travel_advice.graphql index 5160577aee..7d1737d6ae 100644 --- a/app/graphql/queries/travel_advice.graphql +++ b/app/graphql/queries/travel_advice.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query travel_advice($base_path: String!) { - edition(base_path: $base_path) { +query travel_advice($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/travel_advice_index.graphql b/app/graphql/queries/travel_advice_index.graphql index e13cfff830..7015b19325 100644 --- a/app/graphql/queries/travel_advice_index.graphql +++ b/app/graphql/queries/travel_advice_index.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query travel_advice_index($base_path: String!) { - edition(base_path: $base_path) { +query travel_advice_index($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/working_group.graphql b/app/graphql/queries/working_group.graphql index 6a0876ef3b..743498de72 100644 --- a/app/graphql/queries/working_group.graphql +++ b/app/graphql/queries/working_group.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query working_group($base_path: String!) { - edition(base_path: $base_path) { +query working_group($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/world_index.graphql b/app/graphql/queries/world_index.graphql index 89e2d47fd0..ad9e2b7e6e 100644 --- a/app/graphql/queries/world_index.graphql +++ b/app/graphql/queries/world_index.graphql @@ -1,5 +1,5 @@ -query world_index($base_path: String!) { - edition(base_path: $base_path) { +query world_index($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { base_path content_id diff --git a/app/graphql/queries/world_location_news.graphql b/app/graphql/queries/world_location_news.graphql index 2e6ed0591a..783a84675b 100644 --- a/app/graphql/queries/world_location_news.graphql +++ b/app/graphql/queries/world_location_news.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query world_location_news($base_path: String!) { - edition(base_path: $base_path) { +query world_location_news($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/worldwide_corporate_information_page.graphql b/app/graphql/queries/worldwide_corporate_information_page.graphql index f7d5bfcf34..6b5297bab6 100644 --- a/app/graphql/queries/worldwide_corporate_information_page.graphql +++ b/app/graphql/queries/worldwide_corporate_information_page.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query worldwide_corporate_information_page($base_path: String!) { - edition(base_path: $base_path) { +query worldwide_corporate_information_page($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/worldwide_office.graphql b/app/graphql/queries/worldwide_office.graphql index 1245647fe8..c268faabef 100644 --- a/app/graphql/queries/worldwide_office.graphql +++ b/app/graphql/queries/worldwide_office.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query worldwide_office($base_path: String!) { - edition(base_path: $base_path) { +query worldwide_office($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/queries/worldwide_organisation.graphql b/app/graphql/queries/worldwide_organisation.graphql index 0aea615548..4afb54e535 100644 --- a/app/graphql/queries/worldwide_organisation.graphql +++ b/app/graphql/queries/worldwide_organisation.graphql @@ -12,8 +12,8 @@ fragment defaultFields on Edition { web_url } -query worldwide_organisation($base_path: String!) { - edition(base_path: $base_path) { +query worldwide_organisation($base_path: String!, $with_drafts: Boolean) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { analytics_identifier base_path diff --git a/app/graphql/sources/linked_to_editions_source.rb b/app/graphql/sources/linked_to_editions_source.rb index d6a0b85c99..0e11578c78 100644 --- a/app/graphql/sources/linked_to_editions_source.rb +++ b/app/graphql/sources/linked_to_editions_source.rb @@ -3,10 +3,10 @@ class LinkedToEditionsSource < GraphQL::Dataloader::Source SQL = File.read(Rails.root.join("app/graphql/sources/queries/linked_to_editions.sql")) # rubocop:disable Lint/MissingSuper - def initialize(content_store:, locale:) - @content_store = content_store.to_sym + def initialize(locale:, with_drafts: false) @primary_locale = locale @secondary_locale = Edition::DEFAULT_LOCALE + @with_drafts = with_drafts end # rubocop:enable Lint/MissingSuper @@ -23,7 +23,7 @@ def fetch(editions_and_link_types) query_input_count: query_input.count, primary_locale: @primary_locale, secondary_locale: @secondary_locale, - content_store: @content_store, + state_unless_withdrawn: @with_drafts ? %i[draft published] : %i[published], unpublished_link_types: Link::PERMITTED_UNPUBLISHED_LINK_TYPES, non_renderable_formats: Edition::NON_RENDERABLE_FORMATS, } diff --git a/app/graphql/sources/queries/linked_to_editions.sql b/app/graphql/sources/queries/linked_to_editions.sql index ca6aa07573..6f7773b13a 100644 --- a/app/graphql/sources/queries/linked_to_editions.sql +++ b/app/graphql/sources/queries/linked_to_editions.sql @@ -28,13 +28,14 @@ edition_linked_editions AS ( INNER JOIN documents AS source_documents ON source_editions.document_id = source_documents.id LEFT JOIN unpublishings ON editions.id = unpublishings.edition_id WHERE - editions.content_store =:content_store - AND documents.locale IN (:primary_locale,:secondary_locale) + documents.locale IN (:primary_locale,:secondary_locale) AND editions.document_type NOT IN (:non_renderable_formats) AND ( - editions.state != 'unpublished' + editions.state IN (:state_unless_withdrawn) OR ( + editions.state = 'unpublished' + AND links.link_type IN (:unpublished_link_types) AND unpublishings.type = 'withdrawal' @@ -43,9 +44,10 @@ edition_linked_editions AS ( ORDER BY links.id ASC, CASE editions.state - WHEN 'published' THEN 0 - WHEN 'unpublished' THEN 1 - ELSE 2 + WHEN 'draft' THEN 0 + WHEN 'published' THEN 1 + WHEN 'unpublished' THEN 2 + ELSE 3 END, is_primary_locale DESC ), @@ -68,13 +70,14 @@ link_set_linked_editions AS ( ON links.link_set_content_id = query_input.content_id AND links.link_type = query_input.link_type LEFT JOIN unpublishings ON editions.id = unpublishings.edition_id WHERE - editions.content_store =:content_store - AND documents.locale IN (:primary_locale,:secondary_locale) + documents.locale IN (:primary_locale,:secondary_locale) AND editions.document_type NOT IN (:non_renderable_formats) AND ( - editions.state != 'unpublished' + editions.state IN (:state_unless_withdrawn) OR ( + editions.state = 'unpublished' + AND links.link_type IN (:unpublished_link_types) AND unpublishings.type = 'withdrawal' @@ -90,9 +93,10 @@ link_set_linked_editions AS ( ORDER BY links.id ASC, CASE editions.state - WHEN 'published' THEN 0 - WHEN 'unpublished' THEN 1 - ELSE 2 + WHEN 'draft' THEN 0 + WHEN 'published' THEN 1 + WHEN 'unpublished' THEN 2 + ELSE 3 END, is_primary_locale DESC ) diff --git a/app/graphql/sources/queries/reverse_linked_to_editions.sql b/app/graphql/sources/queries/reverse_linked_to_editions.sql index 1633010891..77898be337 100644 --- a/app/graphql/sources/queries/reverse_linked_to_editions.sql +++ b/app/graphql/sources/queries/reverse_linked_to_editions.sql @@ -25,13 +25,14 @@ edition_linked_editions AS ( INNER JOIN query_input ON links.target_content_id = query_input.content_id AND links.link_type = query_input.link_type LEFT JOIN unpublishings ON editions.id = unpublishings.edition_id WHERE - editions.content_store =:content_store - AND documents.locale =:primary_locale + documents.locale =:primary_locale AND editions.document_type NOT IN (:non_renderable_formats) AND ( - editions.state != 'unpublished' + editions.state IN (:state_unless_withdrawn) OR ( + editions.state = 'unpublished' + AND links.link_type IN (:unpublished_link_types) AND unpublishings.type = 'withdrawal' @@ -55,13 +56,14 @@ link_set_linked_editions AS ( INNER JOIN query_input ON links.target_content_id = query_input.content_id AND links.link_type = query_input.link_type LEFT JOIN unpublishings ON editions.id = unpublishings.edition_id WHERE - editions.content_store =:content_store - AND documents.locale IN (:primary_locale,:secondary_locale) + documents.locale IN (:primary_locale,:secondary_locale) AND editions.document_type NOT IN (:non_renderable_formats) AND ( - editions.state != 'unpublished' + editions.state IN (:state_unless_withdrawn) OR ( + editions.state = 'unpublished' + AND links.link_type IN (:unpublished_link_types) AND unpublishings.type = 'withdrawal' @@ -86,9 +88,10 @@ SELECT editions.* FROM ( content_id ASC, target_content_id ASC, CASE state - WHEN 'published' THEN 0 - WHEN 'unpublished' THEN 1 - ELSE 2 + WHEN 'draft' THEN 0 + WHEN 'published' THEN 1 + WHEN 'unpublished' THEN 2 + ELSE 3 END, is_primary_locale DESC ) AS editions diff --git a/app/graphql/sources/reverse_linked_to_editions_source.rb b/app/graphql/sources/reverse_linked_to_editions_source.rb index 2ff9177811..74bc17a230 100644 --- a/app/graphql/sources/reverse_linked_to_editions_source.rb +++ b/app/graphql/sources/reverse_linked_to_editions_source.rb @@ -3,10 +3,10 @@ class ReverseLinkedToEditionsSource < GraphQL::Dataloader::Source SQL = File.read(Rails.root.join("app/graphql/sources/queries/reverse_linked_to_editions.sql")) # rubocop:disable Lint/MissingSuper - def initialize(content_store:, locale:) - @content_store = content_store.to_sym + def initialize(locale:, with_drafts: false) @primary_locale = locale @secondary_locale = Edition::DEFAULT_LOCALE + @with_drafts = with_drafts end # rubocop:enable Lint/MissingSuper @@ -24,7 +24,7 @@ def fetch(editions_and_link_types) query_input_count: query_input.count, secondary_locale: @secondary_locale, primary_locale: @primary_locale, - content_store: @content_store, + state_unless_withdrawn: @with_drafts ? %i[draft published] : %i[published], unpublished_link_types: Link::PERMITTED_UNPUBLISHED_LINK_TYPES, non_renderable_formats: Edition::NON_RENDERABLE_FORMATS, } diff --git a/app/graphql/types/base_object.rb b/app/graphql/types/base_object.rb index 7f8e86180f..7337e02c42 100644 --- a/app/graphql/types/base_object.rb +++ b/app/graphql/types/base_object.rb @@ -12,7 +12,7 @@ def self.links_field(link_type, graphql_field_type) define_method(link_type.to_sym) do dataloader.with( Sources::LinkedToEditionsSource, - content_store: object.content_store, + with_drafts: context[:with_drafts], locale: context[:root_edition].locale, ) .load([object, link_type.to_s]) @@ -25,7 +25,7 @@ def self.reverse_links_field(field_name, link_type, graphql_field_type) define_method(field_name.to_sym) do dataloader.with( Sources::ReverseLinkedToEditionsSource, - content_store: object.content_store, + with_drafts: context[:with_drafts], locale: context[:root_edition].locale, ) .load([object, link_type.to_s]) diff --git a/app/graphql/types/edition_type.rb b/app/graphql/types/edition_type.rb index 6a6d9a0e96..4b85042a90 100644 --- a/app/graphql/types/edition_type.rb +++ b/app/graphql/types/edition_type.rb @@ -103,14 +103,14 @@ def role_appointments if %w[role ministerial_role].include?(object.document_type) dataloader.with( Sources::ReverseLinkedToEditionsSource, - content_store: object.content_store, + with_drafts: context[:with_drafts], locale: context[:root_edition].locale, ) .load([object, "role"]) else dataloader.with( Sources::ReverseLinkedToEditionsSource, - content_store: object.content_store, + with_drafts: context[:with_drafts], locale: context[:root_edition].locale, ) .load([object, "person"]) @@ -390,13 +390,13 @@ class Details < Types::BaseObject field :details_json, GraphQL::Types::JSON field :document_type, String field :ended_on, Types::ContentApiDatetime - field :first_published_at, Types::ContentApiDatetime, null: false + field :first_published_at, Types::ContentApiDatetime field :iso2, String field :links, EditionLinks, method: :itself field :locale, String, null: false field :name, String, null: false field :phase, String, null: false - field :public_updated_at, Types::ContentApiDatetime, null: false + field :public_updated_at, Types::ContentApiDatetime field :publishing_app, String field :publishing_request_id, String field :publishing_scheduled_at, Types::ContentApiDatetime diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 566e5d41ae..4836ce7863 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -4,14 +4,31 @@ module Types class QueryType < Types::BaseObject field :edition, EditionTypeOrSubtype, description: "An edition or one of its subtypes" do argument :base_path, String - argument :content_store, String, required: false, default_value: "live" + argument :with_drafts, Boolean, required: false, default_value: false end - def edition(base_path:, content_store:) + def edition(base_path:, with_drafts:) + content_stores = if with_drafts + %i[draft live] + else + %i[live] + end + edition = Edition .includes(:document, :unpublishing) - .where(content_store:) - .find_by(base_path:) + .where(base_path:, content_store: content_stores) + .order( + Arel.sql( + <<~SQL, + CASE editions.content_store + WHEN 'draft' THEN 0 + WHEN 'live' THEN 1 + ELSE 2 + END + SQL + ), + ) + .first return unless edition @@ -29,6 +46,7 @@ def edition(base_path:, content_store:) end context[:root_edition] = edition + context[:with_drafts] = with_drafts edition end diff --git a/app/services/edition_finder_service.rb b/app/services/edition_finder_service.rb index dc672541c3..3de9ccaaba 100644 --- a/app/services/edition_finder_service.rb +++ b/app/services/edition_finder_service.rb @@ -1,13 +1,30 @@ class EditionFinderService - attr_reader :path, :content_store + attr_reader :path, :content_stores - def initialize(path, content_store) + def initialize(path, with_drafts: false) @path = path - @content_store = content_store + @content_stores = if with_drafts + %i[draft live] + else + %i[live] + end end def find - exact_match = scope.find_by(base_path: path) + exact_match = scope + .where(base_path: path) + .order( + Arel.sql( + <<~SQL, + CASE editions.content_store + WHEN 'draft' THEN 0 + WHEN 'live' THEN 1 + ELSE 2 + END + SQL + ), + ) + .first return exact_match if exact_match if route_matches.present? @@ -18,7 +35,7 @@ def find private def scope - Edition.where(content_store:) + Edition.where(content_store: @content_stores) end def route_matches diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 8b1d93850f..0245a69cca 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -23,16 +23,39 @@ ], "note": "The included SQL is a constant string with no user input." }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "683209c49b28a5b8dcf1f540dbba77d2ef430831a7b3391c7484bd0418bba104", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/queries/links.rb", + "line": 210, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "Arel.sql(\"\\n EXISTS(\\n SELECT nested_links.id\\n FROM links AS nested_links\\n WHERE link_set_content_id IS NOT NULL\\n AND #{where}\\n LIMIT 1\\n )\\n \")", + "render_path": null, + "location": { + "type": "method", + "class": "Queries::Links", + "method": "children_field" + }, + "user_input": "where", + "confidence": "Medium", + "cwe_id": [ + 89 + ], + "note": "This SQL is generated using valid content IDs and configuration data, not with arbitrary user input" + }, { "warning_type": "File Access", "warning_code": 16, - "fingerprint": "fd291054c7ec05ad94a610720679b4679e738f04204e1993fdeda694ee7c5f1d", + "fingerprint": "8bb962377b1903768a01fad99f2970a86d362bc80ab38bb1327411d6b8572e55", "check_name": "FileAccess", "message": "Parameter value used in file name", "file": "app/controllers/graphql_controller.rb", - "line": 28, + "line": 70, "link": "https://brakemanscanner.org/docs/warning_types/file_access/", - "code": "File.read(Rails.root.join(\"app/graphql/queries/#{EditionFinderService.new(Addressable::URI.encode(\"/#{params[:base_path]}\"), \"live\").find.schema_name}.graphql\"))", + "code": "File.read(Rails.root.join(\"app/graphql/queries/#{EditionFinderService.new(Addressable::URI.encode(\"/#{params[:base_path]}\")).find.schema_name}.graphql\"))", "render_path": null, "location": { "type": "method", @@ -47,27 +70,27 @@ "note": "" }, { - "warning_type": "SQL Injection", - "warning_code": 0, - "fingerprint": "683209c49b28a5b8dcf1f540dbba77d2ef430831a7b3391c7484bd0418bba104", - "check_name": "SQL", - "message": "Possible SQL injection", - "file": "app/queries/links.rb", - "line": 210, - "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", - "code": "Arel.sql(\"\\n EXISTS(\\n SELECT nested_links.id\\n FROM links AS nested_links\\n WHERE link_set_content_id IS NOT NULL\\n AND #{where}\\n LIMIT 1\\n )\\n \")", + "warning_type": "File Access", + "warning_code": 16, + "fingerprint": "caea2a7c4a7bdd253244a55991bdb9f5ef30073e70834adccefbee128af05cb5", + "check_name": "FileAccess", + "message": "Parameter value used in file name", + "file": "app/controllers/graphql_controller.rb", + "line": 28, + "link": "https://brakemanscanner.org/docs/warning_types/file_access/", + "code": "File.read(Rails.root.join(\"app/graphql/queries/#{EditionFinderService.new(Addressable::URI.encode(\"/#{params[:base_path]}\"), :with_drafts => true).find.schema_name}.graphql\"))", "render_path": null, "location": { "type": "method", - "class": "Queries::Links", - "method": "children_field" + "class": "GraphqlController", + "method": "draft_content" }, - "user_input": "where", - "confidence": "Medium", + "user_input": "params[:base_path]", + "confidence": "Weak", "cwe_id": [ - 89 + 22 ], - "note": "This SQL is generated using valid content IDs and configuration data, not with arbitrary user input" + "note": "" }, { "warning_type": "SQL Injection", diff --git a/config/routes.rb b/config/routes.rb index 1bba5ff136..35078ce186 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,6 +15,7 @@ def content_id_constraint(request) post "/lookup-by-base-path", to: "lookups#by_base_path" + get "/graphql/draft(/*base_path)" => "graphql#draft_content", as: :graphql_draft_content get "/graphql/content(/*base_path)" => "graphql#live_content", as: :graphql_live_content post "/graphql", to: "graphql#execute" diff --git a/lib/graphql_query_builder.rb b/lib/graphql_query_builder.rb index e30ea849b2..34b8f5139d 100644 --- a/lib/graphql_query_builder.rb +++ b/lib/graphql_query_builder.rb @@ -22,8 +22,8 @@ def initialize(schema_name) def build_query parts = [ - "query #{@schema_name}($base_path: String!) {", - " edition(base_path: $base_path) {", + "query #{@schema_name}($base_path: String!, $with_drafts: Boolean) {", + " edition(base_path: $base_path, with_drafts: $with_drafts) {", " ... on #{edition_type_or_subtype} {", build_fields(@content_item, indent: 6), " }", diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index 7317e5ab34..573e4d2320 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -1,213 +1,280 @@ RSpec.describe GraphqlController do - describe "#live_content" do - shared_examples "a response with default public cache headers" do - it "sets cache headers to expire in the default TTL" do - expect(cache_control["max-age"]).to eq(default_ttl.to_s) - end + shared_examples "a response with default public cache headers" do + it "sets cache headers to expire in the default TTL" do + expect(cache_control["max-age"]).to eq(default_ttl.to_s) + end - it "sets a cache-control directive of public" do - expect(cache_control["public"]).to eq(true) - end + it "sets a cache-control directive of public" do + expect(cache_control["public"]).to eq(true) end + end - context "when the requested base_path has live content" do + shared_examples "a content endpoint with a matching edition" do |content_store| + let(:edition) { create(edition_factory, **edition_properties) } + let(:request_path) { base_path_without_leading_slash(edition.base_path) } + + before do + edition + + get action, params: { base_path: request_path } + end + + it "returns a 200 OK response" do + expect(response.status).to eq(200) + end + + it "returns the content item as JSON data" do + expect(response.media_type).to eq("application/json") + end + + it "sets document_type and schema_type as prometheus labels" do + expect(request.env.dig("govuk.prometheus_labels", "document_type")).to eq(edition.document_type) + expect(request.env.dig("govuk.prometheus_labels", "schema_name")).to eq(edition.schema_name) + end + + it "defers to a service to process the result into a content item" do + edition = create(edition_factory, + schema_name: "news_article", + document_type: "news_story", + details: { "body" => "Some content" }) + + allow_any_instance_of(GraphqlContentItemService) + .to receive(:process) + .and_return({ "details" => { "something" => "jason!" } }) + + # we have a redundant request in the before block for this example + get action, params: { + base_path: base_path_without_leading_slash(edition.base_path), + } + + expect(JSON.parse(response.body)).to eq({ + "details" => { "something" => "jason!" }, + }) + end + + it_behaves_like "a response with default public cache headers" + + context "when the edition has a max cache time" do let(:edition) do create( - :live_edition, - schema_name: "news_article", - document_type: "news_story", - details: { - "body" => "Some content", - }, + edition_factory, + **edition_properties, + details: { max_cache_time: 10 }, ) end - let(:request_path) { base_path_without_leading_slash(edition.base_path) } + it "sets cache headers based on the edition's max cache time value" do + expect(cache_control["max-age"]).to eq("10") + end + end - before do - get :live_content, params: { base_path: request_path } + context "when the edition has a non-ASCII base_path" do + let(:edition) do + create( + edition_factory, + **edition_properties, + base_path: "/news/%D7%91%D7%95%D7%98%20%D7%9C%D7%90%D7%99%D7%A0%D7%93", + ) end + let(:request_path) { "news/בוט לאינד" } it "returns a 200 OK response" do expect(response.status).to eq(200) end - it "returns the content item as JSON data" do + it "returns the presented content item as JSON data" do expect(response.media_type).to eq("application/json") end + end - it "sets document_type and schema_type as prometheus labels" do - expect(request.env.dig("govuk.prometheus_labels", "document_type")).to eq(edition.document_type) - expect(request.env.dig("govuk.prometheus_labels", "schema_name")).to eq(edition.schema_name) + context "when the requested route does not match the base_path" do + let(:edition) do + create( + edition_factory, + **edition_properties, + base_path: "/base-path", + routes: [ + { path: "/base-path", type: "exact" }, + { path: "/base-path/exact", type: "exact" }, + ], + ) + end + let(:request_path) { base_path_without_leading_slash(edition.routes.second[:path]) } + + it "returns a 303 See Other response" do + expect(response.status).to eq(303) + end + + it "returns a redirect to the item by base_path" do + redirect_path = case action + when :draft_content + "/graphql/draft/base-path" + when :live_content + "/graphql/content/base-path" + end + + expect(response).to redirect_to(redirect_path) end it_behaves_like "a response with default public cache headers" + end + + context "when the edition is of a schema unsupported by GraphQL" do + let(:edition) { create(edition_factory, schema_name: "get_involved") } + + it "returns a 404 Not Found response" do + expect(response.status).to eq(404) + end - context "but the requested route does not match the base_path" do + it_behaves_like "a response with default public cache headers" + end + + if content_store == :live + context "when the edition is gone without an explanation or alternative_path" do let(:edition) do create( - :live_edition, - base_path: "/base-path", - document_type: "news_story", - routes: [ - { path: "/base-path", type: "exact" }, - { path: "/base-path/exact", type: "exact" }, - ], + :gone_unpublished_edition_without_explanation, schema_name: "news_article", ) end - let(:request_path) { base_path_without_leading_slash(edition.routes.second[:path]) } + it "responds with 410" do + expect(response.status).to eq(410) + end + + it_behaves_like "a response with default public cache headers" + end + + context "when the edition is gone with an explanation and alternative_path" do + let(:edition) do + create( + :gone_unpublished_edition, + schema_name: "news_article", + ) + end - it "returns a 303 See Other response" do - expect(response.status).to eq(303) + it "responds with 200" do + expect(response.status).to eq(200) end - it "returns a redirect to the item by base_path" do - expect(response).to redirect_to("/graphql/content/base-path") + it "includes the details" do + details = JSON.parse(response.body)["details"] + expect(details["explanation"]).to eq(edition.unpublishing.explanation) + expect(details["alternative_path"]).to eq(edition.unpublishing.alternative_path) end + + it_behaves_like "a response with default public cache headers" end end + end - context "a content item with a non-ASCII base_path" do - before(:each) do - create( - :live_edition, - base_path: "/news/%D7%91%D7%95%D7%98%20%D7%9C%D7%90%D7%99%D7%A0%D7%93", - schema_name: "news_article", - ) - get :live_content, params: { base_path: "news/בוט לאינד" } - end + shared_examples "a content endpoint" do + it "defers to a service to find the correct edition" do + expect_any_instance_of(EditionFinderService).to receive(:find) - it "returns a 200 OK response" do - expect(response.status).to eq(200) - end + get :live_content, params: { + base_path: base_path_without_leading_slash("/base-path"), + } + end - it "returns the presented content item as JSON data" do - expect(response.media_type).to eq("application/json") + context "when there's no matching edition" do + before(:each) { get action, params: { base_path: "unknown-content" } } + + it "returns a 404 Not Found response" do + expect(response.status).to eq(404) end + + it_behaves_like "a response with default public cache headers" end - context "a content item with an invalid path" do + context "when the requested base path is invalid" do it "returns a 400 Bad Request response" do # we can't run the test with an actual invalid URI so we have to mock that expect(Addressable::URI).to receive(:encode).and_wrap_original do |m| m.call("/path\nprotocol:") end - get :live_content, params: { base_path: "content/invalid-uri" } + get action, params: { base_path: "content/invalid-uri" } expect(response.status).to eq(400) end end + end - context "when the requested base_path is not a format supported by GraphQL" do - let(:edition) do - create( - :live_edition, - schema_name: "get_involved", - ) - end + describe "#draft_content" do + let(:action) { :draft_content } - before do - get :live_content, params: { base_path: base_path_without_leading_slash(edition.base_path) } - end + it_behaves_like "a content endpoint" - it "returns a 404 not_found response" do - expect(response.status).to eq(404) + context "when the requested base_path has draft content" do + let(:edition_factory) { :draft_edition } + let(:edition_properties) do + { + schema_name: "person", + document_type: "person", + details: { "body" => "Some content" }, + } end - end - context "a non-existent content item" do - before(:each) { get :live_content, params: { base_path: "unknown-content" } } + it_behaves_like "a content endpoint with a matching edition", :draft + end - it "returns a 404 Not Found response" do - expect(response.status).to eq(404) + context "when the requested base_path only has live content" do + let(:edition_factory) { :live_edition } + let(:edition_properties) do + { + schema_name: "news_article", + document_type: "news_story", + details: { "body" => "Some content" }, + } end - it_behaves_like "a response with default public cache headers" + it_behaves_like "a content endpoint with a matching edition", :live end + end - context "a gone content item without an explanation and without an alternative_path" do - let(:edition) do - create( - :gone_unpublished_edition_without_explanation, - schema_name: "news_article", - ) - end + describe "#live_content" do + let(:action) { :live_content } - before do - get :live_content, params: { base_path: base_path_without_leading_slash(edition.base_path) } - end + it_behaves_like "a content endpoint" - it "responds with 410" do - expect(response.status).to eq(410) + context "when the requested base_path has live content" do + let(:edition_factory) { :live_edition } + let(:edition_properties) do + { + schema_name: "news_article", + document_type: "news_story", + details: { "body" => "Some content" }, + } end - it_behaves_like "a response with default public cache headers" + it_behaves_like "a content endpoint with a matching edition", :live end - context "a gone content item with an explanation and alternative_path" do + context "when the requested base_path only has draft content" do let(:edition) do create( - :gone_unpublished_edition, - schema_name: "news_article", + :draft_edition, + schema_name: "person", + document_type: "person", + details: { + "body" => "Some content", + }, ) end + let(:request_path) { base_path_without_leading_slash(edition.base_path) } + before do - get :live_content, params: { base_path: base_path_without_leading_slash(edition.base_path) } + get :live_content, params: { base_path: request_path } end - it "responds with 200" do - expect(response.status).to eq(200) + it "returns a 404 Not Found response" do + expect(response.status).to eq(404) end - it "includes the details" do - details = JSON.parse(response.body)["details"] - expect(details["explanation"]).to eq(edition.unpublishing.explanation) - expect(details["alternative_path"]).to eq(edition.unpublishing.alternative_path) + it "doesn't return any content item data" do + expect(response.body).not_to be_present end end - - it "defers to a service to process the result into a content item" do - edition = create(:live_edition, - schema_name: "news_article", - document_type: "news_story", - details: { - "body" => "Some content", - }) - - allow_any_instance_of(GraphqlContentItemService) - .to receive(:process) - .and_return({ "details" => { "something" => "jason!" } }) - - get :live_content, params: { - base_path: base_path_without_leading_slash(edition.base_path), - } - - expect(JSON.parse(response.body)).to eq({ - "details" => { "something" => "jason!" }, - }) - end - - it "defers to a service to find the correct edition" do - expect_any_instance_of(EditionFinderService).to receive(:find) - - get :live_content, params: { - base_path: base_path_without_leading_slash("/base-path"), - } - end - - it "sets cache headers based on the edition's max cache time value" do - edition = create( - :live_edition, - schema_name: "specialist_document", - details: { max_cache_time: 10 }, - ) - - get :live_content, params: { base_path: base_path_without_leading_slash(edition.base_path) } - - expect(cache_control["max-age"]).to eq("10") - end end def base_path_without_leading_slash(base_path) diff --git a/spec/factories/edition.rb b/spec/factories/edition.rb index d7302521f1..e29c93305c 100644 --- a/spec/factories/edition.rb +++ b/spec/factories/edition.rb @@ -29,7 +29,7 @@ state { "draft" } content_store { "draft" } sequence(:base_path) { |n| "/vat-rates-#{n}" } - user_facing_version { 1 } + user_facing_version { 2 } transient do change_note { "note" } diff --git a/spec/factories/unpublished_edition.rb b/spec/factories/unpublished_edition.rb index 811921a5cf..4ddc88ec51 100644 --- a/spec/factories/unpublished_edition.rb +++ b/spec/factories/unpublished_edition.rb @@ -4,6 +4,8 @@ content_store { "live" } public_updated_at { "2014-05-14T13:00:06Z" } first_published_at { "2014-01-02T03:04:05Z" } + user_facing_version { 1 } + transient do unpublishing_type { "gone" } explanation { "Removed for testing reasons" } diff --git a/spec/graphql/sources/linked_to_editions_source_spec.rb b/spec/graphql/sources/linked_to_editions_source_spec.rb index ce0bac4c23..8108685fa5 100644 --- a/spec/graphql/sources/linked_to_editions_source_spec.rb +++ b/spec/graphql/sources/linked_to_editions_source_spec.rb @@ -16,7 +16,7 @@ def check_links! GraphQL::Dataloader.with_dataloading do |dataloader| request = dataloader.with( described_class, - content_store: source_edition.content_store, + with_drafts:, locale: source_edition.locale, ).request([source_edition, link_type]) @@ -37,12 +37,14 @@ def check_links! end end + let(:with_drafts) { false } + context "when the same source content has a mix of link set links and edition links for the same link type" do it "returns only the edition links" do - target_edition_1 = create(:edition, title: "edition 1, test link, edition link") - target_edition_2 = create(:edition, title: "edition 2, test link, link set link") + target_edition_1 = create(:live_edition, title: "edition 1, test link, edition link") + target_edition_2 = create(:live_edition, title: "edition 2, test link, link set link") - source_edition = create(:edition, + source_edition = create(:live_edition, edition_links: [ { link_type: "test_link", target_content_id: target_edition_1.content_id }, ], @@ -58,11 +60,11 @@ def check_links! %i[link_set_links edition_links].each do |links_kind| context "when the link kind is #{links_kind}" do it "returns the specified links" do - target_edition_1 = create(:edition, title: "edition 1, test link") - target_edition_2 = create(:edition, title: "edition 2, another link type") - target_edition_3 = create(:edition, title: "edition 3, test link") + target_edition_1 = create(:live_edition, title: "edition 1, test link") + target_edition_2 = create(:live_edition, title: "edition 2, another link type") + target_edition_3 = create(:live_edition, title: "edition 3, test link") - source_edition = create(:edition, + source_edition = create(:live_edition, links_kind => [ { link_type: "test_link", target_content_id: target_edition_1.content_id }, { link_type: "another_link_type", target_content_id: target_edition_2.content_id }, @@ -73,26 +75,61 @@ def check_links! expect(source_edition).to have_links("test_link").with_titles(expected_titles).in_any_order end - it "returns links from only the requested content store" do - target_edition_0 = create(:live_edition, title: "edition 0, live") - target_edition_1 = create(:draft_edition, title: "edition 1, draft") + context "when with_drafts=true" do + let(:with_drafts) { true } - source_edition = create(:draft_edition, - links_kind => [ - { link_type: "test_link", target_content_id: target_edition_0.content_id }, - { link_type: "test_link", target_content_id: target_edition_1.content_id }, - ]) + it "returns links to drafts when drafts are available" do + target_document = create(:document) + create(:live_edition, title: "edition 1, live", document: target_document) + target_edition = create(:draft_edition, title: "edition 2, draft", document: target_document) - expected_titles = [target_edition_1.title] - expect(source_edition).to have_links("test_link").with_titles(expected_titles) + source_edition = create(:draft_edition, + links_kind => [ + { link_type: "test_link", target_content_id: target_document.content_id }, + ]) + + expected_titles = [target_edition.title] + expect(source_edition).to have_links("test_link").with_titles(expected_titles) + end + + it "returns links to live editions when drafts aren't available" do + target_document = create(:document) + target_edition = create(:live_edition, title: "edition, live", document: target_document) + + source_edition = create(:draft_edition, + links_kind => [ + { link_type: "test_link", target_content_id: target_document.content_id }, + ]) + + expected_titles = [target_edition.title] + expect(source_edition).to have_links("test_link").with_titles(expected_titles) + end + end + + context "when with_drafts=false" do + it "doesn't return links to drafts" do + target_edition_1 = create(:draft_edition, title: "edition 1, draft") + target_document = create(:document) + target_edition_2 = create(:live_edition, title: "edition 2, live", document: target_document) + create(:draft_edition, title: "edition 3, draft", document: target_document) + + source_edition = create(:live_edition, + links_kind => [ + { link_type: "test_link", target_content_id: target_edition_1.content_id }, + { link_type: "test_link", target_content_id: target_document.content_id }, + ]) + + expected_titles = [target_edition_2.title] + expect(source_edition).to have_links("test_link").with_titles(expected_titles) + end end it "returns editions in order of their associated link's `position`" do - target_edition_0 = create(:edition, title: "edition 0, position 1") - target_edition_1 = create(:edition, title: "edition 1, position 2") - target_edition_2 = create(:edition, title: "edition 2, position 0") + target_edition_0 = create(:live_edition, title: "edition 0, position 1") + target_edition_1 = create(:live_edition, title: "edition 1, position 2") + target_edition_2 = create(:live_edition, title: "edition 2, position 0") - source_edition = create(:edition, + source_edition = create(:live_edition, links_kind => [ { link_type: "test_link", target_content_id: target_edition_0.content_id, position: 1 }, { link_type: "test_link", target_content_id: target_edition_1.content_id, position: 2 }, @@ -105,12 +142,12 @@ def check_links! context "when links have the same `position`" do it "returns editions reverse-ordered by their associated links' `id`" do - target_edition_0 = create(:edition, title: "edition 0, third link id") - target_edition_1 = create(:edition, title: "edition 1, first link id") - target_edition_2 = create(:edition, title: "edition 2, second link id") - target_edition_3 = create(:edition, title: "edition 3, fourth link id") + target_edition_0 = create(:live_edition, title: "edition 0, third link id") + target_edition_1 = create(:live_edition, title: "edition 1, first link id") + target_edition_2 = create(:live_edition, title: "edition 2, second link id") + target_edition_3 = create(:live_edition, title: "edition 3, fourth link id") - source_edition = create(:edition, + source_edition = create(:live_edition, links_kind => [ { link_type: "test_link", target_content_id: target_edition_1.content_id, position: 0 }, { link_type: "test_link", target_content_id: target_edition_2.content_id, position: 0 }, @@ -192,11 +229,11 @@ def check_links! describe "links between documents with different locales" do it "includes links matching the specified locale (french)" do target_content_id = SecureRandom.uuid - create(:edition, document: create(:document, locale: "en", content_id: target_content_id), title: "english") - french_edition = create(:edition, document: create(:document, locale: "fr", content_id: target_content_id), title: "french") + create(:live_edition, document: create(:document, locale: "en", content_id: target_content_id), title: "english") + french_edition = create(:live_edition, document: create(:document, locale: "fr", content_id: target_content_id), title: "french") source_edition = create( - :edition, + :live_edition, document: create(:document, locale: "fr"), links_kind => [ { link_type: "test_link", target_content_id: }, @@ -209,11 +246,11 @@ def check_links! it "includes English language links if there's no better match available" do target_content_id = SecureRandom.uuid - english_edition = create(:edition, document: create(:document, locale: "en", content_id: target_content_id), title: "english edition") - create(:edition, document: create(:document, locale: "fr", content_id: target_content_id), title: "french edition") + english_edition = create(:live_edition, document: create(:document, locale: "en", content_id: target_content_id), title: "english edition") + create(:live_edition, document: create(:document, locale: "fr", content_id: target_content_id), title: "french edition") source_edition = create( - :edition, + :live_edition, document: create(:document, locale: "de"), links_kind => [ { link_type: "test_link", target_content_id: }, @@ -226,11 +263,11 @@ def check_links! it "doesn't include a link if none match the locale or English" do target_content_id = SecureRandom.uuid - create(:edition, document: create(:document, locale: "de", content_id: target_content_id), title: "german") - create(:edition, document: create(:document, locale: "fr", content_id: target_content_id), title: "french") + create(:live_edition, document: create(:document, locale: "de", content_id: target_content_id), title: "german") + create(:live_edition, document: create(:document, locale: "fr", content_id: target_content_id), title: "french") source_edition = create( - :edition, + :live_edition, document: create(:document, locale: "hu"), links_kind => [ { link_type: "test_link", target_content_id: }, @@ -240,7 +277,36 @@ def check_links! expect(source_edition).not_to have_links("test_link") end - context "when the source Edition is live" do + context "when requested with with_drafts=true" do + let(:with_drafts) { true } + + it "includes a draft 'en' link if there isn't a draft locale-matching one" do + target_content_id = SecureRandom.uuid + english_edition = create( + :draft_edition, + document: create(:document, locale: "en", content_id: target_content_id), + title: "english draft edition", + ) + create( + :live_edition, + document: create(:document, locale: "fr", content_id: target_content_id), + title: "french live edition", + ) + + source_edition = create( + :live_edition, + document: create(:document, locale: "fr"), + links_kind => [ + { link_type: "test_link", target_content_id: }, + ], + ) + + expected_titles = [english_edition.title] + expect(source_edition).to have_links("test_link").with_titles(expected_titles) + end + end + + context "when requested with with_drafts=false" do it "defaults to including a (live) 'en' link if the locale-matching one is draft" do target_content_id = SecureRandom.uuid english_edition = create( @@ -364,11 +430,11 @@ def check_links! end it "doesn't include linked editions of non-renderable document types" do - renderable_edition = create(:edition, title: "renderable edition") + renderable_edition = create(:live_edition, title: "renderable edition") non_renderable_edition = create(:redirect_edition, title: "non-renderable edition (redirect)") source_edition = create( - :edition, + :live_edition, links_kind => [ { link_type: "test_link", target_content_id: renderable_edition.content_id }, { link_type: "test_link", target_content_id: non_renderable_edition.content_id }, diff --git a/spec/graphql/sources/reverse_linked_to_editions_source_spec.rb b/spec/graphql/sources/reverse_linked_to_editions_source_spec.rb index 94d52c36cb..6b756982f2 100644 --- a/spec/graphql/sources/reverse_linked_to_editions_source_spec.rb +++ b/spec/graphql/sources/reverse_linked_to_editions_source_spec.rb @@ -1,5 +1,5 @@ RSpec.describe Sources::ReverseLinkedToEditionsSource do - RSpec::Matchers.define :have_links do |link_type| + RSpec::Matchers.define :have_reverse_links do |link_type| def check_links! expect(@links).not_to be_empty @@ -16,7 +16,7 @@ def check_links! GraphQL::Dataloader.with_dataloading do |dataloader| request = dataloader.with( described_class, - content_store: target_edition.content_store, + with_drafts:, locale: target_edition.locale, ).request([target_edition, link_type]) @@ -37,11 +37,13 @@ def check_links! end end + let(:with_drafts) { false } + context "when the same target content has a mix of link set links and edition links for the same link type" do it "returns all valid source editions" do - target_edition = create(:edition) + target_edition = create(:live_edition) - source_edition_1 = create(:edition, + source_edition_1 = create(:live_edition, title: "edition 1, edition link", edition_links: [ { @@ -49,7 +51,7 @@ def check_links! target_content_id: target_edition.content_id, }, ]) - source_edition_2 = create(:edition, + source_edition_2 = create(:live_edition, title: "edition 2, link set link", link_set_links: [ { @@ -59,15 +61,15 @@ def check_links! ]) expected_titles = [source_edition_1, source_edition_2].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles).in_any_order + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles).in_any_order end end context "when the same document is both a link set link and an edition link" do it "only returns the document once" do - target_edition = create(:edition) + target_edition = create(:live_edition) - source_edition = create(:edition, + source_edition = create(:live_edition, edition_links: [ { link_type: "test_link", target_content_id: target_edition.content_id }, ], @@ -75,73 +77,146 @@ def check_links! { link_type: "test_link", target_content_id: target_edition.content_id }, ]) - GraphQL::Dataloader.with_dataloading do |dataloader| - request = dataloader.with( - described_class, - content_store: target_edition.content_store, - locale: target_edition.locale, - ).request([target_edition, "test_link"]) - - expect(request.load).to eq([source_edition]) - end + expected_titles = [source_edition.title] + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end end %i[link_set_links edition_links].each do |links_kind| context "when the link kind is #{links_kind}" do it "returns the specified reverse links" do - target_edition = create(:edition) + target_edition = create(:live_edition) - source_edition_1 = create(:edition, + source_edition_1 = create(:live_edition, title: "edition 1, test link", links_kind => [ { link_type: "test_link", target_content_id: target_edition.content_id }, ]) - source_edition_2 = create(:edition, + source_edition_2 = create(:live_edition, title: "edition 2, test link", links_kind => [ { link_type: "test_link", target_content_id: target_edition.content_id }, ]) - create(:edition, + create(:live_edition, title: "edition 3, another link type", links_kind => [ { link_type: "another_link_type", target_content_id: target_edition.content_id }, ]) expected_titles = [source_edition_1, source_edition_2].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles).in_any_order + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles).in_any_order + end + + context "when with_drafts=true" do + let(:with_drafts) { true } + + it "returns reverse links to drafts when drafts are available" do + target_edition = create(:live_edition) + + source_document = create(:document) + source_edition_1 = create( + :draft_edition, + title: "edition 1, draft", + document: source_document, + links_kind => [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + create( + :live_edition, + title: "edition 2, live", + document: source_document, + links_kind => [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + + expected_titles = [source_edition_1.title] + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) + end + + it "returns reverse links to live editions when drafts aren't available" do + target_edition = create(:live_edition) + + source_edition = create( + :live_edition, + title: "edition 1, live", + links_kind => [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + + expected_titles = [source_edition.title] + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) + end + end + + context "when with_drafts=false" do + it "doesn't return reverse links to drafts" do + target_edition = create(:live_edition) + + create( + :draft_edition, + title: "edition 1, draft", + links_kind => [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + + source_document = create(:document) + source_edition_2 = create( + :live_edition, + title: "edition 2, live", + document: source_document, + links_kind => [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + + create( + :draft_edition, + title: "edition 3, draft", + document: source_document, + links_kind => [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + + expected_titles = [source_edition_2.title] + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) + end end it "returns editions ordered by their reverse links' `position`" do - target_edition = create(:edition) + target_edition = create(:live_edition) - source_edition_0 = create(:edition, + source_edition_0 = create(:live_edition, title: "edition 0, position 1", links_kind => [ { link_type: "test_link", target_content_id: target_edition.content_id, position: 1 }, ]) - source_edition_1 = create(:edition, + source_edition_1 = create(:live_edition, title: "edition 1, position 2", links_kind => [ { link_type: "test_link", target_content_id: target_edition.content_id, position: 2 }, ]) - source_edition_2 = create(:edition, + source_edition_2 = create(:live_edition, title: "edition 2, position 0", links_kind => [ { link_type: "test_link", target_content_id: target_edition.content_id, position: 0 }, ]) expected_titles = [source_edition_2, source_edition_0, source_edition_1].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end context "when reverse links have the same `position`" do it "returns editions reverse-ordered by their associated reverse links' `id`" do - target_edition = create(:edition) + target_edition = create(:live_edition) - source_edition_1 = create(:edition, + source_edition_1 = create(:live_edition, title: "edition 1, second link id", links_kind => [ { @@ -151,7 +226,7 @@ def check_links! id: 10_002, }, ]) - source_edition_0 = create(:edition, + source_edition_0 = create(:live_edition, title: "edition 0, first link id", links_kind => [ { @@ -161,7 +236,7 @@ def check_links! id: 10_001, }, ]) - source_edition_2 = create(:edition, + source_edition_2 = create(:live_edition, title: "edition 2, third link id", links_kind => [ { @@ -173,7 +248,7 @@ def check_links! ]) expected_titles = [source_edition_2, source_edition_1, source_edition_0].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end end @@ -190,7 +265,7 @@ def check_links! }]) expected_titles = [source_edition].map(&:title) - expect(target_edition).to have_links("parent").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("parent").with_titles(expected_titles) end it "does not include unpublished reverse links when the unpublishing type is not withdrawal" do @@ -221,7 +296,7 @@ def check_links! target_content_id: target_edition.content_id, }]) - expect(target_edition).not_to have_links("parent") + expect(target_edition).not_to have_reverse_links("parent") end end @@ -235,7 +310,7 @@ def check_links! { link_type: "test_link", target_content_id: target_edition.content_id }, ]) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") end it "also does not include unpublished reverse links when the unpublishing type is not withdrawal" do @@ -266,16 +341,16 @@ def check_links! target_content_id: target_edition.content_id, }]) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") end end end it "doesn't include linked editions of non-renderable document types" do - target_edition = create(:edition) + target_edition = create(:live_edition) renderable_edition = create( - :edition, + :live_edition, title: "renderable edition", links_kind => [ { link_type: "test_link", target_content_id: target_edition.content_id }, @@ -290,7 +365,7 @@ def check_links! ) expected_titles = [renderable_edition].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end end end @@ -299,11 +374,11 @@ def check_links! %i[link_set_links edition_links].each do |links_kind| context "when the link kind is #{links_kind}" do it "includes reverse links matching the specified locale" do - target_edition = create(:edition, document: create(:document, locale: "fr")) + target_edition = create(:live_edition, document: create(:document, locale: "fr")) source_content_id = SecureRandom.uuid create( - :edition, + :live_edition, title: "english, test link", document: create(:document, locale: "en", content_id: source_content_id), links_kind => [ @@ -311,7 +386,7 @@ def check_links! ], ) french_edition = create( - :edition, + :live_edition, title: "french, test link", document: create(:document, locale: "fr", content_id: source_content_id), links_kind => [ @@ -320,18 +395,18 @@ def check_links! ) expected_titles = [french_edition].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end end end context "when the link kind is link_set_links" do it "includes English language reverse links if there's no better match available" do - target_edition = create(:edition, document: create(:document, locale: "de")) + target_edition = create(:live_edition, document: create(:document, locale: "de")) source_content_id = SecureRandom.uuid english_edition = create( - :edition, + :live_edition, document: create(:document, locale: "en", content_id: source_content_id), title: "english, test link", link_set_links: [ @@ -339,7 +414,7 @@ def check_links! ], ) create( - :edition, + :live_edition, document: create(:document, locale: "fr", content_id: source_content_id), title: "french, test link", link_set_links: [ @@ -348,15 +423,15 @@ def check_links! ) expected_titles = [english_edition].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end it "doesn't include a reverse link if none match the locale or English" do - target_edition = create(:edition, document: create(:document, locale: "hu")) + target_edition = create(:live_edition, document: create(:document, locale: "hu")) source_content_id = SecureRandom.uuid create( - :edition, + :live_edition, document: create(:document, locale: "de", content_id: source_content_id), title: "german", link_set_links: [ @@ -364,7 +439,7 @@ def check_links! ], ) create( - :edition, + :live_edition, document: create(:document, locale: "fr", content_id: source_content_id), title: "french", link_set_links: [ @@ -372,17 +447,17 @@ def check_links! ], ) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") end end context "when the link kind is edition_links" do it "doesn't include a reverse link if none match the locale" do - target_edition = create(:edition, document: create(:document, locale: "hu")) + target_edition = create(:live_edition, document: create(:document, locale: "hu")) source_content_id = SecureRandom.uuid create( - :edition, + :live_edition, document: create(:document, locale: "en", content_id: source_content_id), title: "english, test link", edition_links: [ @@ -390,7 +465,7 @@ def check_links! ], ) create( - :edition, + :live_edition, document: create(:document, locale: "de", content_id: source_content_id), title: "german", edition_links: [ @@ -398,7 +473,7 @@ def check_links! ], ) create( - :edition, + :live_edition, document: create(:document, locale: "fr", content_id: source_content_id), title: "french", edition_links: [ @@ -406,11 +481,42 @@ def check_links! ], ) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") + end + end + + context "when requested with with_drafts=true" do + let(:with_drafts) { true } + + context "when the link kind is link_set_links" do + it "includes a draft 'en' link if there isn't a draft locale-matching one" do + target_edition = create(:live_edition, document: create(:document, locale: "fr")) + + source_content_id = SecureRandom.uuid + english_edition = create( + :draft_edition, + document: create(:document, locale: "en", content_id: source_content_id), + title: "english draft edition", + link_set_links: [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + create( + :live_edition, + document: create(:document, locale: "fr", content_id: source_content_id), + title: "french live edition", + link_set_links: [ + { link_type: "test_link", target_content_id: target_edition.content_id }, + ], + ) + + expected_titles = [english_edition].map(&:title) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) + end end end - context "when the Edition is live" do + context "when requested with with_drafts=false" do context "when the link kind is link_set_links" do it "defaults to including a (live) 'en' reverse link when the locale-matching one is draft" do target_edition = create(:live_edition, document: create(:document, locale: "fr")) @@ -434,7 +540,7 @@ def check_links! ) expected_titles = [english_edition].map(&:title) - expect(target_edition).to have_links("test_link").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("test_link").with_titles(expected_titles) end it "doesn't include any reverse link if none are live" do @@ -458,12 +564,12 @@ def check_links! ], ) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") end end context "when the link kind is edition_links" do - it "doesn't default to including a (live) 'en' reverse link when the locale-matching one is draft" do + it "doesn't include any reverse links if there are no locale-matching live ones" do target_edition = create(:live_edition, document: create(:document, locale: "fr")) source_content_id = SecureRandom.uuid @@ -484,7 +590,7 @@ def check_links! ], ) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") end end end @@ -514,7 +620,7 @@ def check_links! ) expected_titles = [french_edition].map(&:title) - expect(target_edition).to have_links("related_statistical_data_sets").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("related_statistical_data_sets").with_titles(expected_titles) end it "omits a locale-matching reverse link if it isn't a permitted unpublished link_type" do @@ -530,7 +636,7 @@ def check_links! ], ) - expect(target_edition).not_to have_links("test_link") + expect(target_edition).not_to have_reverse_links("test_link") end end end @@ -558,7 +664,7 @@ def check_links! ) expected_titles = [english_published_edition].map(&:title) - expect(target_edition).to have_links("related_statistical_data_sets").with_titles(expected_titles) + expect(target_edition).to have_reverse_links("related_statistical_data_sets").with_titles(expected_titles) end end @@ -584,7 +690,7 @@ def check_links! ], ) - expect(target_edition).not_to have_links("related_statistical_data_sets") + expect(target_edition).not_to have_reverse_links("related_statistical_data_sets") end end end diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index 2dedae6436..f75d88d80e 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -4,8 +4,8 @@ describe "#edition" do let(:query) do <<~QUERY - query($base_path: String!, $content_store: String!) { - edition(base_path: $base_path, content_store: $content_store) { + query($base_path: String!, $with_drafts: Boolean!) { + edition(base_path: $base_path, with_drafts: $with_drafts) { ... on Edition { base_path state @@ -18,22 +18,34 @@ context "when there is only a draft edition" do let(:draft_edition) { create(:draft_edition) } - context "requesting the draft edition" do + context "requesting with_drafts=true" do it "returns the draft edition" do expected_data = { "base_path" => draft_edition.base_path, "state" => "draft", } - result = PublishingApiSchema.execute(query, variables: { base_path: draft_edition.base_path, content_store: "draft" }) + result = PublishingApiSchema.execute( + query, + variables: { + base_path: draft_edition.base_path, + with_drafts: true, + }, + ) edition_data = result.dig("data", "edition") expect(edition_data).to eq(expected_data) end end - context "requesting the live edition" do + context "requesting with_drafts=false" do it "returns no edition" do - result = PublishingApiSchema.execute(query, variables: { base_path: draft_edition.base_path, content_store: "live" }) + result = PublishingApiSchema.execute( + query, + variables: { + base_path: draft_edition.base_path, + with_drafts: false, + }, + ) edition_data = result.dig("data", "edition") expect(edition_data).to be_nil end @@ -43,22 +55,39 @@ context "when there is only a live edition" do let(:live_edition) { create(:live_edition) } - context "requesting the draft edition" do - it "returns no edition" do - result = PublishingApiSchema.execute(query, variables: { base_path: live_edition.base_path, content_store: "draft" }) + context "requesting with_drafts=true" do + it "returns the live edition" do + expected_data = { + "base_path" => live_edition.base_path, + "state" => "published", + } + + result = PublishingApiSchema.execute( + query, + variables: { + base_path: live_edition.base_path, + with_drafts: true, + }, + ) edition_data = result.dig("data", "edition") - expect(edition_data).to be_nil + expect(edition_data).to eq(expected_data) end end - context "requesting the live edition" do + context "requesting with_drafts=false" do it "returns the live edition" do expected_data = { "base_path" => live_edition.base_path, "state" => "published", } - result = PublishingApiSchema.execute(query, variables: { base_path: live_edition.base_path, content_store: "live" }) + result = PublishingApiSchema.execute( + query, + variables: { + base_path: live_edition.base_path, + with_drafts: false, + }, + ) edition_data = result.dig("data", "edition") expect(edition_data).to eq(expected_data) end @@ -71,27 +100,39 @@ let!(:live_edition) { create(:live_edition, document:, base_path:, user_facing_version: 1) } let!(:draft_edition) { create(:draft_edition, document:, base_path:, user_facing_version: 2) } - context "requesting the draft edition" do + context "requesting with_drafts=true" do it "returns the draft edition" do expected_data = { "base_path" => draft_edition.base_path, "state" => "draft", } - result = PublishingApiSchema.execute(query, variables: { base_path: draft_edition.base_path, content_store: "draft" }) + result = PublishingApiSchema.execute( + query, + variables: { + base_path: live_edition.base_path, + with_drafts: true, + }, + ) edition_data = result.dig("data", "edition") expect(edition_data).to eq(expected_data) end end - context "requesting the live edition" do + context "requesting with_drafts=false" do it "returns the live edition" do expected_data = { "base_path" => live_edition.base_path, "state" => "published", } - result = PublishingApiSchema.execute(query, variables: { base_path: live_edition.base_path, content_store: "live" }) + result = PublishingApiSchema.execute( + query, + variables: { + base_path: live_edition.base_path, + with_drafts: false, + }, + ) edition_data = result.dig("data", "edition") expect(edition_data).to eq(expected_data) end diff --git a/spec/integration/graphql/draft_content_spec.rb b/spec/integration/graphql/draft_content_spec.rb new file mode 100644 index 0000000000..60f2d86085 --- /dev/null +++ b/spec/integration/graphql/draft_content_spec.rb @@ -0,0 +1,52 @@ +RSpec.describe "Requesting draft content by base path" do + context "when not all content is available as a draft" do + it "will link from live editions to draft editions and vice versa" do + level_2_target_edition = create(:live_edition, title: "level 2 edition 1, live") + + level_1_target_document = create(:document) + create( + :live_edition, + title: "level 1 edition 1, live", + document: level_1_target_document, + ) + create( + :draft_edition, + title: "level 1 edition 2, draft", + document: level_1_target_document, + link_set_links: [ + { link_type: "parent_taxons", target_content_id: level_2_target_edition.content_id }, + ], + ) + + edition = create( + :live_edition, + title: "root edition, live", + edition_links: [ + { link_type: "taxons", target_content_id: level_1_target_document.content_id }, + ], + ) + + get "/graphql/draft/#{edition.base_path}" + + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to match( + a_hash_including("title" => "root edition, live"), + ) + expect(parsed_response["links"]).to match( + a_hash_including( + "taxons" => match_array( + a_hash_including("title" => "level 1 edition 2, draft"), + ), + ), + ) + expect(parsed_response["links"]["taxons"].first["links"]).to match( + a_hash_including( + "parent_taxons" => match_array( + a_hash_including("title" => "level 2 edition 1, live"), + ), + ), + ) + end + end +end diff --git a/spec/integration/graphql/link_expansion/direct_link_inclusion_spec.rb b/spec/integration/graphql/link_expansion/direct_link_inclusion_spec.rb index 46587021ce..38ff31ff20 100644 --- a/spec/integration/graphql/link_expansion/direct_link_inclusion_spec.rb +++ b/spec/integration/graphql/link_expansion/direct_link_inclusion_spec.rb @@ -10,8 +10,8 @@ def for_graphql(source_edition, link_type:, with_drafts:) GraphQL::Dataloader.with_dataloading do |dataloader| request = dataloader.with( Sources::LinkedToEditionsSource, - content_store: with_drafts ? "draft" : "live", locale: source_edition.locale, + with_drafts:, ).request([source_edition, link_type]) request.load @@ -60,9 +60,6 @@ def for_graphql(source_edition, link_type:, with_drafts:) ) %w[content_store graphql].each do |destination| - # GraphQL doesn't yet support drafts - next if destination == "graphql" && test_case.with_drafts? - result = send( :"for_#{destination}", source_edition, diff --git a/spec/integration/graphql/link_expansion/direct_link_precedence_with_different_content_ids_spec.rb b/spec/integration/graphql/link_expansion/direct_link_precedence_with_different_content_ids_spec.rb index 6d29cc561f..8e8aa8f807 100644 --- a/spec/integration/graphql/link_expansion/direct_link_precedence_with_different_content_ids_spec.rb +++ b/spec/integration/graphql/link_expansion/direct_link_precedence_with_different_content_ids_spec.rb @@ -2,23 +2,25 @@ GraphqlLinkExpansionPrecedenceHelpers::DirectLinks::TestCaseFactory .all(target_content_ids_differ: true) .each do |test_case| # rubocop:disable Rails/FindEach - context test_case.source_edition_locale_description do - it test_case.description do - aggregate_failures do - if test_case.graphql_titles != test_case.content_store_titles && - test_case.invalid_edition_and_valid_link_set_linked_editions? - # this is a known diff between Content Store and GraphQL so - # we're just checking that the GraphQL result is 'correct' and - # not that it matches Content Store + context test_case.with_drafts_description do + context test_case.source_edition_locale_description do + it test_case.description do + aggregate_failures do + if test_case.graphql_titles != test_case.content_store_titles && + test_case.invalid_edition_and_valid_link_set_linked_editions? + # this is a known diff between Content Store and GraphQL so + # we're just checking that the GraphQL result is 'correct' and + # not that it matches Content Store - expect(test_case.content_store_titles.size).to be(0) - expect(test_case.graphql_titles.size).to be(1) - expect(test_case.graphql_titles.first).to match(/link_set/) - else - expect(test_case.graphql_titles).to eq(test_case.content_store_titles) + expect(test_case.content_store_titles.size).to be(0) + expect(test_case.graphql_titles.size).to be(1) + expect(test_case.graphql_titles.first).to match(/link_set/) + else + expect(test_case.graphql_titles).to eq(test_case.content_store_titles) + end end end end end - end + end end diff --git a/spec/integration/graphql/link_expansion/direct_link_precedence_with_same_content_ids_spec.rb b/spec/integration/graphql/link_expansion/direct_link_precedence_with_same_content_ids_spec.rb index 294d8be3f2..0e9e47fc7c 100644 --- a/spec/integration/graphql/link_expansion/direct_link_precedence_with_same_content_ids_spec.rb +++ b/spec/integration/graphql/link_expansion/direct_link_precedence_with_same_content_ids_spec.rb @@ -2,14 +2,16 @@ GraphqlLinkExpansionPrecedenceHelpers::DirectLinks::TestCaseFactory .all(target_content_ids_differ: false) .each do |test_case| # rubocop:disable Rails/FindEach - context test_case.source_edition_locale_description do - it test_case.description do - aggregate_failures do - expect(test_case.graphql_titles).to eq(test_case.content_store_titles) - expect(test_case.content_store_titles.size).to be <= 1 - expect(test_case.graphql_titles.size).to be <= 1 + context test_case.with_drafts_description do + context test_case.source_edition_locale_description do + it test_case.description do + aggregate_failures do + expect(test_case.graphql_titles).to eq(test_case.content_store_titles) + expect(test_case.content_store_titles.size).to be <= 1 + expect(test_case.graphql_titles.size).to be <= 1 + end end end end - end + end end diff --git a/spec/integration/graphql/link_expansion/reverse_link_inclusion_spec.rb b/spec/integration/graphql/link_expansion/reverse_link_inclusion_spec.rb index 4ddef10da9..f7747bf578 100644 --- a/spec/integration/graphql/link_expansion/reverse_link_inclusion_spec.rb +++ b/spec/integration/graphql/link_expansion/reverse_link_inclusion_spec.rb @@ -11,8 +11,8 @@ def for_graphql(target_edition, link_type:, with_drafts:) GraphQL::Dataloader.with_dataloading do |dataloader| request = dataloader.with( Sources::ReverseLinkedToEditionsSource, - content_store: with_drafts ? "draft" : "live", locale: target_edition.locale, + with_drafts:, ).request([target_edition, link_type]) request.load @@ -60,9 +60,6 @@ def for_graphql(target_edition, link_type:, with_drafts:) end %w[content_store graphql].each do |destination| - # GraphQL doesn't yet support drafts - next if destination == "graphql" && test_case.with_drafts? - # GraphQL will only attempt to find a reverse link for a field that is declared # as a reverse_links_field in app/graphql/types/edition_type.rb. This test # calls the dataloader directly, but the dataloader won't check that the diff --git a/spec/integration/graphql/link_expansion/reverse_link_precedence_with_different_content_ids_spec.rb b/spec/integration/graphql/link_expansion/reverse_link_precedence_with_different_content_ids_spec.rb index 27363e0d5b..26e19dfee8 100644 --- a/spec/integration/graphql/link_expansion/reverse_link_precedence_with_different_content_ids_spec.rb +++ b/spec/integration/graphql/link_expansion/reverse_link_precedence_with_different_content_ids_spec.rb @@ -2,28 +2,30 @@ GraphqlLinkExpansionPrecedenceHelpers::ReverseLinks::TestCaseFactory .all(source_content_ids_differ: true) .each do |test_case| # rubocop:disable Rails/FindEach - context test_case.linked_edition_locale_description do - it test_case.description do - aggregate_failures do - if test_case.graphql_titles != test_case.content_store_titles && - test_case.invalid_edition_and_valid_link_set_linking_source_editions? - # this is a known diff between Content Store and GraphQL so - # we're just checking that the GraphQL result is 'correct' and - # not that it matches Content Store + context test_case.with_drafts_description do + context test_case.linked_edition_locale_description do + it test_case.description do + aggregate_failures do + if test_case.graphql_titles != test_case.content_store_titles && + test_case.invalid_edition_and_valid_link_set_linking_source_editions? + # this is a known diff between Content Store and GraphQL so + # we're just checking that the GraphQL result is 'correct' and + # not that it matches Content Store - expect(test_case.content_store_titles.size).to be(0) - expect(test_case.graphql_titles.size).to be(1) - expect(test_case.graphql_titles.first).to match(/link_set/) - elsif test_case.graphql_titles != test_case.content_store_titles && - test_case.valid_edition_and_link_set_linking_editions? - # this is a known diff between Content Store and GraphQL so - # we're just checking that the results match our expectations + expect(test_case.content_store_titles.size).to be(0) + expect(test_case.graphql_titles.size).to be(1) + expect(test_case.graphql_titles.first).to match(/link_set/) + elsif test_case.graphql_titles != test_case.content_store_titles && + test_case.valid_edition_and_link_set_linking_editions? + # this is a known diff between Content Store and GraphQL so + # we're just checking that the results match our expectations - expect(test_case.content_store_titles.size).to be(1) - expect(test_case.content_store_titles.first).to match(/edition/) - expect(test_case.graphql_titles.size).to be(2) - else - expect(test_case.graphql_titles).to eq(test_case.content_store_titles) + expect(test_case.content_store_titles.size).to be(1) + expect(test_case.content_store_titles.first).to match(/edition/) + expect(test_case.graphql_titles.size).to be(2) + else + expect(test_case.graphql_titles).to eq(test_case.content_store_titles) + end end end end diff --git a/spec/integration/graphql/link_expansion/reverse_link_precedence_with_same_content_ids_spec.rb b/spec/integration/graphql/link_expansion/reverse_link_precedence_with_same_content_ids_spec.rb index 1e0e4809c0..cc9bfe6ca9 100644 --- a/spec/integration/graphql/link_expansion/reverse_link_precedence_with_same_content_ids_spec.rb +++ b/spec/integration/graphql/link_expansion/reverse_link_precedence_with_same_content_ids_spec.rb @@ -2,35 +2,37 @@ GraphqlLinkExpansionPrecedenceHelpers::ReverseLinks::TestCaseFactory .all(source_content_ids_differ: false) .each do |test_case| # rubocop:disable Rails/FindEach - context test_case.linked_edition_locale_description do - it test_case.description do - aggregate_failures do - if test_case.graphql_titles != test_case.content_store_titles && - test_case.invalid_root_locale_and_valid_default_locale_edition_linking_editions? - # this is a known diff between Content Store and GraphQL so - # we're just checking that the results match our expectations + context test_case.with_drafts_description do + context test_case.linked_edition_locale_description do + it test_case.description do + aggregate_failures do + if test_case.graphql_titles != test_case.content_store_titles && + test_case.invalid_root_locale_and_valid_default_locale_edition_linking_editions? + # this is a known diff between Content Store and GraphQL so + # we're just checking that the results match our expectations - expect(test_case.content_store_titles.size).to eq(1) - expect(test_case.content_store_result.first[:locale]) - .to eq(Edition::DEFAULT_LOCALE) - expect(test_case.graphql_titles.size).to eq(0) - elsif test_case.graphql_titles != test_case.content_store_titles && - test_case.valid_published_default_locale_and_unpublished_differing_root_locale_edition_linking_editions? - # this is a known diff between Content Store and GraphQL so - # we're just checking that the results match our expectations + expect(test_case.content_store_titles.size).to eq(1) + expect(test_case.content_store_result.first[:locale]) + .to eq(Edition::DEFAULT_LOCALE) + expect(test_case.graphql_titles.size).to eq(0) + elsif test_case.graphql_titles != test_case.content_store_titles && + test_case.valid_published_default_locale_and_unpublished_differing_root_locale_edition_linking_editions? + # this is a known diff between Content Store and GraphQL so + # we're just checking that the results match our expectations - expect(test_case.content_store_titles.size).to eq(1) - expect(test_case.content_store_result.first[:locale]) - .to eq(Edition::DEFAULT_LOCALE) - expect(test_case.graphql_titles.size).to eq(1) - test_case.graphql_result.first.then do |edition| - expect(edition.state).to eq("unpublished") - expect(edition.locale).not_to eq(Edition::DEFAULT_LOCALE) + expect(test_case.content_store_titles.size).to eq(1) + expect(test_case.content_store_result.first[:locale]) + .to eq(Edition::DEFAULT_LOCALE) + expect(test_case.graphql_titles.size).to eq(1) + test_case.graphql_result.first.then do |edition| + expect(edition.state).to eq("unpublished") + expect(edition.locale).not_to eq(Edition::DEFAULT_LOCALE) + end + else + expect(test_case.graphql_titles).to eq(test_case.content_store_titles) + expect(test_case.content_store_titles.size).to be <= 1 + expect(test_case.graphql_titles.size).to be <= 1 end - else - expect(test_case.graphql_titles).to eq(test_case.content_store_titles) - expect(test_case.content_store_titles.size).to be <= 1 - expect(test_case.graphql_titles.size).to be <= 1 end end end diff --git a/spec/integration/graphql/news_article_spec.rb b/spec/integration/graphql/news_article_spec.rb index 23b3367c32..b1f4074370 100644 --- a/spec/integration/graphql/news_article_spec.rb +++ b/spec/integration/graphql/news_article_spec.rb @@ -105,7 +105,6 @@ { edition( base_path: "/government/news/announcement", - content_store: "live", ) { ... on Edition { base_path diff --git a/spec/integration/put_content/content_with_a_previous_draft_spec.rb b/spec/integration/put_content/content_with_a_previous_draft_spec.rb index dd5db7ee6f..b3105da003 100644 --- a/spec/integration/put_content/content_with_a_previous_draft_spec.rb +++ b/spec/integration/put_content/content_with_a_previous_draft_spec.rb @@ -21,6 +21,7 @@ title: "Old Title", publishing_app: "publisher", update_type: "major", + user_facing_version: 1, ) end diff --git a/spec/lib/tasks/data_hygiene_spec.rb b/spec/lib/tasks/data_hygiene_spec.rb index 9a5cd26fe1..5ea0513cf2 100644 --- a/spec/lib/tasks/data_hygiene_spec.rb +++ b/spec/lib/tasks/data_hygiene_spec.rb @@ -16,8 +16,8 @@ context "and when a draft is present" do before do - create(:edition, document:).publish - create(:edition, document:, user_facing_version: 2) + create(:live_edition, document:) + create(:draft_edition, document:) end it "runs the process to discard a draft with the locale" do diff --git a/spec/presenters/queries/content_item_presenter_spec.rb b/spec/presenters/queries/content_item_presenter_spec.rb index 5f0239337c..d9a4a96abc 100644 --- a/spec/presenters/queries/content_item_presenter_spec.rb +++ b/spec/presenters/queries/content_item_presenter_spec.rb @@ -18,6 +18,7 @@ first_published_at:, public_updated_at:, auth_bypass_ids: [SecureRandom.uuid], + user_facing_version: 1, ) end @@ -120,6 +121,7 @@ update_type: "major", first_published_at:, public_updated_at:, + user_facing_version: 1, ) end diff --git a/spec/services/edition_finder_service_spec.rb b/spec/services/edition_finder_service_spec.rb index 0ff3eec3ad..e12009b46e 100644 --- a/spec/services/edition_finder_service_spec.rb +++ b/spec/services/edition_finder_service_spec.rb @@ -10,11 +10,11 @@ end before do - @edition = create(:live_edition, base_path:, routes:, redirects:) + @live = @edition = create(:live_edition, base_path:, routes:, redirects:) end describe ".find" do - subject { described_class.new(request_path, "live").find } + subject { described_class.new(request_path).find } context "when there isn't an item matching the path" do let(:request_path) { "/path" } @@ -22,10 +22,58 @@ it { is_expected.to be_nil } end - context "when there is a base_path that matches the path" do + context "when there are base_paths that match the path" do let(:request_path) { "/base-path" } - it { is_expected.to eq @edition } + context "with_drafts=true" do + subject { described_class.new(request_path, with_drafts: true).find } + + context "when there are both draft and live base_path matches" do + before do + @draft = create(:draft_edition, base_path:, routes:, redirects:) + end + + it { is_expected.to eq @draft } + end + + context "when there's only a draft base_path match" do + before do + @live.destroy! + + @draft = create(:draft_edition, base_path:, routes:, redirects:) + end + + it { is_expected.to eq @draft } + end + + context "when there's only a live base_path match" do + it { is_expected.to eq @live } + end + end + + context "with_drafts=false" do + context "when there are both draft and live base_path matches" do + before do + @draft = create(:draft_edition, base_path:, routes:, redirects:) + end + + it { is_expected.to eq @live } + end + + context "when there's only a draft base_path match" do + before do + @live.destroy! + + @draft = create(:draft_edition, base_path:, routes:, redirects:) + end + + it { is_expected.to be_nil } + end + + context "when there's only a live base_path match" do + it { is_expected.to eq @live } + end + end end context "when there is a matching exact route for the path" do diff --git a/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case.rb b/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case.rb index 3194571bff..6f2a587e95 100644 --- a/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case.rb +++ b/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case.rb @@ -4,10 +4,12 @@ class TestCase include FactoryBot::Syntax::Methods def initialize( + with_drafts:, root_locale:, linked_editions:, target_content_ids_differ: ) + @with_drafts = with_drafts @root_locale = root_locale @linked_editions_input = linked_editions @target_content_ids_differ = target_content_ids_differ @@ -15,7 +17,7 @@ def initialize( def content_store_titles @content_store_titles ||= Presenters::Queries::ExpandedLinkSet - .by_edition(source_edition, with_drafts: false) + .by_edition(source_edition, with_drafts:) .links .fetch(link_type.to_sym, []) .map { it[:title] } @@ -25,7 +27,7 @@ def graphql_titles @graphql_titles ||= GraphQL::Dataloader.with_dataloading do |dataloader| request = dataloader.with( Sources::LinkedToEditionsSource, - content_store: "live", + with_drafts:, locale: root_locale, ).request([source_edition, link_type]) @@ -48,9 +50,13 @@ def source_edition_locale_description "when the source edition's locale is \"#{root_locale}\"" end + def with_drafts_description + "when #{with_drafts ? 'accepting' : 'rejecting'} drafts" + end + private - attr_reader :root_locale, :linked_editions_input, :target_content_ids_differ + attr_reader :with_drafts, :root_locale, :linked_editions_input, :target_content_ids_differ def source_edition @source_edition ||= create( @@ -102,6 +108,7 @@ def valid_linked_edition_of_kind?(kind) linked_editions[kind].any? do |edition| next if Edition::NON_RENDERABLE_FORMATS.include?(edition.document_type) next unless [Edition::DEFAULT_LOCALE, root_locale].include?(edition.locale) + next if edition.draft? && !with_drafts if edition.unpublished? next unless edition.withdrawn? diff --git a/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case_factory.rb b/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case_factory.rb index 4643fc3e6e..20fce01525 100644 --- a/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case_factory.rb +++ b/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_case_factory.rb @@ -4,8 +4,10 @@ class TestCaseFactory class << self def all(target_content_ids_differ:) query_values = [ - { root_locale: Edition::DEFAULT_LOCALE }, - { root_locale: "fr" }, + { with_drafts: true, root_locale: Edition::DEFAULT_LOCALE }, + { with_drafts: true, root_locale: "fr" }, + { with_drafts: false, root_locale: Edition::DEFAULT_LOCALE }, + { with_drafts: false, root_locale: "fr" }, ] link_kind_values = %w[link_set edition] diff --git a/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_linked_edition.rb b/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_linked_edition.rb index 348dd827df..a0b8008b8e 100644 --- a/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_linked_edition.rb +++ b/spec/support/graphql_link_expansion_precedence_helpers/direct_links/test_linked_edition.rb @@ -22,7 +22,7 @@ def initialize( def call Edition.find_by(state:, document:) || create( - :live_edition, + state == "draft" ? :edition : :live_edition, title: "edition #{Edition.count} (#{link_kind})", state:, document_type:, diff --git a/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case.rb b/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case.rb index 54d2adfbde..c2c83e1063 100644 --- a/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case.rb +++ b/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case.rb @@ -4,10 +4,12 @@ class TestCase include FactoryBot::Syntax::Methods def initialize( + with_drafts:, root_locale:, source_editions:, source_content_ids_differ: ) + @with_drafts = with_drafts @root_locale = root_locale @source_editions_input = source_editions @source_content_ids_differ = source_content_ids_differ @@ -18,7 +20,7 @@ def content_store_result source_editions Presenters::Queries::ExpandedLinkSet - .by_edition(linked_edition, with_drafts: false) + .by_edition(linked_edition, with_drafts:) .links .fetch(ExpansionRules.reverse_link_type(link_type), []) end @@ -31,7 +33,7 @@ def graphql_result GraphQL::Dataloader.with_dataloading do |dataloader| request = dataloader.with( Sources::ReverseLinkedToEditionsSource, - content_store: "live", + with_drafts:, locale: root_locale, ).request([linked_edition, link_type]) @@ -90,9 +92,13 @@ def linked_edition_locale_description "when the linked (root) edition's locale is \"#{root_locale}\"" end + def with_drafts_description + "when #{with_drafts ? 'accepting' : 'rejecting'} drafts" + end + private - attr_reader :root_locale, :source_editions_input, :source_content_ids_differ + attr_reader :with_drafts, :root_locale, :source_editions_input, :source_content_ids_differ def linked_edition @linked_edition ||= create( @@ -173,6 +179,7 @@ def valid_edition_linking_source_edition_of_locale?(locale) def valid_edition?(edition) return false if Edition::NON_RENDERABLE_FORMATS.include?(edition.document_type) return false unless [Edition::DEFAULT_LOCALE, root_locale].include?(edition.locale) + return false if edition.draft? && !with_drafts if edition.unpublished? return false unless edition.withdrawn? diff --git a/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case_factory.rb b/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case_factory.rb index 10f40d1652..d4d1a11e5c 100644 --- a/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case_factory.rb +++ b/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_case_factory.rb @@ -4,8 +4,10 @@ class TestCaseFactory class << self def all(source_content_ids_differ:) query_values = [ - { root_locale: Edition::DEFAULT_LOCALE }, - { root_locale: "fr" }, + { with_drafts: true, root_locale: Edition::DEFAULT_LOCALE }, + { with_drafts: true, root_locale: "fr" }, + { with_drafts: false, root_locale: Edition::DEFAULT_LOCALE }, + { with_drafts: false, root_locale: "fr" }, ] link_kind_values = %w[link_set edition] diff --git a/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_source_edition_factory.rb b/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_source_edition_factory.rb index f514255799..0fc8685c79 100644 --- a/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_source_edition_factory.rb +++ b/spec/support/graphql_link_expansion_precedence_helpers/reverse_links/test_source_edition_factory.rb @@ -22,7 +22,7 @@ def initialize( def call Edition.find_by(state:, document:) || create( - :live_edition, + state == "draft" ? :edition : :live_edition, title: "edition #{Edition.count} (#{link_kind})", state:, document_type:,