From 9fc79f708895fe8a24db83308be0863395c97f4e Mon Sep 17 00:00:00 2001 From: Jason Frey Date: Wed, 15 Nov 2023 17:21:11 -0500 Subject: [PATCH] Add my_settings_view to roles --- ...114223004_add_my_settings_view_to_roles.rb | 46 +++++++ ...3004_add_my_settings_view_to_roles_spec.rb | 122 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 db/migrate/20231114223004_add_my_settings_view_to_roles.rb create mode 100644 spec/migrations/20231114223004_add_my_settings_view_to_roles_spec.rb diff --git a/db/migrate/20231114223004_add_my_settings_view_to_roles.rb b/db/migrate/20231114223004_add_my_settings_view_to_roles.rb new file mode 100644 index 00000000..5cfb9dd6 --- /dev/null +++ b/db/migrate/20231114223004_add_my_settings_view_to_roles.rb @@ -0,0 +1,46 @@ +class AddMySettingsViewToRoles < ActiveRecord::Migration[6.1] + class MiqUserRole < ActiveRecord::Base + has_and_belongs_to_many :miq_product_features, :join_table => :miq_roles_features, :class_name => "AddMySettingsViewToRoles::MiqProductFeature" + end + + class MiqProductFeature < ActiveRecord::Base; end + + def up + return unless MiqUserRole.exists?(:read_only => false) + + say_with_time("Adding my_settings_view to custom user roles") do + my_settings_features = MiqProductFeature.where("identifier LIKE ?", "my_settings_%").pluck(:identifier) + my_settings_view = my_settings_id = nil + + roles_with_features(my_settings_features) + .where.not(:id => roles_with_features(%w[my_settings my_settings_view])) + .each do |user_role| + my_settings_id ||= MiqProductFeature.find_by(:identifier => "my_settings").id + + # This migration will likely run before the product feature is seeded so we need to manually insert it otherwise + my_settings_view ||= MiqProductFeature.create_with( + :name => "View", + :description => "View My Settings", + :feature_type => "view", + :protected => false, + :parent_id => my_settings_id, + :hidden => nil, + :tenant_id => nil + ).find_or_create_by( + :identifier => "my_settings_view" + ) + + user_role.miq_product_features << my_settings_view + end + end + end + + private + + # Bring back all custom user roles that have the given feature_identifiers + def roles_with_features(feature_identifiers) + MiqUserRole + .joins(:miq_product_features) + .where(:read_only => false, :miq_product_features => {:identifier => feature_identifiers}) + end +end diff --git a/spec/migrations/20231114223004_add_my_settings_view_to_roles_spec.rb b/spec/migrations/20231114223004_add_my_settings_view_to_roles_spec.rb new file mode 100644 index 00000000..4c2f5d74 --- /dev/null +++ b/spec/migrations/20231114223004_add_my_settings_view_to_roles_spec.rb @@ -0,0 +1,122 @@ +require_migration + +describe AddMySettingsViewToRoles do + migration_context :up do + let(:user_role_stub) { migration_stub(:MiqUserRole) } + let(:product_feature_stub) { migration_stub(:MiqProductFeature) } + + let!(:my_settings_base) { product_feature_stub.create!(:feature_type => "node", :identifier => "my_settings") } + let!(:my_settings_other) { product_feature_stub.create!(:feature_type => "admin", :identifier => "my_settings_visuals", :parent_id => my_settings_base.id) } + + let(:my_settings_view) do + product_feature_stub + .create_with(:feature_type => "view", :identifier => "my_settings_view", :parent_id => my_settings_base.id) + .find_or_create_by(:identifier => "my_settings_view") + end + + let!(:seeded_user_role) { user_role_stub.create!(:miq_product_features => [my_settings_other], :read_only => true) } + + it "does nothing if there aren't any custom user roles" do + migrate + + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + expect(product_feature_stub.where(:identifier => "my_settings_view")).to_not exist + end + + it "updates custom user roles with a my_settings_* feature" do + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_other], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_other, my_settings_view]) + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to exist + expect(product_feature_stub.where(:identifier => "my_settings_view")).to match_array([my_settings_view]) + end + + it "skips custom user roles with the base my_settings feature" do + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_base], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_base]) # unchanged + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to_not exist + end + + it "skips custom user roles with the base my_settings feature and a my_settings_* feature" do # This edge case should not exist, but we handle it anyway + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_base, my_settings_other], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_base, my_settings_other]) # unchanged + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to_not exist + end + + context "when my_settings_view already exists" do + before { my_settings_view } + + it "updates custom user roles with a my_settings_* feature" do + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_other], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_other, my_settings_view]) + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to match_array([my_settings_view]) + end + + it "handles custom user roles with a my_settings_* feature and already have my_settings_view" do + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_other, my_settings_view], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_other, my_settings_view]) # unchanged + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to match_array([my_settings_view]) + end + + it "skips custom user roles with the base my_settings feature" do + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_base], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_base]) # unchanged + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to match_array([my_settings_view]) + end + + it "skips custom user roles with the base my_settings feature and a my_settings_* feature" do # This edge case should not exist, but we handle it anyway + custom_user_role = user_role_stub.create!(:miq_product_features => [my_settings_base, my_settings_other], :read_only => false) + + migrate + + custom_user_role.reload + seeded_user_role.reload + expect(custom_user_role.miq_product_features).to match_array([my_settings_base, my_settings_other]) # unchanged + expect(seeded_user_role.miq_product_features).to match_array([my_settings_other]) # unchanged + + expect(product_feature_stub.where(:identifier => "my_settings_view")).to match_array([my_settings_view]) + end + end + end +end