eco-helpers 1.5.13 → 2.0.4

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -0
  3. data/eco-helpers.gemspec +31 -29
  4. data/lib/eco/api.rb +1 -1
  5. data/lib/eco/api/common/class_helpers.rb +45 -1
  6. data/lib/eco/api/common/loaders/error_handler.rb +2 -0
  7. data/lib/eco/api/common/loaders/parser.rb +4 -0
  8. data/lib/eco/api/common/loaders/use_case.rb +2 -0
  9. data/lib/eco/api/common/people/person_entry.rb +15 -3
  10. data/lib/eco/api/common/people/person_parser.rb +10 -3
  11. data/lib/eco/api/common/session/logger.rb +9 -1
  12. data/lib/eco/api/common/session/logger/cache.rb +91 -0
  13. data/lib/eco/api/common/session/logger/log.rb +48 -0
  14. data/lib/eco/api/common/version_patches/ecoportal_api/external_person.rb +9 -0
  15. data/lib/eco/api/microcases/people_cache.rb +7 -0
  16. data/lib/eco/api/microcases/people_load.rb +29 -21
  17. data/lib/eco/api/microcases/people_refresh.rb +6 -0
  18. data/lib/eco/api/microcases/people_search.rb +33 -8
  19. data/lib/eco/api/policies.rb +1 -0
  20. data/lib/eco/api/policies/default_policies.rb +12 -0
  21. data/lib/eco/api/policies/default_policies/99_user_access_policy.rb +88 -0
  22. data/lib/eco/api/session.rb +13 -0
  23. data/lib/eco/api/session/batch.rb +0 -3
  24. data/lib/eco/api/session/batch/job.rb +17 -7
  25. data/lib/eco/api/session/config/workflow.rb +1 -0
  26. data/lib/eco/api/usecases.rb +1 -0
  27. data/lib/eco/api/usecases/ooze_samples.rb +11 -0
  28. data/lib/eco/api/usecases/ooze_samples/ooze_update_case.rb +131 -0
  29. data/lib/eco/version.rb +1 -1
  30. metadata +42 -47
  31. data/lib/eco/api/usecases/backup/append_usergroups_case.rb +0 -36
  32. data/lib/eco/api/usecases/backup/create_case.rb +0 -104
  33. data/lib/eco/api/usecases/backup/create_details_case.rb +0 -31
  34. data/lib/eco/api/usecases/backup/create_details_with_supervisor_case.rb +0 -48
  35. data/lib/eco/api/usecases/backup/hris_case.rb +0 -124
  36. data/lib/eco/api/usecases/backup/set_default_tag_case.rb +0 -49
  37. data/lib/eco/api/usecases/backup/set_supervisor_case.rb +0 -41
  38. data/lib/eco/api/usecases/backup/transfer_account_case.rb +0 -90
  39. data/lib/eco/api/usecases/backup/update_case.rb +0 -112
  40. data/lib/eco/api/usecases/backup/update_details_case.rb +0 -64
  41. data/lib/eco/api/usecases/backup/upsert_case.rb +0 -114
@@ -0,0 +1,48 @@
1
+ module Eco
2
+ module API
3
+ module Common
4
+ module Session
5
+ class Logger
6
+ class Log
7
+
8
+ attr_accessor :level, :datetime, :message, :formatted
9
+
10
+ def initialize(level, datetime, message, formatted)
11
+ @level = level
12
+ @datetime = datetime
13
+ @message = message
14
+ @formatted = formatted
15
+ end
16
+
17
+ def to_s
18
+ self.formatted
19
+ end
20
+
21
+ def <=>(other)
22
+ self.datetime <=> other.datetime
23
+ end
24
+
25
+ def before?(value)
26
+ return true if !value
27
+ datetime <= to_datetime(value)
28
+ end
29
+
30
+ def after?(value)
31
+ return true if !value
32
+ datetime >= to_datetime(value)
33
+ end
34
+
35
+ private
36
+
37
+ def to_datetime(value)
38
+ return value if value.is_a?(Time)
39
+ return nil unless value
40
+ Time.parse(value)
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -13,6 +13,15 @@ module Ecoportal
13
13
  original_doc["details"] = JSON.parse(doc["details"])
14
14
  end
15
15
 
16
+ def identify
17
+ if entry
18
+ entry.to_s(:identify)
19
+ else
20
+ str_id = id ? "id: '#{id}'; " : ""
21
+ "#{name}' (#{str_id}ext_id: '#{external_id}'; email: '#{email}')"
22
+ end
23
+ end
24
+
16
25
  end
17
26
  end
18
27
  end
@@ -6,7 +6,14 @@ module Eco
6
6
  # @return [Eco::API::Organization::People] the `People` object with the data.
7
7
  def people_cache(filename = enviro.config.people.cache)
8
8
  logger.info("Going to get all the people via API")
9
+
10
+ start = Time.now
9
11
  people = session.batch.get_people
12
+ secs = Time.now - start
13
+ cnt = people.count
14
+ per_sec = (cnt.to_f / secs).floor
15
+ logger.info("Loaded #{cnt} people in #{secs} seconds (#{per_sec} people/sec)")
16
+
10
17
  file = file_manager.save_json(people, filename, :timestamp)
11
18
  logger.info("#{people.length} people loaded and saved locally to #{file}.")
12
19
  Eco::API::Organization::People.new(people)
@@ -18,27 +18,35 @@ module Eco
18
18
  def people_load(filename = enviro.config.people.cache, modifier: [:newest, :api])
19
19
  modifier = [modifier].flatten
20
20
  load_file = [:file, :newest].any? {|flag| modifier.include?(flag)}
21
- people = case
22
- when filename && load_file
23
- if file = people_load_filename(filename, newest: modifier.include?(:newest))
24
- file_manager.load_json(file).tap do |people|
25
- logger.info("#{people&.length} people loaded from file #{file}") if people.is_a?(Array)
26
- end
27
- else
28
- logger.error("could not find the file #{file_manager.dir.file(filename)}")
29
- exit unless modifier.include?(:api)
30
- people_load(modifier: modifier - [:newest, :file])
31
- end
32
- when modifier.include?(:api)
33
- logger.info("Going to get all the people via API")
34
- session.batch.get_people.tap do |people|
35
- if modifier.include?(:save) && people && people.length > 0
36
- file = file_manager.save_json(people, filename, :timestamp)
37
- logger.info("#{people.length } people saved to file #{file}.")
38
- end
39
- end
40
- end
41
- Eco::API::Organization::People.new(people)
21
+ case
22
+ when filename && load_file
23
+ if file = people_load_filename(filename, newest: modifier.include?(:newest))
24
+ file_manager.load_json(file).tap do |people|
25
+ logger.info("#{people&.length} people loaded from file #{file}") if people.is_a?(Array)
26
+ end
27
+ else
28
+ logger.error("could not find the file #{file_manager.dir.file(filename)}")
29
+ exit unless modifier.include?(:api)
30
+ people_load(modifier: modifier - [:newest, :file])
31
+ end
32
+ when modifier.include?(:api)
33
+ logger.info("Going to get all the people via API")
34
+
35
+ start = Time.now
36
+ session.batch.get_people.tap do |people|
37
+ secs = Time.now - start
38
+ cnt = people.count
39
+ per_sec = (cnt.to_f / secs).floor
40
+ logger.info("Loaded #{cnt} people in #{secs} seconds (#{per_sec} people/sec)")
41
+
42
+ if modifier.include?(:save) && people && people.length > 0
43
+ file = file_manager.save_json(people, filename, :timestamp)
44
+ logger.info("#{people.length } people saved to file #{file}.")
45
+ end
46
+ end
47
+ end.yield_self do |people|
48
+ Eco::API::Organization::People.new(people)
49
+ end
42
50
  end
43
51
 
44
52
  private
@@ -18,7 +18,13 @@ module Eco
18
18
  msg = "Going to refresh #{people.length} people with server data"
19
19
  msg += " (including #{created} that were created)" if created > 0
20
20
  logger.info(msg)
21
+
22
+ start = Time.now
21
23
  entries = session.batch.get_people(people, silent: true)
24
+ secs = Time.now - start
25
+ cnt = entries.count
26
+ per_sec = (cnt.to_f / secs).floor
27
+ logger.info("Re-loaded #{cnt} people (out of #{people.length}) in #{secs} seconds (#{per_sec} people/sec)")
22
28
 
23
29
  missing = people.length - entries.length
24
30
  logger.error("Missed to obtain #{missing} people during the refresh") if missing > 0
@@ -11,24 +11,49 @@ module Eco
11
11
  # @return [Eco::API::Organization::People] the `People` object with the found persons.
12
12
  def people_search(data, options: {}, silent: true)
13
13
  session.logger.info("Going to api get #{data.length} entries...")
14
- status = session.batch.search(data, silent: silent)
15
- people = Eco::API::Organization::People.new(status.people)
16
- session.logger.info("... could get #{people.length} people (out of #{data.length} entries)")
14
+
15
+ start = Time.now
16
+ people = session.batch.search(data, silent: silent).yield_self do |status|
17
+ secs = Time.now - start
18
+ Eco::API::Organization::People.new(status.people).tap do |people|
19
+ cnt = people.count
20
+ per_sec = (cnt.to_f / secs).floor
21
+ msg = "... could get #{cnt} people (out of #{data.length} entries) in #{secs} seconds (#{per_sec} people/sec)"
22
+ session.logger.info(msg)
23
+ end
24
+ end
17
25
 
18
26
  # get the supervisors of found people (current supervisors)
19
27
  supers = people_search_prepare_supers_request(people)
20
28
  if supers.length > 0
21
29
  session.logger.info(" Going to api get #{supers.length} current supervisors...")
22
- status = session.batch.search(supers, silent: silent)
23
- people = people.merge(status.people, strict: micro.strict_search?(options))
30
+ start = Time.now
31
+ people = session.batch.search(supers, silent: silent).yield_self do |status|
32
+ secs = Time.now - start
33
+ found = status.people
34
+ cnt = found.count
35
+ per_sec = (cnt.to_f / secs).floor
36
+ msg = "... could find #{cnt} current supers (out of #{supers.length}) in #{secs} seconds (#{per_sec} people/sec)"
37
+ session.logger.info(msg)
38
+ people.merge(found, strict: micro.strict_search?(options))
39
+ end
24
40
  end
25
41
 
26
42
  # get the supervisors referred in the input data (future supervisors)
27
43
  supers = people_search_prepare_supers_request(data, people)
28
44
  if supers.length > 0
29
- session.logger.info(" Going to api get #{supers.length} supervisors as per entries...")
30
- status = session.batch.search(supers, silent: silent)
31
- people = people.merge(status.people, strict: micro.strict_search?(options))
45
+ session.logger.info(" Going to api get #{supers.length} supervisors as per input entries...")
46
+ start = Time.now
47
+
48
+ people = session.batch.search(supers, silent: silent).yield_self do |status|
49
+ secs = Time.now - start
50
+ found = status.people
51
+ cnt = found.count
52
+ per_sec = (cnt.to_f / secs).floor
53
+ msg = "... could find #{cnt} input supers (out of #{supers.length}) in #{secs} seconds (#{per_sec} people/sec)"
54
+ session.logger.info(msg)
55
+ people.merge(found, strict: micro.strict_search?(options))
56
+ end
32
57
  end
33
58
 
34
59
  session.logger.info("Finally got #{people.length} people (out of #{data.length} entries)")
@@ -36,3 +36,4 @@ module Eco
36
36
  end
37
37
 
38
38
  require_relative 'policies/policy'
39
+ require_relative 'policies/default_policies'
@@ -0,0 +1,12 @@
1
+ module Eco
2
+ module API
3
+ class Policies
4
+ class DefaultPolicies < Eco::API::Policies
5
+ autoloads_children_of "Eco::API::Common::Loaders::Policy"
6
+ autoload_namespace "Eco::API::Policies::DefaultPolicies"
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ require_relative 'default_policies/99_user_access_policy'
@@ -0,0 +1,88 @@
1
+ class Eco::API::Policies::DefaultPolicies::UserAccess < Eco::API::Common::Loaders::Policy
2
+ name "default-user-access"
3
+
4
+ attr_reader :session, :options, :job
5
+ attr_accessor :account_removed_count
6
+
7
+ def main(people, session, options, policy, job)
8
+ @session = session; @options = options; @job = job
9
+
10
+ self.account_removed_count = 0
11
+
12
+ people.each do |person|
13
+ remove_account_when_no_email!(person) if person.email.to_s.empty?
14
+ person.account.policy_group_ids = defid if no_policy_group_ids?(person)
15
+ refresh_abilities!(person)
16
+ end
17
+
18
+ warn_account_removal!
19
+ end
20
+
21
+ private
22
+
23
+ def warn_account_removal!
24
+ if account_removed_count > 0
25
+ msg = "(DefaultPolicy on job '#{job.name}') Removed account to #{account_removed_count} people"
26
+ session.logger.warn(msg)
27
+ end
28
+ end
29
+
30
+ def remove_account_when_no_email!(person)
31
+ if person.account
32
+ self.account_removed_count += 1 if had_account?(person)
33
+ person.account = nil
34
+ end
35
+ end
36
+
37
+ def had_account?(person)
38
+ return false if person.new?
39
+ return false if person.account_added?
40
+ return !!person.original_doc["account"]
41
+ end
42
+
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
+ def no_policy_group_ids?(person)
51
+ (account = person.account) && account.policy_group_ids.empty?
52
+ end
53
+
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
+ def defid
77
+ @defid ||= policy_groups.to_id([default_group]).compact
78
+ end
79
+
80
+ def default_group
81
+ session.config.people.default_usergroup
82
+ end
83
+
84
+ def policy_groups
85
+ session.policy_groups
86
+ end
87
+
88
+ end
@@ -187,6 +187,8 @@ module Eco
187
187
  end
188
188
 
189
189
  # Does merge `Eco::API::UseCases::DefaultCases` with the custom cases.
190
+ # @note
191
+ # - the order matters, as a default usecase can be redefined by a custom one with same name
190
192
  # @return [Eco::API::UseCases]
191
193
  def usecases
192
194
  @usecases ||= config.usecases.dup.tap do |cases|
@@ -195,6 +197,17 @@ module Eco
195
197
  end
196
198
  end
197
199
 
200
+ # Does merge `Eco::API::Policies::DefaultPolicies` with the custom policies.
201
+ # @note
202
+ # - the default policies are added at the end (meaning they will run after the custom policies)
203
+ # @return [Eco::API::Policies]
204
+ def policies
205
+ @policies ||= config.policies.dup.tap do |policies|
206
+ default_policies = Eco::API::Policies::DefaultPolicies.new
207
+ policies.merge(default_policies)
208
+ end
209
+ end
210
+
198
211
  # Set of helpers to simplify your code
199
212
  # @see Eco::API::MicroCases
200
213
  # @return [Eco::API::MicroCases]
@@ -88,10 +88,7 @@ module Eco
88
88
 
89
89
  def get(params: {}, silent: false)
90
90
  fatal "cannot batch get without api connnection, please provide a valid api connection!" unless people_api = api&.people
91
-
92
91
  params = {per_page: DEFAULT_BATCH_BLOCK}.merge(params)
93
- client = people_api.client
94
-
95
92
  return people_api.get_all(params: params, silent: silent)
96
93
  end
97
94
 
@@ -71,12 +71,6 @@ module Eco
71
71
  @subjobs ||= Eco::API::Session::Batch::Jobs.new(enviro, name: "childs-of:#{self.name}")
72
72
  end
73
73
 
74
- def subjobs_add(name = "ad-hoc:job-from:#{self.name}", usecase: self.usecase, &block)
75
- dup(name, usecase: usecase).tap do |subjob|
76
- subjobs.add(subjob, &block)
77
- end
78
- end
79
-
80
74
  # @return [Boolean] `true` if the current batch job is a result of an error_handler
81
75
  def error_handler?
82
76
  usecase? && usecase.is_a?(Eco::API::Error::Handler)
@@ -211,6 +205,7 @@ module Eco
211
205
  end
212
206
 
213
207
  msg << status.errors.message unless !status
208
+ msg << subjobs_summary
214
209
  end
215
210
  end.join("\n")
216
211
  end
@@ -238,7 +233,7 @@ module Eco
238
233
  # Applies the changes introduced by api policies
239
234
  def apply_policies(pre_queue)
240
235
  people(pre_queue).tap do |entries|
241
- policies = session.config.policies
236
+ policies = session.policies
242
237
  unless policies.empty? || options.dig(:skip, :api_policies)
243
238
  policies.launch(people: entries, session: session, options: options, job: self)
244
239
  end
@@ -307,6 +302,21 @@ module Eco
307
302
  file_manager.save_json(requests, file, :timestamp)
308
303
  end
309
304
 
305
+ # Adds a job tied to the current job
306
+ # Used with error handlers that need their own job to run
307
+ def subjobs_add(name = "ad-hoc:job-from:#{self.name}", usecase: self.usecase, &block)
308
+ dup(name, usecase: usecase).tap do |subjob|
309
+ subjobs.add(subjob, &block)
310
+ end
311
+ end
312
+
313
+ def subjobs_summary
314
+ return "" unless subjobs.count > 0
315
+ [].tap do |msg|
316
+ subjobs.map {|subjob| msg << subjob.summary}
317
+ end.join("\n")
318
+ end
319
+
310
320
  end
311
321
  end
312
322
  end
@@ -195,6 +195,7 @@ module Eco
195
195
  # @yieldreturn [Eco::API::UseCases::BaseIO] the `io` input/output object carried througout all the _workflow_
196
196
  # @return [Eco::API::Session::Config::Workflow] the current stage object (to ease chainig).
197
197
  def run(key = nil, io:, &block)
198
+ raise "Missing BaseIO object" unless io.is_a?(Eco::API::UseCases::BaseIO)
198
199
  begin
199
200
  if key
200
201
  io = stage(key).run(io: io, &block)
@@ -160,3 +160,4 @@ require_relative 'usecases/use_case_chain'
160
160
  require_relative 'usecases/base_io'
161
161
  require_relative 'usecases/use_case_io'
162
162
  require_relative 'usecases/default_cases'
163
+ require_relative 'usecases/ooze_samples'
@@ -0,0 +1,11 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class OozeSamples
5
+
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ require_relative 'ooze_samples/ooze_update_case'
@@ -0,0 +1,131 @@
1
+ class Eco::API::UseCases::OozeSamples::OozeUpdateCase < Eco::API::Common::Loaders::UseCase
2
+ name "single-ooze-case"
3
+ type :other
4
+
5
+ attr_reader :session, :options, :usecase
6
+
7
+ SAVE_PATCH = "ooze_patch_update.json"
8
+
9
+ def main(session, options, usecase)
10
+ @session = session; @options = options; @usecase = usecase
11
+ yield
12
+ end_script!
13
+ end
14
+
15
+ private
16
+
17
+ def end_script!
18
+ exit_if_no_changes!
19
+ backup_patch!
20
+ launch_request unless options[:simulate]
21
+ exit(0)
22
+ end
23
+
24
+ def ooze_id
25
+ options.dig(:source, :ooze_id)
26
+ end
27
+
28
+ def stage_id
29
+ options.dig(:source, :stage_id)
30
+ end
31
+
32
+ def stage(id_name = stage_id)
33
+ if stg = ooze.stages[id_name] || ooze.stages.get_by_name(id_name)
34
+ return apiv2.pages.get(ooze_id, stage_id: stg.id).tap do |stage|
35
+ if stage
36
+ new_target(stage)
37
+ logger.info("Got #{object_reference(stage)} from #{object_reference(ooze)}")
38
+ else
39
+ logger.error("Could not get stage '#{id_name}' in ooze '#{ooze_id}'")
40
+ exit(1)
41
+ end
42
+ end
43
+ end
44
+ raise "Stage '#{id_name}' doesn't exist in ooze '#{ooze_id}'"
45
+ end
46
+
47
+ def ooze
48
+ @ooze ||= apiv2.pages.get(ooze_id).tap do |ooze|
49
+ if ooze
50
+ new_target(ooze)
51
+ logger.info("Got #{object_reference(ooze)}")
52
+ else
53
+ logger.error("Could not get ooze '#{ooze_id}'")
54
+ exit(1)
55
+ end
56
+ end
57
+ end
58
+
59
+ def launch_request
60
+ prompt_to_confirm!
61
+
62
+ apiv2.pages.update(target).tap do |response|
63
+ if response.success?
64
+ logger.info("All went OK")
65
+ else
66
+ logger.error(response.body)
67
+ end
68
+ end
69
+ end
70
+
71
+ def exit_if_no_changes!
72
+ unless changes = !!patch_doc["page"]
73
+ logger.warn "No Changes!!"
74
+ exit(0)
75
+ end
76
+ end
77
+
78
+ def apiv2
79
+ @apiv2 ||= session.api(version: :oozes)
80
+ end
81
+
82
+ def target
83
+ @target
84
+ end
85
+
86
+ def new_target(object)
87
+ if @target && patch_doc["page"]
88
+ logger.warn "You you are switching to a new target #{object_reference(object)} after doing unsaved changes to #{object_reference(@target)}"
89
+ end
90
+ @target = object
91
+ end
92
+
93
+ def object_reference(obj)
94
+ return "No reference" unless obj
95
+ "".tap do |ref|
96
+ case obj
97
+ when Ecoportal::API::V2::Page::Stage
98
+ ref << "Stage "
99
+ when Ecoportal::API::V2::Pages::PageStage
100
+ ref << "StagePage "
101
+ when Ecoportal::API::V2::Page
102
+ ref << "Page "
103
+ end
104
+ ref << "'#{obj.name}' " if obj.respond_to?(:name)
105
+ end
106
+ end
107
+
108
+
109
+ def patch_doc
110
+ apiv2.pages.get_body(target)
111
+ end
112
+
113
+ def backup_patch!
114
+ # store the request
115
+ File.open(SAVE_PATCH, "w") do |file|
116
+ #file << (patch_doc || {}).to_json
117
+ file << JSON.pretty_generate(patch_doc || {})
118
+ end
119
+ puts "Saved patch at: #{File.expand_path(SAVE_PATCH)}"
120
+ end
121
+
122
+ def logger
123
+ session.logger
124
+ end
125
+
126
+ def prompt_to_confirm!
127
+ print "\nDo you want to proceed (y/N)? "
128
+ exit(1) unless $stdin.gets.chomp.to_s.downcase == "y"
129
+ end
130
+
131
+ end