module Eco module API module Organization class PresetsFactory ABILITIES = File.join(__dir__, 'presets_values.json') DEFAULT_CUSTOM = 'presets_custom.json' DEFAULT_MAP = 'presets_map.json' def initialize(presets_custom: DEFAULT_CUSTOM, presets_map: DEFAULT_MAP, enviro: nil, policy_groups: nil) @abilities = JSON.load(File.open(ABILITIES)) @habilities = @abilities.map do |key, values| h_values = values.map { |v| [v, true] }.to_h [key, h_values] end.to_h fatal("Expecting Environment object. Given: #{enviro}") if enviro && !enviro.is_a?(Eco::API::Common::Session::Environment) @enviro = enviro policy_groups = policy_groups || @enviro&.api&.policy_groups.to_a if policy_groups.is_a?(Eco::API::Organization::PolicyGroups) @policy_groups = policy_groups else @policy_groups = Eco::API::Organization::PolicyGroups.new(policy_groups) end init_custom(presets_custom) init_map(presets_map) end def new(*policy_group_ids_or_names) names = policy_group_ids_or_names.map do |id_name| @policy_groups.to_name(id_name)&.downcase end.compact if @presets_map preset_names = names.map { |name| @presets_map.fetch(name, nil) } else # option to do not use preset mapping (so just the policy group name) preset_names = names end compile(*preset_names) end # @return [Array] all the abilities def keys @abilities.keys end private def init_custom(file = DEFAULT_CUSTOM) @presets_custom = nil return if !file file = File.expand_path(file) if File.exists?(file) @presets_custom = JSON.load(File.open(file)) errors = @presets_custom.map do |key, preset| (err = preset_errors(preset)) ? "{ '#{key}' preset -> #{err}}": nil end.compact fatal("File '#{file}' contains invalid presets:\n #{errors.join("\n ")}") if errors.length > 0 end end def init_map(file = DEFAULT_MAP) @presets_map = nil return if !file file = File.expand_path(file) if File.exists?(file) fatal("Maps file specified without custom presets file. Aborting!") if !@presets_custom @presets_map = JSON.load(File.open(file)) errors = [] if @policy_groups.length > 0 errors = @policy_groups.map do |pg| exists = @presets_map[pg.name.downcase] || @presets_custom[pg.name.downcase] exists ? nil : "'#{pg.name}'" end.compact warn("No maps or no preset for policy group(s): #{errors.join(", ")}") if errors.length > 0 end errors = @presets_map.map do |source, dest| @presets_custom[dest] ? nil : "'#{dest}'" end.compact warn("Unexisting mapped preset(s): #{errors.uniq.join(", ")}") if errors.length > 0 end end def fatal(msg) raise msg if !@enviro @enviro.logger.fatal(msg) raise msg end def warn(msg) raise msg if !@enviro @enviro.logger.warn(msg) end def compile(*preset_names) fatal("You need to specify an existing file for the custom presets.") if !@presets_custom @presets_custom.values_at(*preset_names).compact.reduce({}) do |p1, p2| merge(p1, p2) end end def merge(preset1, preset2) keys = preset1.keys | preset2.keys @abilities.each_with_object({}) do |(key, values), result| next unless keys.include?(key) idx = [ values.index(preset1[key]), values.index(preset2[key]) ].compact.max result[key] = idx && values[idx] end end # unsused: only play with the given abilities def empty_model JSON.parse(@abilities.to_json).transform_values {|v| nil } end def preset_errors(preset) return "No preset given" if !preset errors = preset.map do |k, v| @habilities.dig(k, v) ? nil : "#{k}:#{v}" end.compact return " unknown: {#{errors.join(", ")}}" if errors.length > 0 nil end end end end end