app/models/miq_user_role.rb
class MiqUserRole < ApplicationRecord
include ReadOnlyMixin
DEFAULT_TENANT_ROLE_NAME = "EvmRole-tenant_administrator"
has_many :entitlements, :dependent => :restrict_with_exception
has_many :miq_groups, :through => :entitlements
has_and_belongs_to_many :miq_product_features, :join_table => :miq_roles_features
virtual_column :vm_restriction, :type => :string
virtual_column :service_template_restriction, :type => :string
validates :name, :presence => true, :uniqueness_when_changed => {:case_sensitive => false}
serialize :settings
default_value_for :read_only, false
FIXTURE_PATH = File.join(FIXTURE_DIR, table_name)
FIXTURE_YAML = "#{FIXTURE_PATH}.yml"
RESTRICTIONS = {
:user => N_('Only User Owned'),
:user_or_group => N_('Only User or Group Owned')
}
def feature_identifiers
@feature_identifiers ||= miq_product_features.pluck(:identifier)
end
# @param identifier [String] Product feature identifier to check if this role allows access to it
# Returns true when requested feature is directly assigned or a descendant of a feature
def allows?(identifier:)
# all features are children of "everything", so checking it isn't strictly necessary
# but it simplifies testing
if feature_identifiers.include?(MiqProductFeature::SUPER_ADMIN_FEATURE) || feature_identifiers.include?(identifier)
true
elsif (parent_identifier = MiqProductFeature.feature_parent(identifier))
allows?(:identifier => parent_identifier)
else
false
end
end
# @param identifiers [Array] Product feature identifiers to check if this role allows access
# to any of them in the given scope.
def allows_any?(identifiers: [])
if identifiers.any? { |i| allows?(:identifier => i) }
true
else
child_idents = identifiers.map { |i| MiqProductFeature.feature_children(i) }.flatten
if child_idents.present?
allows_any?(:identifiers => child_idents)
else
false
end
end
end
def self_service?(klass = nil)
[:user_or_group, :user].include?((settings || {}).fetch_path(:restrictions, restriction_type(klass)))
end
def limited_self_service?(klass = nil)
(settings || {}).fetch_path(:restrictions, restriction_type(klass)) == :user
end
def self.with_roles_excluding(identifier, allowed_ids: nil)
scope = where.not(
:id => MiqUserRole
.unscope(:select)
.joins(:miq_product_features)
.where(:miq_product_features => {:identifier => identifier})
.select(:id)
)
scope = scope.or(where(:id => allowed_ids)) if allowed_ids.present?
scope
end
def self.seed
roles = all.index_by(&:name)
seed_from_array(roles, YAML.load_file(FIXTURE_YAML))
# NOTE: typically there are no extra fixtures (so merge_features is typically false)
Dir.glob(File.join(FIXTURE_PATH, "*.yml")).each do |fixture|
seed_from_array(roles, YAML.load_file(fixture), true)
end
end
def self.seed_from_array(roles, array, merge_features = false)
features = MiqProductFeature.all
array.each do |hash|
feature_ids = hash.delete(:miq_product_feature_identifiers)
hash[:miq_product_features] = features.select { |f| feature_ids.include?(f.identifier) }
role = roles[hash[:name]] ||= new(hash.except(:id))
new_role = role.new_record?
hash[:miq_product_features] &&= role.miq_product_features if !new_role && merge_features
unless role.settings.nil? # Make sure existing settings are merged in with the new ones.
new_settings = hash.delete(:settings) || {}
role.settings.merge!(new_settings)
end
role.attributes = hash.except(:id)
role.save if role.changed?
end
end
virtual_total :group_count, :miq_groups
def vm_restriction
vmr = settings&.dig(:restrictions, :vms)
vmr ? RESTRICTIONS[vmr] : "None"
end
def service_template_restriction
str = settings&.dig(:restrictions, :service_templates)
str ? RESTRICTIONS[str] : "None"
end
def super_admin_user?
allows?(:identifier => MiqProductFeature::SUPER_ADMIN_FEATURE)
end
def tenant_admin_user?
allows?(:identifier => MiqProductFeature::TENANT_ADMIN_FEATURE)
end
def only_my_user_tasks?
!allows?(:identifier => MiqProductFeature::ALL_TASKS_FEATURE) && allows?(:identifier => MiqProductFeature::MY_TASKS_FEATURE)
end
def report_admin_user?
allows?(:identifier => MiqProductFeature::REPORT_ADMIN_FEATURE)
end
def request_admin_user?
allows?(:identifier => MiqProductFeature::REQUEST_ADMIN_FEATURE)
end
def self.default_tenant_role
find_by(:name => DEFAULT_TENANT_ROLE_NAME)
end
def self.display_name(number = 1)
n_('Role', 'Roles', number)
end
private
def restriction_type(klass)
klass ||= Class
if klass <= ServiceTemplate
:service_templates
else
:vms
end
end
end