lib/eco/api/organization/presets_factory.rb in eco-helpers-2.0.13 vs lib/eco/api/organization/presets_factory.rb in eco-helpers-2.0.14
- old
+ new
@@ -2,145 +2,208 @@
module API
module Organization
class PresetsFactory
ABILITIES = File.join(__dir__, 'presets_values.json')
+ INTEGRITY = File.join(__dir__, 'presets_integrity.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
+ @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)
+ @policy_groups = policy_groups
+ @presets_custom_file = presets_custom || DEFAULT_CUSTOM
+ @presets_map_file = presets_map || DEFAULT_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
+ policy_groups.to_name(id_name)&.downcase
end.compact
- if @presets_map
- preset_names = names.map { |name| @presets_map.fetch(name, nil) }
+ 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<String>] all the abilities
def keys
- @abilities.keys
+ abilities_model.keys
end
private
- def init_custom(file = DEFAULT_CUSTOM)
- @presets_custom = nil
+ 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
- return if !file
- file = File.expand_path(file)
+ def merge(preset1, preset2)
+ keys = preset1.keys | preset2.keys
- 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
+ abilities_model.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_model.to_json).transform_values {|v| nil }
end
- def init_map(file = DEFAULT_MAP)
- @presets_map = nil
+ def preset_errors(preset)
+ return "No preset given" if !preset
+ errors = preset.map do |k, v|
+ value_exists?(k, v) ? nil : "#{k}:#{v}"
+ end.compact
+ return " Unknown: {#{errors.join(", ")}}" if errors.length > 0
+ nil
+ end
- return if !file
- file = File.expand_path(file)
+ def preset_integrity(preset)
+ preset.each_with_object([]) do |(ability, value), errors|
+ next unless checks = integrity_model[ability]
- if File.exists?(file)
- fatal("Maps file specified without custom presets file. Aborting!") if !@presets_custom
- @presets_map = JSON.load(File.open(file))
+ suberrors = []
- 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
+ checks.each do |check|
+ next unless check["value"] == value
+ check["conditions"].each do |cond, targets|
+ case cond
+ when "at_least"
+ targets.each do |other, minimum|
+ unless (ability_value_idx(other, minimum) <= ability_value_idx(other, preset[other]))
+ suberrors << "'#{other}' should be at least '#{minimum}'"
+ end
+ end
+ when "one_of"
+ unless targets.any? {|other, expected| preset[other] == expected}
+ suberrors << targets.each_with_object([]) do |(other, expected), out|
+ out << "'#{other}': '#{expected}'"
+ end.join(", ").yield_self do |msg|
+ "there should be at least one of: {#{msg}}"
+ end
+ end
+ else
+ warn("Unsuported integrity condition statement '#{cond}' in '#{ability}' with level '#{value}'")
+ end
+ end
+ end
- warn("No maps or no preset for policy group(s): #{errors.join(", ")}") if errors.length > 0
+ if suberrors.length > 0
+ errors << "Incorrect value '#{value}' for '#{ability}' - reasons: {#{suberrors.join(", ")}}"
end
+ end.yield_self do |errors|
+ " Integrity errors: { #{errors.join(", ")} }" if errors.length > 0
+ end
+ end
- errors = @presets_map.map do |source, dest|
- @presets_custom[dest] ? nil : "'#{dest}'"
- end.compact
+ def integrity_model
+ @integrity_model ||= JSON.load(File.open(INTEGRITY))
+ end
- warn("Unexisting mapped preset(s): #{errors.uniq.join(", ")}") if errors.length > 0
+ def value_exists?(ability, value)
+ abilities_model_inverted.dig(ability, value)
+ end
+
+ def abilities_model_inverted
+ @abilities_model_inverted ||= abilities_model.each_with_object({}) do |(key, values), out|
+ out[key] = values.each_with_object({}) {|v, h| h[v] = true }
end
+ end
+ def ability_value_idx(ability, value)
+ abilities_model[ability].index(value)
end
- def fatal(msg)
- raise msg if !@enviro
- @enviro.logger.fatal(msg)
- raise msg
+ def abilities_model
+ @abilities_model ||= JSON.load(File.open(ABILITIES))
end
- def warn(msg)
- raise msg if !@enviro
- @enviro.logger.warn(msg)
+ def policy_groups
+ return @policy_groups if @policy_groups.is_a?(Eco::API::Organization::PolicyGroups)
+ @policy_groups ||= @enviro&.api&.policy_groups.to_a
+
+ unless @policy_groups.is_a?(Eco::API::Organization::PolicyGroups)
+ @policy_groups = Eco::API::Organization::PolicyGroups.new(@policy_groups)
+ end
+ @policy_groups
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)
+ def presets_custom
+ return @presets_custom if instance_variable_defined?(:@presets_custom)
+ @presets_custom = nil
+ if @presets_custom_file
+ if (file = File.expand_path(@presets_custom_file)) && File.exists?(file)
+ @presets_custom = JSON.load(File.open(file)).tap do |custom_presets|
+ errors = custom_presets.each_with_object([]) do |(key, preset), errors|
+ if err = preset_errors(preset)
+ errors << "{ '#{key}' preset -> #{err}}"
+ end
+ if err = preset_integrity(preset)
+ errors << "{ '#{key}' preset -> #{err}}"
+ end
+ end
+
+ fatal("File '#{file}' contains invalid presets:\n #{errors.join("\n ")}") if errors.length > 0
+ end
+ end
end
end
- def merge(preset1, preset2)
- keys = preset1.keys | preset2.keys
+ def presets_map
+ return @presets_map if instance_variable_defined?(:@presets_map)
+ @presets_map = nil
+ if @presets_map_file
+ if (file = File.expand_path(@presets_map_file)) && File.exists?(file)
+ fatal("Maps file specified without 'presets_custom.json' file. Aborting!") if !presets_custom
+ @presets_map = JSON.load(File.open(file)).tap do |map_presets|
- @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]
+ errors = []
+ if policy_groups.length > 0
+ errors = policy_groups.map do |pg|
+ exists = map_presets[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 = map_presets.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
end
end
- # unsused: only play with the given abilities
- def empty_model
- JSON.parse(@abilities.to_json).transform_values {|v| nil }
+ def fatal(msg)
+ raise msg if !@enviro
+ @enviro.logger.fatal(msg)
+ raise msg
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
+ def warn(msg)
+ raise msg if !@enviro
+ @enviro.logger.warn(msg)
end
+
end
end
end
end