diff --git a/app/controllers/pageflow/entries_controller.rb b/app/controllers/pageflow/entries_controller.rb index aca03922da..570bc0ea4a 100644 --- a/app/controllers/pageflow/entries_controller.rb +++ b/app/controllers/pageflow/entries_controller.rb @@ -85,11 +85,13 @@ def entry_request_scope end def handle_public_entry_request(entry) - return if redirect_according_to_entry_redirect(entry) + config = Pageflow.config_for(entry) + + return if redirect_according_to_entry_redirect(entry, config) return if redirect_according_to_public_https_mode return unless check_entry_password_protection(entry) - delegate_to_entry_type_frontend_app!(entry) + delegate_to_entry_type_frontend_app!(entry, config:) end def redirect_according_to_permalink_redirect @@ -107,18 +109,14 @@ def redirect_according_to_permalink_redirect true end - def redirect_according_to_entry_redirect(entry) - return false unless (redirect_location = entry_redirect(entry)) + def redirect_according_to_entry_redirect(entry, config) + return false unless (redirect_location = config.public_entry_redirect.call(entry, request)) redirect_to(redirect_location, status: :moved_permanently, allow_other_host: true) true end - def entry_redirect(entry) - Pageflow.config.public_entry_redirect.call(entry, request) - end - - def delegate_to_entry_type_frontend_app!(entry, override_status: nil) + def delegate_to_entry_type_frontend_app!(entry, config:, override_status: nil) EntriesControllerEnvHelper.add_entry_info_to_env(request.env, entry:, mode: :published, @@ -126,7 +124,6 @@ def delegate_to_entry_type_frontend_app!(entry, override_status: nil) delegate_to_rack_app!(entry.entry_type.frontend_app) do |result| status, headers, body = result - config = Pageflow.config_for(entry) allow_iframe_for_embed(headers) apply_additional_headers(entry, config, headers) @@ -158,7 +155,9 @@ def render_custom_or_static_404_error_page if site&.custom_404_entry&.published_without_password_protection? entry = PublishedEntry.new(site.custom_404_entry) - delegate_to_entry_type_frontend_app!(entry, override_status: 404) + config = Pageflow.config_for(entry) + + delegate_to_entry_type_frontend_app!(entry, config:, override_status: 404) else # Fallback to ApplicationController's handler method render_static_404_error_page diff --git a/lib/pageflow/configuration.rb b/lib/pageflow/configuration.rb index 21d3cc0392..073c4920cb 100644 --- a/lib/pageflow/configuration.rb +++ b/lib/pageflow/configuration.rb @@ -733,6 +733,7 @@ def enable_all_features delegate :additional_public_entry_headers, to: :config delegate :cutoff_modes, to: :config delegate :entry_translator_url=, to: :config + delegate :public_entry_redirect=, to: :config delegate :public_entry_url_options=, to: :config delegate :for_entry_type, to: :config diff --git a/spec/requests/pageflow/entries_index_request_spec.rb b/spec/requests/pageflow/entries_index_request_spec.rb index 2268c2cb55..68948b8b4d 100644 --- a/spec/requests/pageflow/entries_index_request_spec.rb +++ b/spec/requests/pageflow/entries_index_request_spec.rb @@ -106,6 +106,10 @@ module Pageflow describe 'with configured public_entry_redirect' do it 'redirects to returned location' do + pageflow_configure do |config| + config.public_entry_redirect = ->(_, _) { '/some_location' } + end + site = create(:site, cname: 'pageflow.example.com') create(:entry, :published, @@ -113,14 +117,17 @@ module Pageflow type_name: 'test', permalink_attributes: {slug: '', allow_root_path: true}) - Pageflow.config.public_entry_redirect = ->(_, _) { '/some_location' } - get('http://pageflow.example.com/') expect(response).to redirect_to('/some_location') end it 'redirects even before https redirect takes place' do + pageflow_configure do |config| + config.public_https_mode = :enforce + config.public_entry_redirect = ->(_, _) { '/some_location' } + end + site = create(:site, cname: 'pageflow.example.com') create(:entry, :published, @@ -128,15 +135,18 @@ module Pageflow type_name: 'test', permalink_attributes: {slug: '', allow_root_path: true}) - Pageflow.config.public_https_mode = :enforce - Pageflow.config.public_entry_redirect = ->(_, _) { '/some_location' } - get('http://pageflow.example.com/') expect(response).to redirect_to('/some_location') end it 'passes entry and request' do + pageflow_configure do |config| + config.public_entry_redirect = lambda do |passed_entry, request| + "#{request.protocol}#{request.host}/#{passed_entry.slug}" + end + end + site = create(:site, cname: 'pageflow.example.com') entry = create( :entry, @@ -147,16 +157,16 @@ module Pageflow permalink_attributes: {slug: '', allow_root_path: true} ) - Pageflow.config.public_entry_redirect = lambda do |passed_entry, request| - "#{request.protocol}#{request.host}/#{passed_entry.slug}" - end - get('http://pageflow.example.com/') expect(response).to redirect_to("http://pageflow.example.com/#{entry.slug}") end it 'allows redirecting to other host' do + pageflow_configure do |config| + config.public_entry_redirect = ->(_, _) { 'http://www.example.com/' } + end + site = create(:site, cname: 'pageflow.example.com') create(:entry, :published, @@ -164,14 +174,16 @@ module Pageflow type_name: 'test', permalink_attributes: {slug: '', allow_root_path: true}) - Pageflow.config.public_entry_redirect = ->(_, _) { 'http://www.example.com/' } - get('http://pageflow.example.com/') expect(response).to redirect_to('http://www.example.com/') end it 'does not redirect if nil is returned' do + pageflow_configure do |config| + config.public_entry_redirect = ->(_, _) {} + end + site = create(:site, cname: 'pageflow.example.com') create(:entry, :published, @@ -179,8 +191,6 @@ module Pageflow type_name: 'test', permalink_attributes: {slug: '', allow_root_path: true}) - Pageflow.config.public_entry_redirect = ->(_, _) {} - get('http://pageflow.example.com/') expect(response.status).to eq(200) diff --git a/spec/requests/pageflow/entries_show_request_spec.rb b/spec/requests/pageflow/entries_show_request_spec.rb index 9b1297fe2a..508e0077c9 100644 --- a/spec/requests/pageflow/entries_show_request_spec.rb +++ b/spec/requests/pageflow/entries_show_request_spec.rb @@ -60,7 +60,8 @@ module Pageflow get(short_entry_url(entry)) expect(response.status).to eq(200) - expect(response.body).to include('some-entry published embed=false rendered by entry type frontend app') + expect(response.body) + .to include('some-entry published embed=false rendered by entry type frontend app') end it 'passes embed=true for embed requests' do @@ -69,7 +70,8 @@ module Pageflow get(entry_embed_url(entry)) expect(response.status).to eq(200) - expect(response.body).to include('some-entry published embed=true rendered by entry type frontend app') + expect(response.body) + .to include('some-entry published embed=true rendered by entry type frontend app') end it 'supports finding published entry based on permalink' do @@ -237,7 +239,8 @@ module Pageflow get('http://my.example.com/non-existent-entry') expect(response.status).to eq(404) - expect(response.body).to include('Custom 404 published embed=false rendered by entry type frontend app') + expect(response.body) + .to include('Custom 404 published embed=false rendered by entry type frontend app') end it 'falls back to default 404 when site has no custom_404_entry' do @@ -353,63 +356,104 @@ module Pageflow describe 'with configured public_entry_redirect' do it 'redirects to returned location' do + pageflow_configure do |config| + config.public_entry_redirect = ->(_, _) { '/some_location' } + end + entry = create(:entry, :published, type_name: 'test') - Pageflow.config.public_entry_redirect = ->(_, _) { '/some_location' } - get(short_entry_url(entry)) expect(response).to redirect_to('/some_location') end it 'redirects even before https redirect takes place' do + pageflow_configure do |config| + config.public_https_mode = :enforce + config.public_entry_redirect = ->(_, _) { '/some_location' } + end + entry = create(:entry, :published, type_name: 'test') - Pageflow.config.public_https_mode = :enforce - Pageflow.config.public_entry_redirect = ->(_, _) { '/some_location' } - get(short_entry_url(entry)) expect(response).to redirect_to('/some_location') end it 'passes entry and request' do + pageflow_configure do |config| + config.public_entry_redirect = lambda do |passed_entry, request| + "#{request.protocol}#{request.host}/#{passed_entry.slug}" + end + end + create(:entry, :published, title: 'some-entry', type_name: 'test') - Pageflow.config.public_entry_redirect = lambda do |passed_entry, request| - "#{request.protocol}#{request.host}/#{passed_entry.slug}" - end - get('http://www.example.com/some-entry') expect(response).to redirect_to('http://www.example.com/some-entry') end it 'allows redirecting to other host' do + pageflow_configure do |config| + config.public_entry_redirect = ->(_, _) { 'http://www.example.com/' } + end + entry = create(:entry, :published, type_name: 'test') - Pageflow.config.public_entry_redirect = ->(_, _) { 'http://www.example.com/' } - get(short_entry_url(entry), headers: {'HTTP_HOST' => 'pageflow.example.com'}) expect(response).to redirect_to('http://www.example.com/') end it 'does not redirect if nil is returned' do + pageflow_configure do |config| + config.public_entry_redirect = ->(_, _) {} + end + entry = create(:entry, :published, type_name: 'test') - Pageflow.config.public_entry_redirect = ->(_, _) {} + get(short_entry_url(entry)) + + expect(response.status).to eq(200) + end + + it 'does not use redirect from feature flag by default' do + pageflow_configure do |config| + config.features.register('redirect_feature') do |feature_config| + feature_config.public_entry_redirect = ->(_, _) { '/redirected' } + end + end + + entry = create(:entry, :published, + type_name: 'test') get(short_entry_url(entry)) expect(response.status).to eq(200) end + + it 'uses redirect from feature flag if enabled' do + pageflow_configure do |config| + config.features.register('redirect_feature') do |feature_config| + feature_config.public_entry_redirect = ->(_, _) { '/redirected' } + end + end + + entry = create(:entry, :published, + type_name: 'test', + with_feature: 'redirect_feature') + + get(short_entry_url(entry)) + + expect(response).to redirect_to('/redirected') + end end describe 'X-Frame-Options header' do