eco-helpers 2.0.13 → 2.0.18

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -2
  3. data/eco-helpers.gemspec +6 -4
  4. data/lib/eco-helpers.rb +2 -0
  5. data/lib/eco/api/common/base_loader.rb +14 -0
  6. data/lib/eco/api/common/people/default_parsers/date_parser.rb +11 -1
  7. data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +1 -1
  8. data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +11 -11
  9. data/lib/eco/api/common/people/person_entry.rb +9 -2
  10. data/lib/eco/api/common/people/supervisor_helpers.rb +27 -0
  11. data/lib/eco/api/common/session/file_manager.rb +2 -2
  12. data/lib/eco/api/common/session/mailer.rb +0 -1
  13. data/lib/eco/api/common/session/s3_uploader.rb +0 -1
  14. data/lib/eco/api/common/session/sftp.rb +0 -1
  15. data/lib/eco/api/common/version_patches/exception.rb +8 -4
  16. data/lib/eco/api/error.rb +5 -3
  17. data/lib/eco/api/microcases.rb +3 -1
  18. data/lib/eco/api/microcases/append_usergroups.rb +0 -1
  19. data/lib/eco/api/microcases/people_cache.rb +2 -2
  20. data/lib/eco/api/microcases/people_load.rb +2 -2
  21. data/lib/eco/api/microcases/people_refresh.rb +2 -2
  22. data/lib/eco/api/microcases/people_search.rb +6 -6
  23. data/lib/eco/api/microcases/preserve_default_tag.rb +23 -0
  24. data/lib/eco/api/microcases/preserve_filter_tags.rb +28 -0
  25. data/lib/eco/api/microcases/preserve_policy_groups.rb +30 -0
  26. data/lib/eco/api/microcases/set_account.rb +0 -1
  27. data/lib/eco/api/organization.rb +1 -0
  28. data/lib/eco/api/organization/people.rb +7 -0
  29. data/lib/eco/api/organization/people_analytics.rb +60 -0
  30. data/lib/eco/api/organization/presets_factory.rb +116 -93
  31. data/lib/eco/api/organization/presets_integrity.json +58 -0
  32. data/lib/eco/api/organization/presets_values.json +5 -4
  33. data/lib/eco/api/policies/default_policies/99_user_access_policy.rb +0 -30
  34. data/lib/eco/api/session.rb +1 -20
  35. data/lib/eco/api/session/batch.rb +23 -7
  36. data/lib/eco/api/session/batch/job.rb +3 -0
  37. data/lib/eco/api/session/config.rb +16 -15
  38. data/lib/eco/api/session/config/api.rb +4 -0
  39. data/lib/eco/api/session/config/apis.rb +80 -0
  40. data/lib/eco/api/session/config/files.rb +7 -0
  41. data/lib/eco/api/session/config/people.rb +3 -19
  42. data/lib/eco/api/usecases/default_cases.rb +4 -1
  43. data/lib/eco/api/usecases/default_cases/abstract_policygroup_abilities_case.rb +161 -0
  44. data/lib/eco/api/usecases/default_cases/analyse_people_case.rb +76 -0
  45. data/lib/eco/api/usecases/default_cases/codes_to_tags_case.rb +2 -3
  46. data/lib/eco/api/usecases/default_cases/reset_landing_page_case.rb +11 -1
  47. data/lib/eco/api/usecases/default_cases/restore_db_case.rb +1 -2
  48. data/lib/eco/api/usecases/default_cases/supers_cyclic_identify_case.rb +72 -0
  49. data/lib/eco/api/usecases/default_cases/supers_hierarchy_case.rb +59 -0
  50. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +104 -26
  51. data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +62 -36
  52. data/lib/eco/cli.rb +0 -10
  53. data/lib/eco/cli/config/default/options.rb +19 -17
  54. data/lib/eco/cli/config/default/people_filters.rb +3 -3
  55. data/lib/eco/cli/config/default/usecases.rb +77 -25
  56. data/lib/eco/cli/config/default/workflow.rb +12 -3
  57. data/lib/eco/cli/config/help.rb +1 -0
  58. data/lib/eco/cli/config/options_set.rb +106 -13
  59. data/lib/eco/cli/config/use_cases.rb +33 -33
  60. data/lib/eco/cli/scripting/args_helpers.rb +30 -3
  61. data/lib/eco/data.rb +1 -0
  62. data/lib/eco/data/crypto/encryption.rb +3 -3
  63. data/lib/eco/data/files/directory.rb +28 -20
  64. data/lib/eco/data/files/helpers.rb +6 -4
  65. data/lib/eco/data/fuzzy_match.rb +119 -0
  66. data/lib/eco/data/fuzzy_match/array_helpers.rb +75 -0
  67. data/lib/eco/data/fuzzy_match/chars_position_score.rb +37 -0
  68. data/lib/eco/data/fuzzy_match/ngrams_score.rb +73 -0
  69. data/lib/eco/data/fuzzy_match/pairing.rb +102 -0
  70. data/lib/eco/data/fuzzy_match/result.rb +67 -0
  71. data/lib/eco/data/fuzzy_match/results.rb +53 -0
  72. data/lib/eco/data/fuzzy_match/score.rb +44 -0
  73. data/lib/eco/data/fuzzy_match/stop_words.rb +35 -0
  74. data/lib/eco/data/fuzzy_match/string_helpers.rb +69 -0
  75. data/lib/eco/version.rb +1 -1
  76. metadata +86 -10
  77. data/lib/eco/api/microcases/refresh_abilities.rb +0 -19
  78. data/lib/eco/api/organization/presets_reference.json +0 -59
  79. data/lib/eco/api/usecases/default_cases/refresh_abilities_case.rb +0 -30
@@ -0,0 +1,58 @@
1
+ {
2
+ "person_core_create": [
3
+ { "value": "create", "conditions": {
4
+ "at_least": {"person_core": "view_people_manager"}
5
+ }
6
+ }
7
+ ],
8
+ "person_core_edit": [
9
+ { "value": "edit", "conditions": {
10
+ "at_least": {"person_core": "view_people_manager"}
11
+ }
12
+ }
13
+ ],
14
+ "person_details": [
15
+ { "value": "view", "conditions": {
16
+ "at_least": {"person_core": "attach"}
17
+ }
18
+ },
19
+ { "value": "edit_public", "conditions": {
20
+ "one_of": {
21
+ "person_core_edit": "edit",
22
+ "person_core_create": "create"
23
+ }
24
+ }
25
+ },
26
+ { "value": "view_private", "conditions": {
27
+ "at_least": {"person_core": "attach" }
28
+ }
29
+ },
30
+ { "value": "edit_private", "conditions": {
31
+ "one_of": {
32
+ "person_core_edit": "edit",
33
+ "person_core_create": "create"
34
+ }
35
+ }
36
+ }
37
+ ],
38
+ "person_account": [
39
+ { "value": "view", "conditions": {
40
+ "at_least": {"person_core": "attach" }
41
+ }
42
+ },
43
+ { "value": "create", "conditions": {
44
+ "at_least": {"person_core_create": "create"}
45
+ }
46
+ },
47
+ { "value": "edit", "conditions": {
48
+ "at_least": {"person_core_edit": "edit"}
49
+ }
50
+ }
51
+ ],
52
+ "person_abilities": [
53
+ { "value": "view", "conditions": {
54
+ "at_least": {"person_core_edit": "edit"}
55
+ }
56
+ }
57
+ ]
58
+ }
@@ -2,14 +2,15 @@
2
2
  "files": [null, "download", "upload", "browse", "administrate"],
3
3
  "data": [null, "view", "update", "administrate", "implement"],
4
4
  "reports": [null, "view", "edit", "administrate"],
5
+ "pages": [null, "view", "update", "create", "administrate"],
6
+ "page_editor": [null, "basic", "intermediate", "advanced", "implement"],
7
+ "registers": [null, "view", "dashboard", "administrate", "implement"],
5
8
  "tasks": [null, "reassign_self", "reassign", "administrate"],
6
9
  "organization": [null, "view", "administrate", "implement"],
7
10
  "person_core": [null, "attach", "view_people_manager", "dashboard"],
8
11
  "person_core_create": [null, "create"],
9
12
  "person_core_edit": [null, "edit"],
10
- "person_account": [null, "view", "create", "edit"],
11
13
  "person_details": [null, "view", "edit_public", "view_private", "edit_private"],
12
- "pages": [null, "view", "update", "create", "administrate"],
13
- "page_editor": [null, "basic", "intermediate", "advanced", "implement"],
14
- "registers": [null, "view", "dashboard", "administrate", "implement"]
14
+ "person_account": [null, "view", "create", "edit"],
15
+ "person_abilities": [null, "view", "edit"]
15
16
  }
@@ -12,7 +12,6 @@ class Eco::API::Policies::DefaultPolicies::UserAccess < Eco::API::Common::Loader
12
12
  people.each do |person|
13
13
  remove_account_when_no_email!(person) if person.email.to_s.empty?
14
14
  person.account.policy_group_ids = defid if no_policy_group_ids?(person)
15
- refresh_abilities!(person)
16
15
  end
17
16
 
18
17
  warn_account_removal!
@@ -40,39 +39,10 @@ class Eco::API::Policies::DefaultPolicies::UserAccess < Eco::API::Common::Loader
40
39
  return !!person.original_doc["account"]
41
40
  end
42
41
 
43
- def refresh_abilities!(person)
44
- return nil if options.dig(:exclude, :abilities)
45
- return nil unless account = person.account
46
- account.permissions_custom = session.new_preset(person)
47
- account.permissions_custom = min_abilities if no_abilities?(person)
48
- end
49
-
50
42
  def no_policy_group_ids?(person)
51
43
  (account = person.account) && account.policy_group_ids.empty?
52
44
  end
53
45
 
54
- def no_abilities?(person)
55
- return true unless account = person.account
56
- account.permissions_custom && account.permissions_custom.values.all?(&:nil?)
57
- end
58
-
59
- def min_abilities
60
- {
61
- "files" => "upload",
62
- "data" => nil,
63
- "reports" => nil,
64
- "pages" => "create",
65
- "page_editor" => "basic",
66
- "registers" => "view",
67
- "organization" => nil,
68
- "person_core" => "attach",
69
- "person_core_edit" => nil,
70
- "person_core_create" => nil,
71
- "person_details" => "view",
72
- "person_account" => nil
73
- }
74
- end
75
-
76
46
  def defid
77
47
  @defid ||= policy_groups.to_id([default_group]).compact
78
48
  end
@@ -61,28 +61,9 @@ module Eco
61
61
  self
62
62
  end
63
63
 
64
- # Builds the presets using the usergroup ids of the input.
65
- # @note for each flag/ability it will take the highest among those mapped for the present usergroups.
66
- # @param input [Ecoportal::API::Internal::Person, Array<String>] the array should be of usegroup names or ids.
67
- # @return [Hash] with custom presets.
68
- def new_preset(input)
69
- case input
70
- when Ecoportal::API::Internal::Person
71
- presets_factory.new(*input&.account&.policy_group_ids)
72
- when Array
73
- presets_factory.new(*input)
74
- else
75
- presets_factory.new(input)
76
- end
77
- end
78
-
79
64
  # Helper to state the abilities that a person should have with given their usergroups
80
65
  def presets_factory
81
- @presets_factory ||= Eco::API::Organization::PresetsFactory.new({
82
- presets_custom: file_manager.dir.file(config.people.presets_custom, should_exist: true),
83
- presets_map: file_manager.dir.file(config.people.presets_map, should_exist: true),
84
- enviro: enviro
85
- })
66
+ @presets_factory ||= Eco::API::Organization::PresetsFactory.new(enviro: enviro)
86
67
  end
87
68
 
88
69
  # Helper to obtain a EntryFactory
@@ -114,14 +114,16 @@ module Eco
114
114
  logger.info(msg) unless silent
115
115
 
116
116
  start_slice = Time.now
117
- people_api.batch do |batch|
118
- slice.each do |person|
119
- batch.public_send(method, person) do |response|
120
- faltal("Request with no response") unless !!response
121
- status[person] = response
117
+ offer_retry_on(Ecoportal::API::Errors::TimeOut) do
118
+ people_api.batch do |batch|
119
+ slice.each do |person|
120
+ batch.public_send(method, person) do |response|
121
+ faltal("Request with no response") unless !!response
122
+ status[person] = response
123
+ end
122
124
  end
123
- end
124
- end # next batch
125
+ end # end batch
126
+ end
125
127
 
126
128
  iteration += 1
127
129
  done += slice.length
@@ -129,6 +131,20 @@ module Eco
129
131
  end
130
132
  end
131
133
 
134
+ def offer_retry_on(error_type, retries_left = 3, &block)
135
+ begin
136
+ block.call
137
+ rescue error_type => e
138
+ raise unless retries_left > 0
139
+ print "Batch TimeOut. You have #{retries_left} retries left. Do you want to retry (y/N)? "
140
+ if (res = STDIN.gets.chomp) && res[0].downcase == "y"
141
+ offer_retry_on(error_type, retries_left - 1, &block)
142
+ else
143
+ raise
144
+ end
145
+ end
146
+ end
147
+
132
148
  def str_stats(start, count)
133
149
  now = Time.now
134
150
  secs = (now - start).round(3)
@@ -288,10 +288,13 @@ module Eco
288
288
  handlers = session.config.error_handlers
289
289
  if status.errors.any? && !handlers.empty? && !error_handler?
290
290
  err_types = status.errors.by_type
291
+ logger.debug("(#{self.name}) got these error types: #{err_types.keys}")
291
292
  handlers.each do |handler|
292
293
  if entries = err_types[handler.name]
293
294
  handler_job = subjobs_add("#{self.name} => #{handler.name}", usecase: handler)
295
+ logger.debug("Running error handler #{handler.name}")
294
296
  handler.launch(people: people(entries), session: session, options: options, job: handler_job)
297
+ logger.debug("Launching job of error handler: #{handler_job.name}")
295
298
  handler_job.launch(simulate: simulate)
296
299
  end
297
300
  end
@@ -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
@@ -286,16 +297,6 @@ module Eco
286
297
  people.default_schema = name
287
298
  end
288
299
 
289
- # Specify the file with the account custom abilities presets
290
- def presets_custom=(file)
291
- people.presets_custom = file
292
- end
293
-
294
- # Specify the file with the usergroup to custom presets mapping
295
- def presets_map=(file)
296
- people.presets_map = file
297
- end
298
-
299
300
  # @see Eco::API::Session::Config::People
300
301
  # @param (see Eco::API::Session::Config::People)
301
302
  # @return [Eco::API::Common::People::PersonParser] parser/serializer for the defined `format`.
@@ -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
@@ -82,6 +82,86 @@ module Eco
82
82
  self["user_key"]
83
83
  end
84
84
 
85
+ # Method to support CLI one-off API requests
86
+ def one_off
87
+ if one_off?
88
+ add(one_off_org, key: one_off_key, host: "#{one_off_enviro}.ecoportal.com")
89
+ return one_off_org
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def one_off?
96
+ @is_one_off ||= SCR.get_arg("-api-key") || SCR.get_arg("-one-off")
97
+ end
98
+
99
+ def one_off_key
100
+ return @one_off_key if instance_variable_defined?(:@one_off_key)
101
+ if one_off?
102
+ Dotenv.load("./.env_one_off")
103
+ SCR.get_arg("-api-key", with_param: true).yield_self do |key|
104
+ one_off_key_env(key)
105
+ end
106
+ end
107
+ end
108
+
109
+ def one_off_key_env(key)
110
+ if one_off?
111
+ if key
112
+ env_file_set_var("./.env_one_off", one_off_key_env_var, key)
113
+ key
114
+ else
115
+ Dotenv.load("./.env_one_off")
116
+ ENV[one_off_key_env_var].tap do |k|
117
+ raise "At least the first time, you should provide the -api-key" unless k
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ def one_off_key_env_var
124
+ @one_off_key_env_var ||= "#{one_off_org}_KEY"
125
+ end
126
+
127
+ def one_off_org
128
+ return @one_off_org if instance_variable_defined?(:@one_off_org)
129
+ unless org = SCR.get_arg("-org", with_param: true)
130
+ raise("You should specify -org NAME when using -api-key or -one-off")
131
+ end
132
+ @one_off_org ||= "#{org.downcase.split(/[^a-z]+/).join("_")}_#{one_off_enviro.gsub(".", "_")}".to_sym
133
+ end
134
+
135
+ def one_off_enviro
136
+ return @one_off_enviro if instance_variable_defined?(:@one_off_enviro)
137
+ enviro = SCR.get_arg("-enviro") ? SCR.get_arg("-enviro", with_param: true) : "live"
138
+ @one_off_enviro ||= enviro.downcase
139
+ end
140
+
141
+ def env_file_set_var(file, var, value)
142
+ begin
143
+ pattern = /"#{var}=(?<value>[^ \r\n]+)"/
144
+ File.open(file, "w+") do |fd|
145
+ found = false
146
+ fd.each_line do |line|
147
+ if match = line.match(pattern)
148
+ found = true
149
+ # IO::SEEK_CUR => Seeks to _amount_ plus current position
150
+ fd.seek(-(line.length + 1), IO::SEEK_CUR)
151
+ fd.write line.gsub(match[:value], value)
152
+ end
153
+ end
154
+
155
+ fd << "#{var}=#{value}" unless found
156
+ end
157
+ rescue StandardError => e
158
+ puts "#{e}"
159
+ return false
160
+ end
161
+ return true
162
+ end
163
+
164
+
85
165
  end
86
166
  end
87
167
  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
@@ -86,23 +86,7 @@ module Eco
86
86
  def default_schema?
87
87
  !!self["default_schema"]
88
88
  end
89
-
90
- def presets_custom=(file)
91
- self["presets_custom"] = file
92
- end
93
-
94
- def presets_custom
95
- self["presets_custom"]
96
- end
97
-
98
- def presets_map=(file)
99
- self["presets_map"] = file
100
- end
101
-
102
- def presets_map
103
- self["presets_map"]
104
- end
105
-
89
+
106
90
  # @return [Hash] with defined pairs format `key` and Person parsers.
107
91
  def parsers
108
92
  self["parsers"] ||= {}
@@ -9,6 +9,8 @@ module Eco
9
9
  end
10
10
  end
11
11
 
12
+ require_relative 'default_cases/abstract_policygroup_abilities_case.rb'
13
+ require_relative 'default_cases/analyse_people_case'
12
14
  require_relative 'default_cases/append_usergroups_case'
13
15
  require_relative 'default_cases/change_email_case'
14
16
  require_relative 'default_cases/codes_to_tags_case'
@@ -22,7 +24,6 @@ require_relative 'default_cases/hris_case'
22
24
  require_relative 'default_cases/new_id_case'
23
25
  require_relative 'default_cases/new_email_case'
24
26
  require_relative 'default_cases/org_data_convert_case'
25
- require_relative 'default_cases/refresh_abilities_case'
26
27
  require_relative 'default_cases/refresh_case'
27
28
  require_relative 'default_cases/reinvite_trans_case'
28
29
  require_relative 'default_cases/reinvite_sync_case'
@@ -32,6 +33,8 @@ require_relative 'default_cases/reset_landing_page_case'
32
33
  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'
36
+ require_relative 'default_cases/supers_hierarchy_case'
37
+ require_relative 'default_cases/supers_cyclic_identify_case'
35
38
  require_relative 'default_cases/switch_supervisor_case'
36
39
  require_relative 'default_cases/to_csv_case'
37
40
  require_relative 'default_cases/to_csv_detailed_case'