eco-helpers 2.0.15 → 2.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ea76fb273e572c873b2f23348c54b56fd4e51cd39d9bf1109ddbc4594ba260f
4
- data.tar.gz: 56d64b1eb28202f4bd18997ff8854fdd6ae36c758217796f4739012f59d4ef5c
3
+ metadata.gz: 669f1a3e8d49a2499b02d925386477a8e52cc633c830072420484edcf8e4919d
4
+ data.tar.gz: 86b36286a089bfa03d3cb17d4c17648a4dcc5f1ed07145ee81565cd19d102c90
5
5
  SHA512:
6
- metadata.gz: bf49254f9b3f162f278d65f734fba3d3f683906cb1202df4d4cc4f7a90f2d663655e5168cf5bdea13d78b63d8ece32bcd22541655b001f3a9bfad429d89d2de8
7
- data.tar.gz: 3dcd85969e34079aa050546e427ebe0d28cb7ec358b121f066cd603af23c9c44bb05551ce8db061f1721832981c2b74c1a46aa095c031f9ea0fb8b29b1b65310
6
+ metadata.gz: 0a346a01757374cc004c12b5aadadf6b3c1daebba937c8d1c0cf597608297ab825d604af3a7f70f92528e28e0f009fd482abd31eb660c4abcf9d9796f55f69db
7
+ data.tar.gz: f912a967dfb21cb0e455b357c9f5ca28fae4de55cbacd060fd000add64992b86168a3ed38150d1ddaf9a264245da582a49c434d62d24bc28285d82b3f9a2e693
data/CHANGELOG.md CHANGED
@@ -1,12 +1,25 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [2.0.15] - 2021-04-xx
4
+ ## [2.0.16] - 2021-04-xx
5
5
 
6
6
  ### Added
7
- - Use case `Eco::API::UseCases::DefaultCases::SupersHierarchy`, invokable via `-supers-hiearchy`
7
+ - Use case `Eco::API::UseCases::DefaultCases::SupersCyclicIdentify`, invokable via `-identify-cyclic-supers`
8
+ - Use case `Eco::API::UseCases::DefaultCases::AbstractPolicyGroupAbilities`, invokable via `-abstract-policygroup-abilities`
9
+ - Option to run `one-off` scripts, without org configurations:
10
+ 1. `-api-key INTERNAL_API_KEY`
11
+ 2. `-enviro [live|pre.dev]`
12
+ 3. `-org NAME_OF_ORG`
13
+
8
14
  ### Changed
9
15
  ### Fixed
16
+
17
+
18
+ ## [2.0.15] - 2021-04-29
19
+
20
+ ### Added
21
+ - Use case `Eco::API::UseCases::DefaultCases::SupersHierarchy`, invokable via `-supers-hiearchy`
22
+ ### Fixed
10
23
  - `eco/cli/config/default/workflow.rb` prevent `rescue` looping
11
24
 
12
25
  ## [2.0.14] - 2021-04-15
@@ -17,7 +30,6 @@ All notable changes to this project will be documented in this file.
17
30
  - `Eco::API::Organization::PresetsFactory` added integrity validation for `person_*` abilities
18
31
  - `Eco::API::Session::Batch::Job` more debug info on erron handlers
19
32
 
20
- ### Changed
21
33
  ### Fixed
22
34
  - `Eco::API::Error.get_type` was almost always matching `Eco::API::Error::Unclassified` -> fixed
23
35
 
data/eco-helpers.gemspec CHANGED
@@ -36,5 +36,5 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency 'aws-sdk-ses', '>= 1.36.0', '< 2'
37
37
  spec.add_dependency 'dotenv', '>= 2.7.6', '< 2.8'
38
38
  spec.add_dependency 'net-sftp', '>= 3.0.0', '< 3.1'
39
-
39
+ #spec.add_dependency 'fuzzy_match' '>= 2.1.0', '< 2.2'
40
40
  end
@@ -15,6 +15,7 @@ module Eco
15
15
  # Reorders as follows:
16
16
  # 1. supervisors, people with no supervisor or where their supervisor not present
17
17
  # 2. subordinates
18
+ # @return [Array<Entry>] `values` sorted by supervisors/subordinates
18
19
  def sort_by_supervisors(values, supervisors_first: true)
19
20
  raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
20
21
  return [] unless values && values.is_a?(Enumerable)
@@ -32,6 +33,32 @@ module Eco
32
33
  roam.call(supervisors_tree(values))
33
34
  end
34
35
 
36
+ # Identifies all the cyclic supervisor chains
37
+ # @note as `supervisors_tree` will have any entry involved in a cycle at the top, it just checks all the top entries against their offspring
38
+ # @return [Array<Array>] the sets of entries that are cyclic
39
+ def identify_cyclic_chains(values)
40
+ raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
41
+ return [] unless values && values.is_a?(Enumerable)
42
+
43
+ identify = Proc.new do |top_sup, offspring, chain = [top_sup]|
44
+ next [] if offspring.empty?
45
+ offspring.each_with_object([]) do |(sup, subordinates), set|
46
+ break set unless set.empty?
47
+ if top_sup.supervisor_id == sup.id
48
+ set.concat(chain, [sup])
49
+ else
50
+ set = identify.call(top_sup, subordinates, chain | [sup])
51
+ end
52
+ end
53
+ end
54
+
55
+ supervisors_tree(values).each_with_object([]) do |(top_sup, offspring), sets|
56
+ if (set = identify.call(top_sup, offspring)) && !set.empty?
57
+ sets.push(set)
58
+ end
59
+ end
60
+ end
61
+
35
62
  def tree_to_str(tree, lev: 0)
36
63
  raise "Required Hash tree structure. Given: #{tree.class}" unless tree.is_a?(Hash)
37
64
  "".tap do |str|
@@ -20,8 +20,8 @@ module Eco
20
20
  begin
21
21
  @dir = Eco::Data::Files::Directory.new(value)
22
22
  @dir_path = @dir.create
23
- rescue
24
- logger.error("could not create or make any sense of directory '#{value}'")
23
+ rescue Exception => e
24
+ logger.error("could not create or make any sense of directory '#{value}': #{e.to_s}")
25
25
  end
26
26
  end
27
27
 
@@ -3,6 +3,27 @@ module Eco
3
3
  module Organization
4
4
 
5
5
  class PresetsFactory
6
+
7
+ class << self
8
+
9
+ def all_abilities(hash = {})
10
+ Hash[abilities.each_with_object(nil).to_a].merge(hash)
11
+ end
12
+
13
+ def abilities_model
14
+ @abilities_model ||= JSON.load(File.open(ABILITIES))
15
+ end
16
+
17
+ def integrity_model
18
+ @integrity_model ||= JSON.load(File.open(INTEGRITY))
19
+ end
20
+
21
+ def abilities
22
+ @abilities ||= abilities_model.keys
23
+ end
24
+
25
+ end
26
+
6
27
  ABILITIES = File.join(__dir__, 'presets_values.json')
7
28
  INTEGRITY = File.join(__dir__, 'presets_integrity.json')
8
29
  DEFAULT_CUSTOM = 'presets_custom.json'
@@ -111,7 +132,7 @@ module Eco
111
132
  end
112
133
 
113
134
  def integrity_model
114
- @integrity_model ||= JSON.load(File.open(INTEGRITY))
135
+ self.class.integrity_model
115
136
  end
116
137
 
117
138
  def value_exists?(ability, value)
@@ -129,7 +150,7 @@ module Eco
129
150
  end
130
151
 
131
152
  def abilities_model
132
- @abilities_model ||= JSON.load(File.open(ABILITIES))
153
+ self.class.abilities_model
133
154
  end
134
155
 
135
156
  def policy_groups
@@ -159,6 +159,8 @@ module Eco
159
159
  end
160
160
 
161
161
  def working_directory(mode: nil)
162
+ return files.working_directory if apis.active_api&.one_off?
163
+
162
164
  unless mode
163
165
  wd = files.working_directory
164
166
  return wd unless wd.to_s.strip.empty?
@@ -183,12 +185,21 @@ module Eco
183
185
  end
184
186
 
185
187
  def require(file = nil, match: nil)
186
- if match
187
- file_manager.dir.dir_files(pattern: match).each do |file|
188
- require_relative File.expand_path(file)
188
+ begin
189
+ if match
190
+ file_manager.dir.dir_files(pattern: match).each do |file|
191
+ require_relative File.expand_path(file)
192
+ end
193
+ else
194
+ target = File.expand_path(file_manager.dir.file(file))
195
+ require_relative target
196
+ end
197
+ rescue LoadError => e
198
+ if apis.active_api.one_off?
199
+ pp e.to_s
200
+ else
201
+ raise
189
202
  end
190
- else
191
- require_relative "#{File.expand_path(file_manager.dir.file(file))}"
192
203
  end
193
204
  end
194
205
  # @!endgroup
@@ -83,6 +83,10 @@ module Eco
83
83
  self["name"]
84
84
  end
85
85
 
86
+ def one_off?
87
+ name.is_a?(Symbol)
88
+ end
89
+
86
90
  def key
87
91
  self["key"]
88
92
  end
@@ -40,6 +40,20 @@ module Eco
40
40
  self
41
41
  end
42
42
 
43
+ # Method to support CLI one-off API requests
44
+ def one_off
45
+ if SCR.get_arg("-api-key")
46
+ key = SCR.get_arg("-api-key", with_param: true)
47
+ enviro = SCR.get_arg("-enviro") ? SCR.get_arg("-enviro", with_param: true) : "live"
48
+ host = "#{enviro}.ecoportal.com"
49
+ org = SCR.get_arg("-org") ? SCR.get_arg("-org", with_param: true) : raise("You should specify -org NAME when using -api-key")
50
+ org = org.downcase.split(/[^a-z]+/).join("_")
51
+ org = org.to_sym
52
+ add(org, key: key, host: host)
53
+ return org
54
+ end
55
+ end
56
+
43
57
  def active_api
44
58
  self["active-api"]
45
59
  end
@@ -14,6 +14,13 @@ module Eco
14
14
  end
15
15
 
16
16
  def working_directory
17
+ if config.apis.active_api&.one_off?
18
+ one_off_dir = File.join("one_off", config.apis.active_name.to_s)
19
+ unless full_path = Eco::Data::Files::Directory.new(one_off_dir).create
20
+ raise "Could not create the folder '#{full_path}'"
21
+ end
22
+ self["dir"] = one_off_dir
23
+ end
17
24
  self["dir"]
18
25
  end
19
26
 
@@ -9,7 +9,7 @@ module Eco
9
9
  end
10
10
 
11
11
  def cache
12
- self["cache"]
12
+ self["cache"] ||= "cache/people.json"
13
13
  end
14
14
 
15
15
  def partial_cache
@@ -35,7 +35,7 @@ module Eco
35
35
  end
36
36
 
37
37
  def requests_folder
38
- self["requests_folder"]
38
+ self["requests_folder"] ||= "requests"
39
39
  end
40
40
 
41
41
  # people to exclude from update feeds
@@ -9,6 +9,7 @@ module Eco
9
9
  end
10
10
  end
11
11
 
12
+ require_relative 'default_cases/abstract_policygroup_abilities_case.rb'
12
13
  require_relative 'default_cases/append_usergroups_case'
13
14
  require_relative 'default_cases/change_email_case'
14
15
  require_relative 'default_cases/codes_to_tags_case'
@@ -33,6 +34,7 @@ require_relative 'default_cases/restore_db_case'
33
34
  require_relative 'default_cases/set_default_tag_case'
34
35
  require_relative 'default_cases/set_supervisor_case'
35
36
  require_relative 'default_cases/supers_hierarchy_case'
37
+ require_relative 'default_cases/supers_cyclic_identify_case'
36
38
  require_relative 'default_cases/switch_supervisor_case'
37
39
  require_relative 'default_cases/to_csv_case'
38
40
  require_relative 'default_cases/to_csv_detailed_case'
@@ -0,0 +1,161 @@
1
+ class Eco::API::UseCases::DefaultCases::AbstractPolicyGroupAbilities < Eco::API::Common::Loaders::UseCase
2
+ name "abstract-policygroup-abilities"
3
+ type :export
4
+
5
+ attr_reader :session, :people, :options
6
+
7
+ def main(people, session, options, usecase)
8
+ @session = session; @options = options; @people = people
9
+
10
+ generate_csv!
11
+ exit(0)
12
+ end
13
+
14
+ private
15
+
16
+ def file
17
+ @file ||= options.dig(:output, :file) || "suggested_abilities.csv"
18
+ end
19
+
20
+ def generate_csv!
21
+ policy_groups.each_with_object({}) do |group, data|
22
+ data[group.id] ||= {}
23
+ data[group.id][:name] = group.name
24
+ data[group.id][:suggested] = group_suggestions(group.id)
25
+ data[group.id][:percents] = group_abilities(group.id)
26
+ end.yield_self do |data|
27
+ abilities_list = Eco::API::Organization::PresetsFactory.abilities
28
+ CSV.open(file, "w") do |csv|
29
+ csv << ["Type", "UserGroup", "ID", *abilities_list]
30
+ # Dump the final suggestions
31
+ data.each do |id, meta|
32
+ csv << ["Suggested", meta[:name], id, *meta[:suggested].values_at(*abilities_list)]
33
+ end
34
+ # Dump the percentaged levels of each ability
35
+ data.each do |id, meta|
36
+ analysis = meta[:percents].values_at(*abilities_list).each_with_object([]) do |levels, values|
37
+ values << levels.map do |level, percentil|
38
+ "#{level ? level : "null"} => #{percentil}"
39
+ end.join("\n")
40
+ end
41
+ csv << ["Analysis", meta[:name], id, *analysis]
42
+ end
43
+ end
44
+ puts "Generated file #{file}"
45
+ end
46
+ end
47
+
48
+ def policy_groups
49
+ @policy_groups ||= session.policy_groups
50
+ end
51
+
52
+ # Suggests 1 final set of abilities for a usergroup
53
+ def group_suggestions(id)
54
+ group_abilities(id).each_with_object({}) do |(key, levels), set|
55
+ data = levels.to_a.sort_by(&:last).reverse.first
56
+ set[key] = data ? data.shift : nil
57
+ end
58
+ end
59
+
60
+ # Cleans up each ability's levels by:
61
+ # 1. cutting at some minimum threshold percentage
62
+ # 2. directly selecting those greater than 70%
63
+ def group_abilities(id)
64
+ @group_abilities ||= {}
65
+ @group_abilities[id] ||= ability_levels_percent(id).each_with_object({}) do |(ability, levels), out|
66
+ outstanding = nil
67
+ levels.select do |level, percentil|
68
+ outstanding ||= level if percentil >= 75
69
+ percentil > 15
70
+ end.yield_self do |filtered|
71
+ out[ability] = outstanding ? filtered.slice(outstanding) : filtered
72
+ end
73
+ end
74
+ end
75
+
76
+ # With given the percentages of sets of abilities
77
+ # it abstracts the percentage of each level of each ability
78
+ def ability_levels_percent(id)
79
+ @ability_levels_percent ||= {}
80
+ @ability_levels_percent[id] ||= Eco::API::Organization::PresetsFactory.abilities.each_with_object({}) do |key, out|
81
+ out[key] ||= {}
82
+ ability_sets_percent(id).each_with_object(out[key]) do |(set, percentil), levels|
83
+ levels[set[key]] ||= 0
84
+ levels[set[key]] = (levels[set[key]] + percentil).round(2)
85
+ end
86
+ end
87
+ end
88
+
89
+ # Give a percentage to each set of abilities
90
+ def ability_sets_percent(id)
91
+ @ability_sets_percent ||= {}
92
+ @ability_sets_percent[id] ||= scoped_relevant_raw_data(id).yield_self do |data|
93
+ # Transform ability sets counter to percentage
94
+ total = data[:count]
95
+ abilities = data[:abilities]
96
+ data[:abilities].transform_values do |val|
97
+ percent(val, total)
98
+ end
99
+ end
100
+ end
101
+
102
+ # Get rid of data simingly irrelevant
103
+ def scoped_relevant_raw_data(id)
104
+ sp = single_percent(id)
105
+ sing = single(id); mult = multiple(id)
106
+
107
+ # Scope Relevant Raw Data
108
+ case
109
+ when sp >= 80
110
+ sing
111
+ when sp < 15
112
+ mult
113
+ else # combine
114
+ all_abilities = sing[:abilities].keys | mult[:abilities].keys
115
+ data = {count: sing[:count] + mult[:count], abilities: {}}
116
+ all_abilities.each_with_object(data) do |abilities, merged|
117
+ scount = sing[:abilities][abilities] || 0
118
+ mcount = mult[:abilities][abilities] || 0
119
+ merged[:abilities][abilities] = scount + mcount
120
+ end
121
+ end
122
+ end
123
+
124
+ def single_percent(id)
125
+ percent(single(id)[:count], count(id))
126
+ end
127
+
128
+ def single(id)
129
+ groups_abilities.dig(id, :single) || {count: 0, abilities: {}}
130
+ end
131
+
132
+ def multiple(id)
133
+ groups_abilities.dig(id, :multiple) || {count: 0, abilities: {}}
134
+ end
135
+
136
+ def count(id)
137
+ groups_abilities.dig(id, :count) || 0
138
+ end
139
+
140
+ def groups_abilities
141
+ @groups_abilities ||= people.users.each_with_object({}) do |user, groups|
142
+ abilities = Eco::API::Organization::PresetsFactory.all_abilities(user.account.permissions_custom)
143
+ ids = user.account.policy_group_ids
144
+ category = ids.count > 1 ? :multiple : :single
145
+
146
+ ids.each do |id|
147
+ groups[id] ||= {count: 0}
148
+ groups[id][:count] += 1
149
+ groups[id][category] ||= {count: 0, abilities: {}}
150
+ groups[id][category][:count] += 1
151
+ groups[id][category][:abilities][abilities] ||= 0
152
+ groups[id][category][:abilities][abilities] += 1
153
+ end
154
+ end
155
+ end
156
+
157
+ def percent(num, total)
158
+ (100 * num.to_f / total).round(2)
159
+ end
160
+
161
+ end
@@ -0,0 +1,72 @@
1
+ class Eco::API::UseCases::DefaultCases::SupersCyclicIdentify < Eco::API::Common::Loaders::UseCase
2
+ name "identify-cyclic-supers"
3
+ type :export
4
+
5
+ attr_reader :session, :people, :options
6
+
7
+ def main(people, session, options, usecase)
8
+ @session = session; @options = options; @people = people
9
+
10
+ save!(cyclic_sets)
11
+ exit(0)
12
+ end
13
+
14
+ private
15
+
16
+ def cyclic_sets
17
+ Eco::API::Common::People::SupervisorHelpers.identify_cyclic_chains(people)
18
+ end
19
+
20
+ def file
21
+ @file ||= options.dig(:output, :file) || "cyclic_supers.txt"
22
+ end
23
+
24
+ def save!(data)
25
+ if data.empty?
26
+ session.logger.info("There were no cyclic supervisors identified!!")
27
+ return
28
+ end
29
+
30
+ ext = File.extname(file).downcase.delete(".")
31
+
32
+ File.open(file, "w") do |fd|
33
+ if ext == "txt"
34
+ create_file(data, file: file, format: :txt)
35
+ elsif ext == "html"
36
+ puts "html is still not supported"
37
+ exit(1)
38
+ create_file(data, file: file, format: :html)
39
+ elsif ext == "json"
40
+ puts "json is still not supported"
41
+ exit(1)
42
+ create_file(data, file: file, format: :json)
43
+ end
44
+ end
45
+ end
46
+
47
+ def create_file(sets, file:, format: :txt)
48
+ File.open(file, "w") do |fd|
49
+ fd << sets_to_str(sets, format: format)
50
+ end
51
+ puts "Generated file #{file}"
52
+ end
53
+
54
+ def sets_to_str(sets, format: :txt)
55
+ raise "Required Array. Given: #{sets.class}" unless sets.is_a?(Array)
56
+ "".tap do |str|
57
+ sets.each do |set|
58
+ str << set_to_str(set, format: format)
59
+ end
60
+ end
61
+ end
62
+
63
+ def set_to_str(set, lev: 0, format: :txt)
64
+ raise "Required Array. Given: #{set.class}" unless set.is_a?(Array)
65
+ "".tap do |str|
66
+ entry = set.shift
67
+ str << "#{" " * lev}#{(lev > 0)? "+-#{lev}- " : ""}#{entry.name} (#{entry.external_id}|#{entry.email}|#{entry.id})\n"
68
+ str << set_to_str(set, lev: lev + 1, format: format) unless !set || set.empty?
69
+ end
70
+ end
71
+
72
+ end
data/lib/eco/cli.rb CHANGED
@@ -23,16 +23,6 @@ module Eco
23
23
  def run(session:)
24
24
  io = Eco::API::UseCases::BaseIO.new(session: session, options: options)
25
25
  session.workflow(io: io).run(io: io)
26
- #session.workflow(io: io) do |wf, io|
27
- # io = wf.run(:options, io: io)
28
- # io = wf.run(:load, io: io)
29
- # io = wf.run(:usecases, io: io)
30
- # io = wf.run(:launch_jobs, io: io)
31
- # io = wf.run(:post_launch, io: io)
32
- # io = wf.run(:report, io: io)
33
- # io = wf.run(:end, io: io)
34
- # io = wf.run(:close, io: io)
35
- #end
36
26
  end
37
27
 
38
28
  end
@@ -7,6 +7,18 @@ ASSETS.cli.config do |cnf|
7
7
  options.deep_merge!(output: {file: file})
8
8
  end
9
9
 
10
+ desc = "Draws the Cyclic Supervisors when identified (use option -to file.ext)"
11
+ cases.add("-identify-cyclic-supers", :export, desc, case_name: "identify-cyclic-supers") do |people, session, options|
12
+ file = (SCR.get_arg("-to") && SCR.get_file("-to", required: true, should_exist: false)) || "supers_hierarchy.txt"
13
+ options.deep_merge!(output: {file: file})
14
+ end
15
+
16
+ desc = "Abstracts the Abilities that each Usergroup should probably have (use option -to file.ext)"
17
+ cases.add("-abstract-policygroup-abilities", :export, desc, case_name: "abstract-policygroup-abilities") do |people, session, options|
18
+ file = (SCR.get_arg("-to") && SCR.get_file("-to", required: true, should_exist: false)) || "suggested_abilities.txt"
19
+ options.deep_merge!(output: {file: file})
20
+ end
21
+
10
22
  desc = "It exports to a CSV the (filtered) people"
11
23
  cases.add("-people-to-csv", :export, desc) do |people, session, options|
12
24
  file = SCR.get_file("-people-to-csv", required: true, should_exist: false)
@@ -5,6 +5,29 @@ module Eco
5
5
  module Files
6
6
  class Directory
7
7
 
8
+ class << self
9
+ def create(path, includes_file: false)
10
+ return true if Files.file_exists?(path)
11
+
12
+ parts = Files.split(File.expand_path(path))
13
+ filename = parts.pop if includes_file
14
+
15
+ return true if Files.dir_exists?(File.join(*parts))
16
+
17
+ subpath = nil
18
+ begin
19
+ parts.each do |curr|
20
+ subpath = subpath ? File.join(subpath, curr) : curr
21
+ Dir.mkdir(subpath) unless Files.dir_exists?(subpath)
22
+ end
23
+ rescue Exception => e
24
+ pp e
25
+ return false
26
+ end
27
+ true
28
+ end
29
+ end
30
+
8
31
  attr_reader :dir_path
9
32
 
10
33
  def initialize(dir_path = Dir.pwd)
@@ -14,12 +37,14 @@ module Eco
14
37
  end
15
38
 
16
39
  def exists?
17
- Files.dir_exists(@dir_path)
40
+ Files.dir_exists?(@dir_path)
18
41
  end
19
42
 
20
43
  def create
21
- succeed = Directory.create(File.expand_path(@dir_path)) unless self.exists?
22
- self.full_path if succeed
44
+ return self.full_path if self.exists?
45
+ if succeed = Directory.create(File.expand_path(@dir_path))
46
+ return self.full_path
47
+ end
23
48
  end
24
49
 
25
50
  def full_path
@@ -57,23 +82,6 @@ module Eco
57
82
  File.join(*args)
58
83
  end
59
84
 
60
- def self.create(path, includes_file: false)
61
- return true if Files.file_exists?(path)
62
- parts = Files.split(File.expand_path(path))
63
- filename = parts.pop if includes_file
64
- return true if Files.dir_exists?(File.join(*parts))
65
- subpath = nil
66
- begin
67
- parts.each do |curr|
68
- subpath = subpath ? File.join(subpath, curr) : curr
69
- Dir.mkdir(subpath) unless Files.dir_exists?(subpath)
70
- end
71
- rescue Exception => e
72
- pp e
73
- end
74
- false
75
- end
76
-
77
85
  private
78
86
 
79
87
  def file_pattern(value)
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = "2.0.15"
2
+ VERSION = "2.0.16"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.15
4
+ version: 2.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
@@ -375,6 +375,7 @@ files:
375
375
  - lib/eco/api/usecases/base_case.rb
376
376
  - lib/eco/api/usecases/base_io.rb
377
377
  - lib/eco/api/usecases/default_cases.rb
378
+ - lib/eco/api/usecases/default_cases/abstract_policygroup_abilities_case.rb
378
379
  - lib/eco/api/usecases/default_cases/append_usergroups_case.rb
379
380
  - lib/eco/api/usecases/default_cases/change_email_case.rb
380
381
  - lib/eco/api/usecases/default_cases/codes_to_tags_case.rb
@@ -399,6 +400,7 @@ files:
399
400
  - lib/eco/api/usecases/default_cases/restore_db_case.rb
400
401
  - lib/eco/api/usecases/default_cases/set_default_tag_case.rb
401
402
  - lib/eco/api/usecases/default_cases/set_supervisor_case.rb
403
+ - lib/eco/api/usecases/default_cases/supers_cyclic_identify_case.rb
402
404
  - lib/eco/api/usecases/default_cases/supers_hierarchy_case.rb
403
405
  - lib/eco/api/usecases/default_cases/switch_supervisor_case.rb
404
406
  - lib/eco/api/usecases/default_cases/to_csv_case.rb