From 6420cf8747b2edeaa2671303c8715b1997b728f4 Mon Sep 17 00:00:00 2001 From: Thorben <99347625+Thorben-D@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:06:38 +0100 Subject: [PATCH] Fixes #37169 - Managing a Hosts Repository Sets does not behave as expected (#10905) --- .../api/v2/host_subscriptions_controller.rb | 13 ++++++++ .../v2/host_subscriptions_controller_test.rb | 32 ++++++++++++++++++ .../RepositorySetsActions.js | 2 ++ .../RepositorySetsTab/RepositorySetsTab.js | 1 + .../Tabs/__tests__/repositorySetsTab.test.js | 33 +++++++++++++++++++ 5 files changed, 81 insertions(+) diff --git a/app/controllers/katello/api/v2/host_subscriptions_controller.rb b/app/controllers/katello/api/v2/host_subscriptions_controller.rb index 9e36390c838..a80f4cc83e5 100644 --- a/app/controllers/katello/api/v2/host_subscriptions_controller.rb +++ b/app/controllers/katello/api/v2/host_subscriptions_controller.rb @@ -178,6 +178,7 @@ def product_content param :content_overrides_search, Hash, :desc => N_("Content override search parameters") do param_group :search, Api::V2::ApiController param :enabled, :bool, :desc => N_("Set true to override to enabled; Set false to override to disabled.'"), :required => false + param :limit_to_env, :bool, :desc => N_("Limit actions to content in the host's environment."), :required => false param :remove, :bool, :desc => N_("Set true to remove an override and reset it to 'default'"), :required => false end def content_override @@ -240,10 +241,22 @@ def action_permission def find_content_overrides if !params.dig(:content_overrides_search, :search).nil? + content_labels = ::Katello::Content.joins(:product_contents) .where("#{Katello::ProductContent.table_name}.product_id": @host.organization.products.subscribable.enabled) .search_for(params[:content_overrides_search][:search]) .pluck(:label) + + if Foreman::Cast.to_bool(params.dig(:content_overrides_search, :limit_to_env)) + env_content = ProductContentFinder.new( + :match_subscription => false, + :match_environment => true, + :consumable => @host.subscription_facet + ).product_content + env_content_labels = ::Katello::Content.find(env_content.pluck(:content_id)).pluck(:label) + content_labels &= env_content_labels + end + @content_overrides = content_labels.map do |label| { content_label: label, value: Foreman::Cast.to_bool(params[:content_overrides_search][:enabled]), diff --git a/test/controllers/api/v2/host_subscriptions_controller_test.rb b/test/controllers/api/v2/host_subscriptions_controller_test.rb index 3e4b74de3ee..dae93e3cc0f 100644 --- a/test/controllers/api/v2/host_subscriptions_controller_test.rb +++ b/test/controllers/api/v2/host_subscriptions_controller_test.rb @@ -241,6 +241,38 @@ def test_find_content_overrides_with_empty_string_search refute_equal result, "wrong" end + def test_find_content_overrides_with_empty_string_search_limited_to_environment + # Create Host with "fedora" and "rhel" as content + content_view = katello_content_views(:library_dev_view) + library = katello_environments(:library) + activation_key = katello_activation_keys(:library_dev_staging_view_key) + host_collection = katello_host_collections(:simple_host_collection) + activation_key.host_collections << host_collection + + host = FactoryBot.create(:host, :with_content, :with_subscription, :content_view => content_view, + :lifecycle_environment => library, :organization => content_view.organization) + + # Get content_id and label of first product of host + products = ::Katello::Content.joins(:product_contents) + .where("#{Katello::ProductContent.table_name}.product_id": host.organization.products.subscribable.enabled) + in_env_id = products.pluck(:content_id)[0] + label = products.pluck(:label)[0] + + # Create fake product with content_id and stub ProductContentFinder + content = FactoryBot.build(:katello_content, label: label, name: label) + pc = [FactoryBot.build(:katello_product_content, content: content, content_id: in_env_id)] + ProductContentFinder.any_instance.stubs(:product_content).returns(pc) + + controller = ::Katello::Api::V2::HostSubscriptionsController.new + controller.params = { :host_id => host.id, :content_overrides_search => { :search => '', :limit_to_env => true} } + controller.instance_variable_set(:@host, host) + controller.send(:find_content_overrides) + + result = controller.instance_variable_get(:@content_overrides) + assert_equal(1, result.length) + assert_equal(label, result[0][:content_label]) + end + def test_content_override_bulk content_overrides = [{:content_label => 'some-content', :value => 1}] expected_content_labels = content_overrides.map { |co| co[:content_label] } diff --git a/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js b/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js index d89103935e6..4fa8aae711f 100644 --- a/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js +++ b/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js @@ -24,6 +24,7 @@ export const setContentOverrides = ({ hostId, search, enabled, + limit_to_env: limitToEnv, remove = false, updateResults, singular, @@ -35,6 +36,7 @@ export const setContentOverrides = ({ content_overrides_search: { search, enabled, + limit_to_env: limitToEnv, remove, }, }, diff --git a/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js b/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js index b23b9a667b7..63bf52b7dac 100644 --- a/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +++ b/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js @@ -369,6 +369,7 @@ const RepositorySetsTab = () => { hostId, search, enabled, + limit_to_env: toggleGroupState === LIMIT_TO_ENVIRONMENT, remove, updateResults: resp => updateResults(resp), singular: singular || selectedCount === 1, diff --git a/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js b/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js index b76725ca230..f198a1c4155 100644 --- a/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +++ b/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js @@ -367,6 +367,39 @@ test('Can override in bulk', async (done) => { assertNockRequest(scope); assertNockRequest(contentOverrideScope, done); // Pass jest callback to confirm test is done}); }); +test('Can override in bulk when limited to environment', async (done) => { + const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl); + const scope = nockInstance + .get(hostRepositorySets) + .query(limitToEnvQuery) + .reply(200, mockRepoSetData); + const contentOverrideScope = nockInstance + .put(contentOverride, { + content_overrides_search: + { + search: '', + limit_to_env: true, + remove: true, + }, + }) + .reply(200, mockContentOverride); + + const { + getByText, getByLabelText, queryByText, + } = renderWithRedux(, renderOptions()); + + await patientlyWaitFor(() => expect(getByText(firstRepoSet.contentUrl)).toBeInTheDocument()); + getByLabelText('Select all').click(); + const actionMenu = getByLabelText('bulk_actions'); + actionMenu.click(); + const resetToDefault = queryByText('Reset to default'); + expect(resetToDefault).toBeInTheDocument(); + resetToDefault.click(); + + assertNockRequest(autocompleteScope); + assertNockRequest(scope); + assertNockRequest(contentOverrideScope, done); +}); test('Can filter by status', async (done) => { const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);