eco-helpers 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/lib/eco/api.rb +1 -0
  3. data/lib/eco/api/common.rb +1 -0
  4. data/lib/eco/api/common/class_helpers.rb +33 -0
  5. data/lib/eco/api/common/people.rb +1 -0
  6. data/lib/eco/api/common/people/person_attribute_parser.rb +52 -0
  7. data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +2 -2
  8. data/lib/eco/api/common/people/person_parser.rb +16 -10
  9. data/lib/eco/api/common/version_patches.rb +2 -3
  10. data/lib/eco/api/common/version_patches/ecoportal_api.rb +4 -0
  11. data/lib/eco/api/common/version_patches/{base_model.rb → ecoportal_api/base_model.rb} +0 -0
  12. data/lib/eco/api/common/version_patches/{external_person.rb → ecoportal_api/external_person.rb} +0 -0
  13. data/lib/eco/api/common/version_patches/{internal_person.rb → ecoportal_api/internal_person.rb} +0 -0
  14. data/lib/eco/api/common/version_patches/hash.rb +2 -0
  15. data/lib/eco/api/common/version_patches/hash/deep_merge.rb +34 -0
  16. data/lib/eco/api/error.rb +133 -0
  17. data/lib/eco/api/error/handler.rb +19 -0
  18. data/lib/eco/api/error/handlers.rb +22 -0
  19. data/lib/eco/api/organization/people.rb +11 -11
  20. data/lib/eco/api/organization/policy_groups.rb +8 -0
  21. data/lib/eco/api/policies.rb +26 -3
  22. data/lib/eco/api/policies/policy.rb +4 -5
  23. data/lib/eco/api/session.rb +27 -18
  24. data/lib/eco/api/session/batch.rb +12 -6
  25. data/lib/eco/api/session/batch/errors.rb +134 -0
  26. data/lib/eco/api/session/batch/job.rb +213 -0
  27. data/lib/eco/api/session/batch/jobs.rb +72 -0
  28. data/lib/eco/api/session/batch/jobs_groups.rb +85 -0
  29. data/lib/eco/api/session/batch/status.rb +133 -0
  30. data/lib/eco/api/session/config.rb +36 -14
  31. data/lib/eco/api/session/config/base_config.rb +2 -0
  32. data/lib/eco/api/session/config/people.rb +8 -0
  33. data/lib/eco/api/session/config/post_launch.rb +58 -0
  34. data/lib/eco/api/session/config/workflow.rb +189 -0
  35. data/lib/eco/api/session/task.rb +49 -6
  36. data/lib/eco/api/usecases.rb +137 -2
  37. data/lib/eco/api/usecases/base_case.rb +20 -8
  38. data/lib/eco/api/usecases/base_io.rb +97 -0
  39. data/lib/eco/api/usecases/default_case.rb +19 -0
  40. data/lib/eco/api/usecases/default_cases.rb +2 -2
  41. data/lib/eco/api/usecases/default_cases/change_email_case.rb +2 -2
  42. data/lib/eco/api/usecases/default_cases/create_case.rb +2 -2
  43. data/lib/eco/api/usecases/default_cases/create_details_case.rb +2 -2
  44. data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +2 -2
  45. data/lib/eco/api/usecases/default_cases/delete_case.rb +2 -2
  46. data/lib/eco/api/usecases/default_cases/email_as_id_case.rb +2 -2
  47. data/lib/eco/api/usecases/default_cases/hris_case.rb +2 -2
  48. data/lib/eco/api/usecases/default_cases/new_email_case.rb +2 -2
  49. data/lib/eco/api/usecases/default_cases/new_id_case.rb +2 -2
  50. data/lib/eco/api/usecases/default_cases/recover_db_case.rb +11 -8
  51. data/lib/eco/api/usecases/default_cases/refresh_presets_case.rb +2 -2
  52. data/lib/eco/api/usecases/default_cases/reinvite_case.rb +2 -2
  53. data/lib/eco/api/usecases/default_cases/remove_account_case.rb +2 -2
  54. data/lib/eco/api/usecases/default_cases/reset_landing_page_case.rb +2 -2
  55. data/lib/eco/api/usecases/default_cases/set_default_tag_case.rb +2 -2
  56. data/lib/eco/api/usecases/default_cases/set_supervisor_case.rb +2 -2
  57. data/lib/eco/api/usecases/default_cases/switch_supervisor_case.rb +2 -2
  58. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +4 -4
  59. data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +3 -3
  60. data/lib/eco/api/usecases/default_cases/update_case.rb +2 -2
  61. data/lib/eco/api/usecases/default_cases/update_details_case.rb +2 -2
  62. data/lib/eco/api/usecases/default_cases/upsert_case.rb +2 -2
  63. data/lib/eco/api/usecases/use_case.rb +23 -36
  64. data/lib/eco/api/usecases/use_case_chain.rb +14 -24
  65. data/lib/eco/api/usecases/use_case_io.rb +23 -75
  66. data/lib/eco/assets.rb +11 -11
  67. data/lib/eco/cli.rb +37 -0
  68. data/lib/eco/cli/config.rb +63 -1
  69. data/lib/eco/cli/config/default.rb +15 -0
  70. data/lib/eco/cli/config/default/filters.rb +69 -0
  71. data/lib/eco/cli/config/default/input.rb +21 -0
  72. data/lib/eco/cli/config/default/options.rb +47 -0
  73. data/lib/eco/cli/config/default/people.rb +39 -0
  74. data/lib/eco/cli/config/default/usecases.rb +63 -0
  75. data/lib/eco/cli/config/default/workflow.rb +86 -0
  76. data/lib/eco/cli/config/input.rb +40 -0
  77. data/lib/eco/cli/config/options_set.rb +35 -0
  78. data/lib/eco/cli/config/people_filters.rb +38 -0
  79. data/lib/eco/cli/config/use_cases.rb +87 -0
  80. data/lib/eco/cli/scripting/args_helpers.rb +10 -4
  81. data/lib/eco/cli/scripting/argument.rb +6 -0
  82. data/lib/eco/language/models/collection.rb +1 -0
  83. data/lib/eco/version.rb +1 -1
  84. metadata +32 -12
  85. data/lib/eco/api/policies/base_policy.rb +0 -14
  86. data/lib/eco/api/policies/used_policies.rb +0 -37
  87. data/lib/eco/api/session/batch_job.rb +0 -215
  88. data/lib/eco/api/session/batch_jobs.rb +0 -62
  89. data/lib/eco/api/session/batch_status.rb +0 -205
  90. data/lib/eco/api/session/job_groups.rb +0 -75
  91. data/lib/eco/api/usecases/use_group.rb +0 -124
  92. data/lib/eco/cli/config/options.rb +0 -11
@@ -0,0 +1,189 @@
1
+ module Eco
2
+ module API
3
+ class Session
4
+ class Config
5
+ class Workflow
6
+ extend Eco::API::Common::ClassHelpers
7
+
8
+ @workflow = {
9
+ load: {input: nil, people: {get: nil, filter: nil}},
10
+ usecases: nil,
11
+ launch_jobs: nil,
12
+ post_launch: {usecases: nil, launch_jobs: nil},
13
+ end: nil
14
+ }
15
+
16
+ class << self
17
+ def stages
18
+ @stages ||= (@workflow || {}).keys
19
+ end
20
+
21
+ def validate_stage(stage)
22
+ "Unknown Workflow stage '#{stage}'. Should be any of #{stages}" unless stages.include?(stage)
23
+ end
24
+
25
+ def titleize(key)
26
+ str_name = key.to_s.strip.split(/[\-\_ ]/i).compact.map do |str|
27
+ str.slice(0).upcase + str.slice(1..-1).downcase
28
+ end.join("")
29
+ end
30
+
31
+ def get_model(key)
32
+ raise "Expected Symbol. Given: #{key.class}" unless key.is_a?(Symbol)
33
+ workflow = @workflow[key]
34
+ raise "Expected Array. Given #{model.class}" unless !workflow || workflow.is_a?(Hash)
35
+
36
+ class_name = titleize(key.to_s)
37
+ full_class_name = "#{self}::#{class_name}"
38
+
39
+ if target_class = resolve_class(full_class_name, exception: false)
40
+ else
41
+ target_class = Class.new(Eco::API::Session::Config::Workflow) do
42
+ @workflow = workflow
43
+ end
44
+ self.const_set class_name, target_class
45
+ end
46
+
47
+ target_class
48
+ end
49
+
50
+ end
51
+
52
+ attr_reader :config
53
+ attr_reader :name
54
+
55
+ def initialize(name = nil, _parent: self, config:)
56
+ @config = config
57
+ @name = name
58
+
59
+ @stages = {}
60
+ @_parent = _parent
61
+
62
+ @pending = true
63
+ # moments
64
+ @on = nil
65
+ @before = []
66
+ @after = []
67
+ end
68
+
69
+ def pending?
70
+ @pending
71
+ end
72
+
73
+ def skip!
74
+ @skip = true
75
+ @pending = false
76
+ end
77
+
78
+ def skip?
79
+ return @skip if instance_variable_defined?(:@skip)
80
+ return false if root?
81
+ @_parent.skip?
82
+ end
83
+
84
+ def for(key = nil)
85
+ raise "A block should be given." unless block_given?
86
+ if !key
87
+ yield(self)
88
+ else
89
+ stage(key).for(&Proc.new)
90
+ end
91
+ self
92
+ end
93
+
94
+ def on(key = nil, &block)
95
+ raise "A block should be given." unless block
96
+ if !key
97
+ @on = block
98
+ else
99
+ stage(key).on(&block)
100
+ end
101
+ self
102
+ end
103
+
104
+ def before(key = nil, &block)
105
+ raise "A block should be given." unless block
106
+ if !key
107
+ @before.push(block)
108
+ else
109
+ stage(key).before(&block)
110
+ end
111
+ self
112
+ end
113
+
114
+ def after(key = nil, &block)
115
+ raise "A block should be given." unless block
116
+ if !key
117
+ @after.push(block)
118
+ else
119
+ stage(key).after(&block)
120
+ end
121
+ self
122
+ end
123
+
124
+ def run(key = nil, io:, &block)
125
+ if key
126
+ io = stage(key).run(io: io, &block)
127
+ elsif pending?
128
+ @before.each {|c| io = c.call(self, io)}
129
+
130
+ unless skip?
131
+ io.session.logger.debug("(Workflow: #{path}) running now")
132
+ if block
133
+ io = block.call(self, io)
134
+ else
135
+ existing_stages.each {|stg| io = stg.run(io: io)}
136
+
137
+ unless ready?
138
+ msg = "(Workflow: #{path}) 'on' callback is not defined, nor block given"
139
+ io.session.logger.debug(msg)
140
+ end
141
+ io = @on.call(self, io) if ready?
142
+ end
143
+ @pending = false
144
+ end
145
+
146
+ @after.each {|c| io = c.call(self, io)}
147
+ end
148
+ io
149
+ end
150
+
151
+ protected
152
+
153
+ def path
154
+ return name if root?
155
+ "#{@_parent.path}:#{name}"
156
+ end
157
+
158
+ def root?
159
+ @_parent == self
160
+ end
161
+
162
+ def ready?
163
+ !!@on
164
+ end
165
+
166
+ def existing_stages
167
+ # sort defined stages by stage order
168
+ sorted_keys = self.class.stages & @stages.keys
169
+ sorted_keys.map {|k| stage(k)}
170
+ end
171
+
172
+ def ready_stages
173
+ exiting_stages.select {|s| s.ready?}
174
+ end
175
+
176
+ def stages_ready?
177
+ existing_stages.all? {|s| s.ready?}
178
+ end
179
+
180
+ def stage(key)
181
+ self.class.validate_stage(key)
182
+ @stages[key] ||= self.class.get_model(key).new(key, _parent: self, config: config)
183
+ end
184
+
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -15,21 +15,64 @@ module Eco
15
15
  Eco::API::Organization::People.new(people)
16
16
  end
17
17
 
18
- def search(data, silent: true)
18
+ def people_refresh(people:, include_created: true)
19
+ ini = people.length
20
+ if include_created
21
+ session.job_groups.find_jobs(type: :create).map do |job|
22
+ people = people.merge(job.people)
23
+ end
24
+ end
25
+
26
+ created = people.length - ini
27
+ msg = "Going to refresh #{people.length} people with server data"
28
+ msg += " (including #{created} that were created)" if created > 0
29
+ session.logger.info(msg)
30
+ status = session.batch.get_people(people, silent: true)
31
+ entries = status.people
32
+
33
+ missing = people.length - entries.length
34
+ session.logger.error("Missed to obtain #{missing} people during the refresh") if missing > 0
35
+
36
+ Eco::API::Organization::People.new(status.people)
37
+ end
38
+
39
+ def search(data, options: {}, silent: true)
40
+ strict_search = session.config.people.strict_search? && (!options[:search]&.key?(:strict) || options.dig(:search, :strict))
41
+
19
42
  # to scope people to be fresh data got via api
20
- session.logger.info("going to api get entries...")
43
+ session.logger.info("going to api get #{data.length} entries...")
44
+
21
45
  status = session.batch.search(data, silent: silent)
22
46
  people = Eco::API::Organization::People.new(status.people)
47
+
23
48
  # get the supervisors
24
- session.logger.info("going to api get supervisors...")
49
+ supers = people.each_with_object([]) do |person, sup|
50
+ if sup_id = person.supervisor_id
51
+ spr = {"id" => sup_id}
52
+ sup.push(spr) unless sup.include?(spr) || people.person(id: sup_id, external_id: sup_id)
53
+ end
54
+ end
55
+
56
+ if supers.length > 0
57
+ session.logger.info("going to api get #{supers.length} current supervisors...")
58
+ status = session.batch.search(supers, silent: silent)
59
+ people = people.merge(status.people, strict: strict_search)
60
+ end
61
+
25
62
  supers = data.each_with_object([]) do |entry, sup|
26
63
  if entry.respond_to?(:supervisor_id) && !entry.supervisor_id.to_s.strip.empty?
64
+ sup_id = entry.supervisor_id
27
65
  spr = {"id" => entry.supervisor_id}
28
- sup.push(spr) unless sup.include?(spr)
66
+ sup.push(spr) unless sup.include?(spr) || people.person(id: sup_id, external_id: sup_id)
29
67
  end
30
68
  end
31
- status = session.batch.search(supers, silent: silent)
32
- people = people.merge(status.people)
69
+
70
+ if supers.length > 0
71
+ session.logger.info("going to api get #{supers.length} supervisors as per entries...")
72
+ status = session.batch.search(supers, silent: silent)
73
+ people = people.merge(status.people, strict: strict_search)
74
+ end
75
+
33
76
  session.logger.info("could get #{people.length} people (out of #{data.length} entries)")
34
77
  people
35
78
  end
@@ -1,13 +1,148 @@
1
1
  module Eco
2
2
  module API
3
- module UseCases
3
+ class UseCases
4
+ class UnkownCase < Exception
5
+ def initialize(msg = nil, case_name: nil, type: nil)
6
+ msg ||= "Unkown case"
7
+ msg += ". Case name '#{case_name}'" if case_name
8
+ msg += ". Case type '#{type}'" if type
9
+ super(msg)
10
+ end
11
+ end
12
+
13
+ class AmbiguousCaseReference < Exception
14
+ def initialize(msg = nil, case_name: nil)
15
+ msg ||= "You must specify type when there are multiple cases with same name"
16
+ msg += ". Case name '#{case_name}'" if case_name
17
+ super(msg)
18
+ end
19
+
20
+ end
21
+
22
+ include Enumerable
23
+
24
+ def initialize()
25
+ @usecases = {}
26
+ @cache_init = false
27
+ @cases_by_name = {}
28
+ end
29
+
30
+ def length
31
+ count
32
+ end
33
+
34
+ def empty?
35
+ count == 0
36
+ end
37
+
38
+ def each(params: {}, &block)
39
+ return to_enum(:each) unless block
40
+ items.each(&block)
41
+ end
42
+
43
+ def items
44
+ @usecases.values
45
+ end
46
+
47
+ def add(usecase)
48
+ raise "Expected Eco::API::UseCases::UseCase object. Given: #{usecase}" if !usecase || !usecase.is_a?(Eco::API::UseCases::UseCase)
49
+ name = usecase.name
50
+ type = usecase.type
51
+ puts "Warning: overriding '#{type.to_s}' case #{name}" if self.defined?(name, type: type)
52
+ @cache_init = false
53
+ @usecases[key(name, type)] = usecase
54
+ usecase
55
+ end
56
+
57
+ def define(name, type:, &block)
58
+ Eco::API::UseCases::UseCase.new(name, type: type, root: self, &block).tap do |usecase|
59
+ add(usecase)
60
+ end
61
+ end
62
+
63
+ def defined?(name, type: nil)
64
+ return @usecases.key?(key(name, type)) if type
65
+ name?(name)
66
+ end
67
+
68
+ def name?(name)
69
+ !!by_name[name]
70
+ end
71
+
72
+ def names
73
+ by_name.keys
74
+ end
75
+
76
+ def types(name)
77
+ return nil if !name?(name)
78
+ by_name[name].map { |usecase| usecase.type }
79
+ end
80
+
81
+ def case(name, type: nil)
82
+ if type && target_case = @usecases[key(name, type)]
83
+ return target_case
84
+ elsif type
85
+ raise UseCases::UnkownCase.new(case_name: name, type: type)
86
+ end
87
+ raise UseCases::UnkownCase.new(case_name: name, type: type) unless cases = by_name[name]
88
+ raise UseCases::AmbiguousCaseReference.new(case_name: name) if cases.length > 1
89
+ cases.first
90
+ end
91
+
92
+ # merges cases overriding self for exisint parsers
93
+ def merge(cases)
94
+ return self if !cases
95
+ raise "Expected a Eco::API::UseCases object. Given #{cases.class}" if !cases.is_a?(Eco::API::UseCases)
96
+ cases_hash = cases.to_h
97
+
98
+ @usecases.merge!(cases_hash)
99
+
100
+ cases_hash.transform_values do |usecase|
101
+ usecase.root = self
102
+ end
103
+
104
+ @cache_init = false
105
+ self
106
+ end
107
+
108
+ protected
109
+
110
+ def to_h
111
+ @usecases
112
+ end
113
+
114
+ private
115
+
116
+ def by_name
117
+ init_caches
118
+ @by_name
119
+ end
120
+
121
+ def init_caches
122
+ return true if @cache_init
123
+ @cache_init = true
124
+ @by_name = @usecases.values.group_by { |usecase| usecase.name }
125
+ end
126
+
127
+ def key(name, type)
128
+ name.to_s + type.to_s
129
+ end
130
+
131
+ def name(key)
132
+ key.to_s.split(":").first
133
+ end
134
+
135
+ def type
136
+ key.to_s.split(":").last&.to_sym
137
+ end
4
138
  end
5
139
  end
6
140
  end
7
141
 
8
142
  require_relative 'usecases/base_case'
143
+ require_relative 'usecases/default_case'
9
144
  require_relative 'usecases/use_case'
10
145
  require_relative 'usecases/use_case_chain'
146
+ require_relative 'usecases/base_io'
11
147
  require_relative 'usecases/use_case_io'
12
- require_relative 'usecases/use_group'
13
148
  require_relative 'usecases/default_cases'
@@ -1,16 +1,28 @@
1
1
  module Eco
2
2
  module API
3
- module UseCases
3
+ class UseCases
4
4
  class BaseCase
5
-
6
- def initialize(cases, **options)
7
- raise "Expected UseGroup. Given: #{cases.class}" unless cases.is_a?(UseGroup)
8
- @cases = cases
9
- @options = options
5
+
6
+ class InvalidType < Exception
7
+ def initialize(msg = nil, type:, types:)
8
+ msg ||= "Invalid type."
9
+ msg = "Given type '#{type}'. Valid types: #{types}"
10
+ super(msg)
11
+ end
10
12
  end
11
13
 
12
- def process
13
- raise "You should reimplement this method"
14
+ @types = [:import, :filter, :transform, :sync, :export]
15
+
16
+ class << self
17
+ attr_reader :types
18
+
19
+ def valid_type?(type)
20
+ types.include?(type)
21
+ end
22
+
23
+ def validate_type(type)
24
+ raise InvalidType.new(type: type, types: types) unless valid_type?(type)
25
+ end
14
26
  end
15
27
 
16
28
  end