eco-helpers 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +3 -0
  4. data/README.md +20 -0
  5. data/eco-helpers.gemspec +34 -0
  6. data/lib/eco-helpers.rb +15 -0
  7. data/lib/eco/api.rb +13 -0
  8. data/lib/eco/api/common.rb +10 -0
  9. data/lib/eco/api/common/people.rb +17 -0
  10. data/lib/eco/api/common/people/base_parser.rb +16 -0
  11. data/lib/eco/api/common/people/default_parsers.rb +40 -0
  12. data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +28 -0
  13. data/lib/eco/api/common/people/default_parsers/date_parser.rb +33 -0
  14. data/lib/eco/api/common/people/default_parsers/multi_parser.rb +33 -0
  15. data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +23 -0
  16. data/lib/eco/api/common/people/default_parsers/select_parser.rb +29 -0
  17. data/lib/eco/api/common/people/entries.rb +120 -0
  18. data/lib/eco/api/common/people/person_entry.rb +380 -0
  19. data/lib/eco/api/common/people/person_factory.rb +114 -0
  20. data/lib/eco/api/common/people/person_modifier.rb +62 -0
  21. data/lib/eco/api/common/people/person_parser.rb +140 -0
  22. data/lib/eco/api/common/people/types.rb +47 -0
  23. data/lib/eco/api/common/session.rb +15 -0
  24. data/lib/eco/api/common/session/base_session.rb +46 -0
  25. data/lib/eco/api/common/session/environment.rb +47 -0
  26. data/lib/eco/api/common/session/file_manager.rb +90 -0
  27. data/lib/eco/api/common/session/logger.rb +105 -0
  28. data/lib/eco/api/common/session/mailer.rb +92 -0
  29. data/lib/eco/api/common/session/s3_uploader.rb +110 -0
  30. data/lib/eco/api/common/version_patches.rb +11 -0
  31. data/lib/eco/api/common/version_patches/external_person.rb +11 -0
  32. data/lib/eco/api/eco_faker.rb +59 -0
  33. data/lib/eco/api/organization.rb +13 -0
  34. data/lib/eco/api/organization/account.rb +23 -0
  35. data/lib/eco/api/organization/people.rb +118 -0
  36. data/lib/eco/api/organization/policy_groups.rb +51 -0
  37. data/lib/eco/api/organization/preferences.rb +28 -0
  38. data/lib/eco/api/organization/preferences_reference.json +23 -0
  39. data/lib/eco/api/organization/presets.rb +138 -0
  40. data/lib/eco/api/organization/presets_backup.rb +220 -0
  41. data/lib/eco/api/organization/presets_values.json +10 -0
  42. data/lib/eco/api/organization/tag_tree.rb +134 -0
  43. data/lib/eco/api/organization_old.rb +73 -0
  44. data/lib/eco/api/session.rb +180 -0
  45. data/lib/eco/api/session/batch.rb +132 -0
  46. data/lib/eco/api/session/batch_job.rb +152 -0
  47. data/lib/eco/api/session/batch_jobs.rb +131 -0
  48. data/lib/eco/api/session/batch_status.rb +138 -0
  49. data/lib/eco/api/session/task.rb +92 -0
  50. data/lib/eco/api/session_config.rb +179 -0
  51. data/lib/eco/api/session_config/api.rb +47 -0
  52. data/lib/eco/api/session_config/apis.rb +78 -0
  53. data/lib/eco/api/session_config/files.rb +30 -0
  54. data/lib/eco/api/session_config/logger.rb +54 -0
  55. data/lib/eco/api/session_config/mailer.rb +65 -0
  56. data/lib/eco/api/session_config/people.rb +89 -0
  57. data/lib/eco/api/session_config/s3_bucket.rb +62 -0
  58. data/lib/eco/api/session_config/use_cases.rb +30 -0
  59. data/lib/eco/api/usecases.rb +12 -0
  60. data/lib/eco/api/usecases/base_case.rb +14 -0
  61. data/lib/eco/api/usecases/case_data.rb +13 -0
  62. data/lib/eco/api/usecases/default_cases.rb +53 -0
  63. data/lib/eco/api/usecases/default_cases/change_email_case.rb +47 -0
  64. data/lib/eco/api/usecases/default_cases/create_details_case.rb +29 -0
  65. data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +49 -0
  66. data/lib/eco/api/usecases/default_cases/delete_case.rb +20 -0
  67. data/lib/eco/api/usecases/default_cases/email_as_id_case.rb +24 -0
  68. data/lib/eco/api/usecases/default_cases/hris_case.rb +67 -0
  69. data/lib/eco/api/usecases/default_cases/new_email_case.rb +26 -0
  70. data/lib/eco/api/usecases/default_cases/new_id_case.rb +26 -0
  71. data/lib/eco/api/usecases/default_cases/refresh_presets.rb +25 -0
  72. data/lib/eco/api/usecases/default_cases/reinvite_case.rb +22 -0
  73. data/lib/eco/api/usecases/default_cases/remove_account_case.rb +36 -0
  74. data/lib/eco/api/usecases/default_cases/reset_landing_page_case.rb +24 -0
  75. data/lib/eco/api/usecases/default_cases/set_default_tag_case.rb +44 -0
  76. data/lib/eco/api/usecases/default_cases/set_supervisor_case.rb +39 -0
  77. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +36 -0
  78. data/lib/eco/api/usecases/default_cases/update_details_case.rb +30 -0
  79. data/lib/eco/api/usecases/default_cases/upsert_account_case.rb +35 -0
  80. data/lib/eco/api/usecases/use_case.rb +177 -0
  81. data/lib/eco/api/usecases/use_group.rb +104 -0
  82. data/lib/eco/cli.rb +9 -0
  83. data/lib/eco/cli/input.rb +109 -0
  84. data/lib/eco/cli/input_multi.rb +137 -0
  85. data/lib/eco/cli/root.rb +8 -0
  86. data/lib/eco/cli/session.rb +9 -0
  87. data/lib/eco/cli/session/batch.rb +9 -0
  88. data/lib/eco/common.rb +7 -0
  89. data/lib/eco/common/base_cli.rb +116 -0
  90. data/lib/eco/common/language.rb +9 -0
  91. data/lib/eco/data.rb +9 -0
  92. data/lib/eco/data/crypto.rb +7 -0
  93. data/lib/eco/data/crypto/encryption.rb +318 -0
  94. data/lib/eco/data/files.rb +10 -0
  95. data/lib/eco/data/files/directory.rb +93 -0
  96. data/lib/eco/data/files/file_pattern.rb +32 -0
  97. data/lib/eco/data/files/helpers.rb +90 -0
  98. data/lib/eco/data/mapper.rb +54 -0
  99. data/lib/eco/data/random.rb +10 -0
  100. data/lib/eco/data/random/distribution.rb +133 -0
  101. data/lib/eco/data/random/fake.rb +320 -0
  102. data/lib/eco/data/random/values.rb +80 -0
  103. data/lib/eco/language.rb +12 -0
  104. data/lib/eco/language/curry.rb +28 -0
  105. data/lib/eco/language/hash_transform.rb +68 -0
  106. data/lib/eco/language/hash_transform_modifier.rb +114 -0
  107. data/lib/eco/language/match.rb +30 -0
  108. data/lib/eco/language/match_modifier.rb +190 -0
  109. data/lib/eco/language/models.rb +11 -0
  110. data/lib/eco/language/models/attribute_parser.rb +38 -0
  111. data/lib/eco/language/models/collection.rb +181 -0
  112. data/lib/eco/language/models/modifier.rb +68 -0
  113. data/lib/eco/language/models/wrap.rb +114 -0
  114. data/lib/eco/language/values_at.rb +159 -0
  115. data/lib/eco/lexic/dictionary.rb +33 -0
  116. data/lib/eco/lexic/dictionary/dictionary.txt +355484 -0
  117. data/lib/eco/lexic/dictionary/tags.json +38 -0
  118. data/lib/eco/scripting.rb +30 -0
  119. data/lib/eco/scripting/README.md +11 -0
  120. data/lib/eco/scripting/arguments.rb +40 -0
  121. data/lib/eco/tester.rb +97 -0
  122. data/lib/eco/version.rb +3 -0
  123. metadata +325 -0
@@ -0,0 +1,152 @@
1
+ module Eco
2
+ module API
3
+ class Session
4
+ class BatchJob < API::Common::Session::BaseSession
5
+ TYPES = [:create, :update, :delete, :get]
6
+ SETS = [:core, :details, :account]
7
+
8
+ attr_reader :name, :status
9
+
10
+ def initialize(name, type:, sets:, root:)
11
+ raise "A name is required to refer a job. Given: #{name}" if !name
12
+ raise "Type should be one of #{TYPES}. Given: #{type}" if !BatchJob.valid_type?(type)
13
+ raise "Sets should be some of #{SETS}. Given: #{sets}" if !BatchJob.valid_sets?(sets)
14
+ super(root.enviro)
15
+
16
+ @name = name
17
+ @type = type
18
+ @sets = [sets].flatten
19
+ @root = root
20
+ reset
21
+ end
22
+
23
+ def reset
24
+ @queue = []
25
+ @callbacks = {}
26
+ @status = nil
27
+ end
28
+
29
+ def signature
30
+ "job \"#{@name}\" ['#{@type.to_s.upcase}': #{sets_title}]"
31
+ end
32
+
33
+ def match?(type:, sets:)
34
+ sets = [sets].flatten
35
+ type == @type && (sets.order == @sets.order)
36
+ end
37
+
38
+ def pending?
39
+ @queue.length > 0
40
+ end
41
+
42
+ def add(data)
43
+ unless !data
44
+ @queue.push(data)
45
+ @callbacks[data] = Proc.new if block_given?
46
+ end
47
+ end
48
+
49
+ def people
50
+ Eco::API::Organization::People.new(@queue)
51
+ end
52
+
53
+ def processed_queue
54
+ @queue.map do |entry|
55
+ callback = @callbacks[entry]
56
+ e = entry
57
+ e = callback.call(entry) if callback
58
+ e = nil if as_update(e).empty?
59
+ e
60
+ end.compact
61
+ end
62
+
63
+ def launch(simulate: false)
64
+ queue = processed_queue
65
+ launch_feedback(queue, simulate ? 2500 : 800)
66
+
67
+ if !simulate && queue.length > 0
68
+ backup_update(queue)
69
+ @status = batch.launch(queue, method: @type.to_s)
70
+ @status.root = self
71
+ end
72
+
73
+ logger.info("Simulate: this would have launched: '#{@type.to_s}'") if simulate
74
+ return @status
75
+ end
76
+
77
+ def core?
78
+ sets.include?(:core)
79
+ end
80
+
81
+ def details?
82
+ sets.include?(:dettails)
83
+ end
84
+
85
+ def account?
86
+ sets.include?(:account)
87
+ end
88
+
89
+ def self.valid_type?(value)
90
+ TYPES.include?(value)
91
+ end
92
+
93
+ def self.valid_sets?(value)
94
+ sets = [value].flatten
95
+ sets.all? { |s| SETS.include?(s) }
96
+ end
97
+
98
+ private
99
+
100
+ def as_update(update)
101
+ hash = update if update.is_a?(Hash)
102
+ hash = update.as_update if update.is_a?(Ecoportal::API::V1::Person)
103
+ fields = hash&.dig('details', 'fields')
104
+ fields&.map! { |fld| fld&.slice("id", "alt_id", "value") }
105
+ hash || {}
106
+ end
107
+
108
+ def sets_title
109
+ "#{@sets.map {|s| s.to_s}.join(", ")}"
110
+ end
111
+
112
+ def launch_feedback(data, max_chars = 800)
113
+ if !data || !data.is_a?(Array) || data.empty?
114
+ logger.warn("#{"*" * 20} Nothing for #{signature} so far :) #{"*" * 20}")
115
+ return
116
+ end
117
+ header = ("*" * 20) + " #{signature} - Feedback Sample " + ("*" * 20)
118
+ logger.info(header)
119
+
120
+ sample_length = 1
121
+ sample = data.slice(0, 20).map do |entry|
122
+ update = as_update(entry)
123
+ max_chars -= update.pretty_inspect.length
124
+ sample_length += 1 if max_chars > 0
125
+ update
126
+ end
127
+
128
+ logger.info("#{sample.slice(0, sample_length).pretty_inspect}")
129
+ logger.info("#{@type.to_s.upcase} length: #{data.length}")
130
+ logger.info("*" * header.length)
131
+ end
132
+
133
+ def backup_update(data)
134
+ data_body = data.map { |u| as_update(u) }
135
+ dir = config.people.requests_folder
136
+ file = File.join(dir, "#{@type.to_s}_data.json")
137
+ file_manager.save_json(data_body, file, :timestamp)
138
+ end
139
+
140
+ def session
141
+ @root.session
142
+ end
143
+
144
+ def batch
145
+ session.batch
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,131 @@
1
+ module Eco
2
+ module API
3
+ class Session
4
+ class JobGroups < API::Common::Session::BaseSession
5
+ DELAY_BETWEEN_GROUPS = 2
6
+
7
+ def initialize(session:)
8
+ raise("JobGroups requires a session object") unless session.is_a?(API::Session)
9
+ super(session.enviro)
10
+ @session = session
11
+ reset
12
+ end
13
+
14
+ def reset
15
+ @order = []
16
+ @groups = {}
17
+ @callbacks = {}
18
+ end
19
+
20
+ def [](name)
21
+ @groups[name]
22
+ end
23
+
24
+ def exists?(name)
25
+ @groups.key?(name)
26
+ end
27
+
28
+ def new(name, order: :last)
29
+ raise("Can't create job group named #{'name'} because it already exists.") if exists?(name)
30
+
31
+ group = BatchJobs.new(name, session: @session)
32
+ @groups[name] = group
33
+
34
+ if order == :last
35
+ @order.push(group)
36
+ else
37
+ @order.unshift(group)
38
+ end
39
+
40
+ @callbacks[group] = Proc.new if block_given?
41
+
42
+ group
43
+ end
44
+
45
+ def pending?
46
+ @groups.any? do |group|
47
+ group.pending?
48
+ end
49
+ end
50
+
51
+ def launch(simulate: false)
52
+ groups_status = {}
53
+ @order.each.with_index do |group, idx|
54
+ groups_status[group] = group_status = group.launch(simulate: simulate)
55
+ callback = @callbacks[group]
56
+ callback.call(group, group_status) if callback
57
+ JobGroups.counter(DELAY_BETWEEN_GROUPS) if !simulate && idx < @order.length - 1
58
+ end
59
+ return groups_status
60
+ end
61
+
62
+ def self.counter(seconds)
63
+ puts "\n"
64
+ while seconds + 1 > 0 do
65
+ print " Waiting #{seconds}\r"
66
+ $stdout.flush
67
+ seconds -= 1
68
+ sleep 1
69
+ end
70
+ print "#{" " * 40}"
71
+ $stdout.flush
72
+ puts ""
73
+ end
74
+
75
+ end
76
+
77
+ class BatchJobs < API::Common::Session::BaseSession
78
+ attr_reader :name, :session
79
+
80
+ def initialize(name, session:)
81
+ raise("BatchJobs requires a session object") unless session.is_a?(API::Session)
82
+ super(session.enviro)
83
+ @session = session
84
+ @name = name
85
+ reset
86
+ end
87
+
88
+ def reset
89
+ @jobs = {}
90
+ @callbacks = {}
91
+ end
92
+
93
+ def [](name)
94
+ @jobs[name]
95
+ end
96
+
97
+ def exists?(name)
98
+ @jobs.key?(name)
99
+ end
100
+
101
+ def new(name, type:, sets:)
102
+ raise("Can't create job named '#{name}' because it already exists.") if exists?(name)
103
+
104
+ job = BatchJob.new(name, type: type, sets: sets, root: self)
105
+ @jobs[name] = job
106
+ @callbacks[job] = Proc.new if block_given?
107
+
108
+ job
109
+ end
110
+
111
+ def pending?
112
+ @jobs.keys.any? do |key|
113
+ @jobs[key].pending?
114
+ end
115
+ end
116
+
117
+ def launch(simulate: false)
118
+ group_status = {}
119
+ @jobs.each do |name, job|
120
+ group_status[job] = job_status = job.launch(simulate: simulate)
121
+ callback = @callbacks[job]
122
+ callback.call(job, job_status) if callback
123
+ end
124
+
125
+ return group_status
126
+ end
127
+
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,138 @@
1
+ require 'json'
2
+ require 'pp'
3
+ require 'securerandom' # for uuid (perhaps metter to have structure i.e. Session:id-Batch:id)
4
+
5
+ module Eco
6
+ module API
7
+ class Session
8
+ class BatchStatus < Common::Session::BaseSession
9
+ attr_reader :queue, :method
10
+ attr_reader :root
11
+
12
+ def initialize(e, queue:, method:)
13
+ super(e)
14
+
15
+ unless queue && queue.is_a?(Array)
16
+ msg = "In batch operations you must batch an array. Received: #{queue}"
17
+ logger.fatal(msg)
18
+ raise msg
19
+ end
20
+ @method = method
21
+ @queue = queue
22
+ @hash = @queue.each_with_index.map do |entry, i|
23
+ [entry, i]
24
+ end.to_h
25
+ @responses = Array(0..@queue.length-1)
26
+ end
27
+
28
+ def root=(object)
29
+ @root = object
30
+ end
31
+
32
+ def [](key)
33
+ @responses[to_index(key)]
34
+ end
35
+
36
+ def []=(key, response)
37
+ @responses[to_index(key)] = response
38
+ end
39
+
40
+ def received?(key)
41
+ !!self[key]
42
+ end
43
+
44
+ def success?(key)
45
+ self[key]&.success?
46
+ end
47
+
48
+ def people
49
+ raise "This batch wasn't a 'get'. Can't obtain people without 'get' method" unless method == "get"
50
+ out = Array(0..queue.length-1)
51
+ @responses.each_with_index do |respose, i|
52
+ out[i] = response.result
53
+ end
54
+ out
55
+ end
56
+
57
+ def error_queries
58
+ queue.each_with_index.map do |query,i|
59
+ self[i].success? ? nil : query
60
+ end.compact
61
+ end
62
+
63
+ def errors?
64
+ queue.any? {|query| !self[query].success?}
65
+ end
66
+
67
+ def errors_count
68
+ error_queries.length
69
+ end
70
+
71
+ def str_error(key)
72
+ msg = ""
73
+ unless success?(key)
74
+ i = to_index(key)
75
+ entry = queue[i]
76
+ response = self[i]
77
+ msg = "Error #{response.status}: #{response.body}\n"
78
+ msg += "-- Failed to batch #{method} (entry #{i+1}). Person: #{person_ref(entry)}"
79
+ end
80
+ msg
81
+ end
82
+
83
+ def str_errors(sort: :by_status)
84
+ queries = error_queries
85
+ if sort == :by_status
86
+ queries = error_queries.sort_by do |query|
87
+ self[query].status
88
+ end
89
+ end
90
+ strs = []
91
+ if queries.length > 0
92
+ strs = queries.map {|query| str_error(query)}
93
+ end
94
+ strs
95
+ end
96
+
97
+ def print_error(key)
98
+ unless success?(key)
99
+ logger.error(str_error(key))
100
+ end
101
+ end
102
+
103
+ def print_errors(sort: :by_status)
104
+ strs = str_errors(sort: sort)
105
+ if strs.length > 0
106
+ logger.error(strs.join("\n"))
107
+ #strs.each {|str| logger.error(str)}
108
+ else
109
+ logger.info("There were no errors for the current batch '#{method}'!! ;)")
110
+ end
111
+ end
112
+
113
+
114
+ private
115
+
116
+ def person_ref(entry)
117
+ is_person = entry.is_a?(Ecoportal::API::Internal::Person) || entry.is_a?(Ecoportal::API::V1::Person)
118
+ ref = nil
119
+ ref = "'#{entry.name}' ('#{entry.external_id}': '#{entry.email}')" if is_person
120
+ ref
121
+ end
122
+
123
+ def to_index(key)
124
+ key.is_a?(Integer) ? valid_index(index: key) : valid_index(entry: key)
125
+ end
126
+
127
+ def valid_index(index: nil, entry: nil)
128
+ index ||= @hash[entry]
129
+ unless index && index < @queue.length
130
+ raise "You must provide either the index or the original entry object of the batch"
131
+ end
132
+ index
133
+ end
134
+
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,92 @@
1
+ module Eco
2
+ module API
3
+ class Session
4
+ class Task < API::Common::Session::BaseSession
5
+ NEWEST_FILE_MODE = [:newest, :last_file, :previous]
6
+ LOAD_FILE_MODE = [:file]
7
+ SAVE_FILE_MODE = [:save]
8
+ API_MODE = [:api, :api_get]
9
+
10
+ attr_reader :batch
11
+
12
+ def initialize(root, env)
13
+ super(env)
14
+ @root = root
15
+ end
16
+
17
+ def batch
18
+ @root&.batch
19
+ end
20
+
21
+ def file_people(filename = enviro.config.people.cache)
22
+ logger.info("Going to get all the people via API")
23
+ people = batch.get_people
24
+ file = file_manager.save_json(people, filename, :timestamp)
25
+ logger.info("#{people.length} people loaded and saved locally to #{file}.")
26
+ API::Organization::People.new(people)
27
+ end
28
+
29
+ def load_people(filename = enviro.config.people.cache, modifier: [:newest, :api])
30
+ modifier = [modifier].flatten
31
+ people = []
32
+ case
33
+ when !!filename && (load_file?(modifier) || newest_file?(modifier))
34
+ case
35
+ when newest_file?(modifier)
36
+ # search input file based on pattern (in case the name has a timestamp)
37
+ file = file_manager.dir.newest_file(file: filename)
38
+ logger.info("previous file found: #{file}") if !!file
39
+ else
40
+ file = file_manager.dir.file(filename)
41
+ end
42
+
43
+ if !file
44
+ logger.error("could not find the file #{file_manager.dir.file(filename)}")
45
+ exit if !use_api?(modifier)
46
+ people = self.load_people(modifier: modifier - NEWEST_FILE_MODE - LOAD_FILE_MODE)
47
+ else
48
+ people = file_manager.load_json(file)
49
+ if !!people && people.is_a?(Array)
50
+ logger.info("#{people&.length} people loaded from file #{file}")
51
+ end
52
+ end
53
+ when use_api?(modifier)
54
+ # no previous file: use API to get all people
55
+ logger.info("Going to get all the people via API")
56
+ people = batch.get_people
57
+
58
+ if save_file?(modifier) && people && people.length > 0
59
+ file = file_manager.save_json(people, filename, :timestamp)
60
+ logger.info("#{people.length } people saved to file #{file}.")
61
+ end
62
+ end
63
+ Eco::API::Organization::People.new(people)
64
+ end
65
+
66
+ private
67
+
68
+ # MODIFIERS
69
+ def use_api?(modifier)
70
+ modifiers = [modifier].flatten
71
+ modifiers.any? { |m| API_MODE.include?(m) }
72
+ end
73
+
74
+ def load_file?(modifier)
75
+ modifiers = [modifier].flatten
76
+ modifiers.any? { |m| LOAD_FILE_MODE.include?(m) }
77
+ end
78
+
79
+ def newest_file?(modifier)
80
+ modifiers = [modifier].flatten
81
+ modifiers.any? { |m| NEWEST_FILE_MODE.include?(m) }
82
+ end
83
+
84
+ def save_file?(modifier)
85
+ modifiers = [modifier].flatten
86
+ modifiers.any? { |m| SAVE_FILE_MODE.include?(m) }
87
+ end
88
+
89
+ end
90
+ end
91
+ end
92
+ end