eco-helpers 0.6.17 → 0.7.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +19 -0
  3. data/.yardopts +2 -2
  4. data/Gemfile +6 -0
  5. data/Rakefile +27 -0
  6. data/eco-helpers.gemspec +9 -6
  7. data/lib/eco/api.rb +2 -1
  8. data/lib/eco/api/common/people.rb +1 -1
  9. data/lib/eco/api/common/people/base_parser.rb +31 -1
  10. data/lib/eco/api/common/people/default_parsers.rb +5 -1
  11. data/lib/eco/api/common/people/default_parsers/csv_parser.rb +37 -0
  12. data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +0 -1
  13. data/lib/eco/api/common/people/entries.rb +14 -18
  14. data/lib/eco/api/common/people/entry_factory.rb +97 -9
  15. data/lib/eco/api/common/people/person_entry.rb +147 -206
  16. data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +212 -0
  17. data/lib/eco/api/common/people/person_factory.rb +10 -12
  18. data/lib/eco/api/common/people/person_parser.rb +97 -37
  19. data/lib/eco/api/common/session/base_session.rb +1 -2
  20. data/lib/eco/api/common/session/file_manager.rb +1 -1
  21. data/lib/eco/api/organization.rb +2 -1
  22. data/lib/eco/api/organization/people.rb +54 -22
  23. data/lib/eco/api/organization/person_schemas.rb +54 -0
  24. data/lib/eco/api/organization/policy_groups.rb +5 -9
  25. data/lib/eco/api/organization/{presets.rb → presets_factory.rb} +1 -1
  26. data/lib/eco/api/policies.rb +10 -0
  27. data/lib/eco/api/policies/base_policy.rb +14 -0
  28. data/lib/eco/api/policies/policy.rb +20 -0
  29. data/lib/eco/api/policies/used_policies.rb +37 -0
  30. data/lib/eco/api/session.rb +36 -34
  31. data/lib/eco/api/session/batch.rb +94 -44
  32. data/lib/eco/api/session/batch_job.rb +108 -48
  33. data/lib/eco/api/session/batch_jobs.rb +4 -5
  34. data/lib/eco/api/session/batch_status.rb +70 -11
  35. data/lib/eco/api/session/config.rb +22 -5
  36. data/lib/eco/api/session/config/files.rb +10 -1
  37. data/lib/eco/api/session/config/people.rb +18 -5
  38. data/lib/eco/api/session/config/policies.rb +29 -0
  39. data/lib/eco/api/session/config/use_cases.rb +3 -7
  40. data/lib/eco/api/session/job_groups.rb +9 -10
  41. data/lib/eco/api/usecases.rb +2 -1
  42. data/lib/eco/api/usecases/base_case.rb +7 -2
  43. data/lib/eco/api/usecases/default_cases/change_email_case.rb +4 -2
  44. data/lib/eco/api/usecases/default_cases/create_case.rb +2 -1
  45. data/lib/eco/api/usecases/default_cases/create_details_case.rb +3 -1
  46. data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +4 -2
  47. data/lib/eco/api/usecases/default_cases/hris_case.rb +20 -13
  48. data/lib/eco/api/usecases/default_cases/new_email_case.rb +3 -1
  49. data/lib/eco/api/usecases/default_cases/new_id_case.rb +4 -2
  50. data/lib/eco/api/usecases/default_cases/recover_db_case.rb +9 -5
  51. data/lib/eco/api/usecases/default_cases/remove_account_case.rb +4 -2
  52. data/lib/eco/api/usecases/default_cases/set_supervisor_case.rb +4 -2
  53. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +2 -2
  54. data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +2 -2
  55. data/lib/eco/api/usecases/default_cases/update_case.rb +16 -2
  56. data/lib/eco/api/usecases/default_cases/update_details_case.rb +3 -1
  57. data/lib/eco/api/usecases/default_cases/upsert_case.rb +25 -3
  58. data/lib/eco/api/usecases/use_case.rb +23 -140
  59. data/lib/eco/api/usecases/use_case_chain.rb +95 -0
  60. data/lib/eco/api/usecases/use_case_io.rb +117 -0
  61. data/lib/eco/api/usecases/use_group.rb +25 -5
  62. data/lib/eco/common/base_cli_backup.rb +1 -0
  63. data/lib/eco/language/models.rb +1 -1
  64. data/lib/eco/language/models/collection.rb +42 -31
  65. data/lib/eco/language/models/parser_serializer.rb +68 -0
  66. data/lib/eco/version.rb +1 -1
  67. metadata +93 -38
  68. data/lib/eco/api/common/people/types.rb +0 -47
  69. data/lib/eco/api/usecases/case_data.rb +0 -13
  70. data/lib/eco/language/models/attribute_parser.rb +0 -38
  71. data/lib/eco/lexic/dictionary.rb +0 -33
  72. data/lib/eco/lexic/dictionary/dictionary.txt +0 -355484
  73. data/lib/eco/lexic/dictionary/tags.json +0 -38
@@ -16,8 +16,7 @@ module Eco
16
16
 
17
17
  def initialize(e)
18
18
  raise "Expected object Eco::API::Common::Session::Environment. Given: #{e.class}" unless e.is_a?(Environment)
19
- #e = Environment.new(e) if !e.is_a?(Environment)
20
- self.environment = e #if e.is_a?(Environment)
19
+ self.environment = e
21
20
  end
22
21
 
23
22
  def session
@@ -31,7 +31,7 @@ module Eco
31
31
 
32
32
  ##### FILE #####
33
33
  def file(filename, should_exist: false)
34
- dir.file(filename, should_exist: should_exit)
34
+ dir.file(filename, should_exist: should_exist)
35
35
  end
36
36
 
37
37
  def newest(filename)
@@ -6,7 +6,8 @@ module Eco
6
6
  end
7
7
 
8
8
  require_relative 'organization/tag_tree'
9
- require_relative 'organization/presets'
9
+ require_relative 'organization/presets_factory'
10
10
  require_relative 'organization/preferences'
11
11
  require_relative 'organization/people'
12
12
  require_relative 'organization/policy_groups'
13
+ require_relative 'organization/person_schemas'
@@ -2,7 +2,6 @@ module Eco
2
2
  module API
3
3
  module Organization
4
4
  class People < Eco::Language::Models::Collection
5
-
6
5
  # build the shortcuts of Collection
7
6
  attr_collection :id, :external_id, :email, :name, :supervisor_id
8
7
  attr_presence :account, :details
@@ -16,7 +15,7 @@ module Eco
16
15
  end
17
16
 
18
17
  def [](id_or_ext)
19
- self.id(id_or_ext) || self.external_id(id_or_ext)
18
+ id(id_or_ext) || external_id(id_or_ext)
20
19
  end
21
20
 
22
21
  def id(*args)
@@ -28,32 +27,65 @@ module Eco
28
27
  end
29
28
 
30
29
  def users
31
- self.account_present(true)
30
+ account_present(true)
32
31
  end
33
32
 
34
33
  def contacts
35
- self.details_present(true)
34
+ details_present(true)
36
35
  end
37
36
 
38
37
  def non_users
39
- self.account_present(false)
38
+ account_present(false)
40
39
  end
41
40
 
42
- def person(id: nil, external_id: nil, email: nil)
41
+ # It searches a person using the paramters given.
42
+ # @param id [String] the `internal id` of the person
43
+ # @param external_id [String] the `exernal_id` of the person
44
+ # @param email [String] the `email` of the person
45
+ # @param strict [Boolean] if should perform a `soft` or a `strict` search. `strict` will avoid repeated email addresses.
46
+ # @return [Person, nil] the person we were searching, or `nil` if not found.
47
+ def person(id: nil, external_id: nil, email: nil, strict: false)
43
48
  init_caches
44
49
  pers = @by_id[id]&.first if id
45
- pers = @by_external_id[external_id&.strip]&.first if !pers && !external_id.to_s.strip.empty?
46
- pers = @by_users_email[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
47
- pers = @by_non_users_email[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
48
- pers = @by_external_id[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
50
+ pers = @by_external_id[external_id&.strip]&.first if !pers && !external_id.to_s.strip.empty?
51
+
52
+ # strict prevents taking existing user for searched person with same email
53
+ # specially useful if the organisation ensures all have external id (no need for email search)
54
+ if !pers && (!strict || external_id.to_s.strip.empty?)
55
+ # person still not found and either not strict or no external_id provided
56
+ pers = @by_users_email[email&.downcase.strip]&.first if !email.to_s.strip.empty?
57
+
58
+ if !pers && !strict && !email.to_s.strip.empty?
59
+ candidates = @by_non_users_email[email&.downcase.strip] || []
60
+ raise "Too many non-user candidates (#{candiates.length}) with email '#{email}'" if candidates.length > 1
61
+ pers = candidates.first
62
+ end
63
+
64
+ end
65
+ pers = @by_external_id[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
66
+
49
67
  pers
50
68
  end
51
69
 
52
- def find(object)
53
- id = object.respond_to?("id")? object.send("id") : nil
70
+ def find(object, strict: false)
71
+ id = object.respond_to?("id")? object.send("id") : nil
54
72
  external_id = object.respond_to?("external_id")? object.send("external_id") : nil
55
- email = object.respond_to?("email")? object.send("email") : nil
56
- person(id: id, external_id: external_id, email: email)
73
+ email = object.respond_to?("email")? object.send("email") : nil
74
+ person(id: id, external_id: external_id, email: email, strict: strict)
75
+ end
76
+
77
+ def uniq(include_unsearchable: false)
78
+ init_caches
79
+ unsearchable = []
80
+ newFrom to_a.each_with_object([]) do |person, people|
81
+ if found = find(person)
82
+ people << found
83
+ else
84
+ unsearchable << person
85
+ end
86
+ end.tap do |people|
87
+ people << unsearchable if include_unsearchable
88
+ end
57
89
  end
58
90
 
59
91
  def exclude(object)
@@ -64,15 +96,15 @@ module Eco
64
96
  discarded = list.map do |person|
65
97
  find(person)
66
98
  end.compact
67
- newFrom self.to_a - discarded
99
+ newFrom to_a - discarded
68
100
  end
69
101
 
70
102
  def email_id_maps
71
- self.users.group_by(:email).transform_values { |person| person.id }
103
+ users.group_by(:email).transform_values { |person| person.id }
72
104
  end
73
105
 
74
106
  def group_by_supervisor
75
- self.to_h(:supervisor_id)
107
+ to_h(:supervisor_id)
76
108
  end
77
109
 
78
110
  # only those that are present
@@ -89,7 +121,7 @@ module Eco
89
121
  sup_ids - (sup_ids & self.ids)
90
122
  end
91
123
 
92
- def to_h(attr)
124
+ def to_h(attr = "id")
93
125
  super(attr || "id")
94
126
  end
95
127
 
@@ -103,10 +135,10 @@ module Eco
103
135
 
104
136
  def init_caches
105
137
  return if @caches_init
106
- @by_id = self.to_h('id')
107
- @by_external_id = self.to_h('external_id')
108
- @by_users_email = self.users.to_h('email')
109
- @by_non_users_email = self.non_users.to_h('email')
138
+ @by_id = to_h
139
+ @by_external_id = to_h('external_id')
140
+ @by_users_email = users.to_h('email')
141
+ @by_non_users_email = non_users.to_h('email')
110
142
  @caches_init = true
111
143
  end
112
144
 
@@ -0,0 +1,54 @@
1
+ module Eco
2
+ module API
3
+ module Organization
4
+ class PersonSchemas < Eco::Language::Models::Collection
5
+ # build the shortcuts of Collection
6
+ attr_collection :id, :name
7
+
8
+ def initialize(schemas = [], klass: Ecoportal::API::Internal::PersonSchema)
9
+ @klass = Ecoportal::API::Internal::PersonSchema
10
+ @caches_init = false
11
+ super(schemas, klass: @klass)
12
+ init_caches
13
+ end
14
+
15
+ def to_id(name)
16
+ case name
17
+ when Enumerable
18
+ name.map do |n|
19
+ schema(n)&.id
20
+ end.compact
21
+ else
22
+ schema(name)&.id
23
+ end
24
+ end
25
+
26
+ def to_name(id)
27
+ schema(id)&.name
28
+ end
29
+
30
+ def schema(id_name)
31
+ @by_id.fetch(schema_id(id_name), nil)
32
+ end
33
+
34
+ private
35
+
36
+ def schema_name(id_name)
37
+ (@by_id[id_name] || @by_name[id_name&.downcase])&.name&.downcase
38
+ end
39
+
40
+ def schema_id(id_name)
41
+ (@by_name[id_name&.downcase] || @by_id[id_name])&.id
42
+ end
43
+
44
+ def init_caches
45
+ return if @caches_init
46
+ @by_id = self.map { |pg| [pg.id, pg] }.to_h
47
+ @by_name = self.map { |pg| [pg.name&.downcase, pg] }.to_h
48
+ @caches_init = true
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
@@ -5,10 +5,8 @@ module Eco
5
5
  # build the shortcuts of Collection
6
6
  attr_collection :id, :name
7
7
 
8
- include Common::People
9
-
10
- def initialize(policy_groups = [], klass: INTERNAL::PolicyGroup)
11
- @klass = INTERNAL::PolicyGroup
8
+ def initialize(policy_groups = [], klass: Ecoportal::API::Internal::PolicyGroup)
9
+ @klass = Ecoportal::API::Internal::PolicyGroup
12
10
  @caches_init = false
13
11
  super(policy_groups, klass: @klass)
14
12
  init_caches
@@ -16,7 +14,7 @@ module Eco
16
14
 
17
15
  def to_id(name)
18
16
  case name
19
- when Array
17
+ when Enumerable
20
18
  name.map do |n|
21
19
  policy_group(n)&.id
22
20
  end.compact
@@ -54,13 +52,11 @@ module Eco
54
52
  private
55
53
 
56
54
  def policy_group_name(id_name)
57
- @by_id.fetch(id_name, nil)&.name&.downcase ||
58
- @by_name.fetch(id_name&.downcase, nil)&.name&.downcase
55
+ (@by_id[id_name] || @by_name[id_name&.downcase])&.name&.downcase
59
56
  end
60
57
 
61
58
  def policy_group_id(id_name)
62
- @by_name.fetch(id_name&.downcase, nil)&.id ||
63
- @by_id.fetch(id_name, nil)&.id
59
+ (@by_name[id_name&.downcase] || @by_id[id_name])&.id
64
60
  end
65
61
 
66
62
  def init_caches
@@ -5,7 +5,7 @@ module Eco
5
5
  class PresetsFactory
6
6
  ABILITIES = File.join(__dir__, 'presets_values.json')
7
7
  DEFAULT_CUSTOM = 'presets_custom.json'
8
- DEFAULT_MAP = 'presets_map.json'
8
+ DEFAULT_MAP = 'presets_map.json'
9
9
 
10
10
  def initialize(presets_custom: DEFAULT_CUSTOM, presets_map: DEFAULT_MAP, enviro: nil, policy_groups: nil)
11
11
  @abilities = JSON.load(File.open(ABILITIES))
@@ -0,0 +1,10 @@
1
+ module Eco
2
+ module API
3
+ module Policies
4
+ end
5
+ end
6
+ end
7
+
8
+ require_relative 'policies/base_policy'
9
+ require_relative 'policies/policy'
10
+ require_relative 'policies/used_policies'
@@ -0,0 +1,14 @@
1
+ module Eco
2
+ module API
3
+ module Policies
4
+ class BasePolicy < Eco::API::UseCases::BaseCase
5
+
6
+ def initialize(policies, **options)
7
+ raise "Expected UsedPolicies. Given: #{policies.class}" unless policies.is_a?(UsedPolicies)
8
+ super(policies, **options)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module Eco
2
+ module API
3
+ module Policies
4
+ class Policy < Eco::API::UseCases::UseCase
5
+ TYPES = [:transform]
6
+
7
+ def initialize(name, type: :transform, root:, options: {}, &block)
8
+ raise "Undefine usecase type #{type}. Please, use any of #{TYPES}" unless self.class.valid_type?(type)
9
+ super(name, type: type, root: root, options: options, &block)
10
+ end
11
+
12
+ def root=(value)
13
+ raise "Root should be a UsedPolicies object. Given: #{value}" if !value.is_a?(UsedPolicies)
14
+ @root = value
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+ module Eco
2
+ module API
3
+ module Policies
4
+ class UsedPolicies < Eco::API::UseCases::UseGroup
5
+
6
+ attr_reader :policies
7
+
8
+ def add(policy)
9
+ raise "Expected Policy object. Given: #{policy}" if !policy || !policy.is_a?(Policy)
10
+ super(policy)
11
+ end
12
+
13
+ def define(name, type: :transform, &block)
14
+ Policy.new(name, type: type, root: self, &block).tap do |policy|
15
+ add(policy)
16
+ end
17
+ end
18
+
19
+ # TODO: decide if policies deal with queue or single person
20
+ def launch(people:, session:, options: {})
21
+
22
+ args = {
23
+ people: people,
24
+ session: session,
25
+ options: options
26
+ }
27
+
28
+ items.map do |policy|
29
+ session.logger.debug("UsedPolicies: going to process '#{policy.name}' policy")
30
+ policy.launch(**args)
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -1,13 +1,10 @@
1
1
  module Eco
2
2
  module API
3
3
  class Session < Common::Session::BaseSession
4
- attr_reader :batch, :policy_groups
5
- attr_accessor :schema, :schemas_hash
6
- attr_reader :tagtree
4
+ attr_reader :batch, :policy_groups, :tagtree
7
5
  attr_reader :job_groups
8
-
9
- #attr_reader :organization
10
- #alias_method :org, :organization
6
+ attr_reader :schemas
7
+ attr_accessor :schema
11
8
 
12
9
  def initialize(init = {})
13
10
  e = init
@@ -24,13 +21,9 @@ module Eco
24
21
 
25
22
  @use_cases = Eco::API::UseCases::DefaultCases.new.merge(config.usecases.use_group)
26
23
 
27
- @schemas = api&.person_schemas.to_a
28
- @schemas_hash = @schemas.map do |sch|
29
- [[sch.id, sch], [sch.name.downcase, sch]]
30
- end.flatten(1).to_h
31
-
24
+ @schemas = config.schemas
32
25
  self.schema = config.people.default_schema || @schemas.first
33
- @policy_groups = nil
26
+ @policy_groups = config.policy_groups
34
27
 
35
28
  @tagtree = nil
36
29
  if tree_file = config.dig('org', 'tagtree')
@@ -50,10 +43,9 @@ module Eco
50
43
  end
51
44
 
52
45
  def self.configure
53
- # TODO: change to Session::Config.new.tap
54
- conf = Session::Config.new
55
- yield(conf) if block_given?
56
- conf
46
+ Session::Config.new.tap do |conf|
47
+ yield(conf) if block_given?
48
+ end
57
49
  end
58
50
 
59
51
  # TASKS & JOBS
@@ -99,9 +91,9 @@ module Eco
99
91
  def schema=(value)
100
92
  case value
101
93
  when String
102
- sch = @schemas_hash[value.downcase]
103
- fatal "The schema with id or name '#{value}' does not exist" if !sch
104
- @schema = sch
94
+ unless @schema = @schemas.schema(value)
95
+ fatal "The schema with id or name '#{value}' does not exist"
96
+ end
105
97
  when Ecoportal::API::V1::PersonSchema
106
98
  @schema = value
107
99
  else
@@ -109,16 +101,24 @@ module Eco
109
101
  return
110
102
  end
111
103
 
112
- @person_factory = Eco::API::Common::People::PersonFactory.new(schema: @schema)
104
+ @person_factory = Eco::API::Common::People::PersonFactory.new(schema: @schema)
105
+
106
+ # TODO: check PersonEntry#to_internal and #to_external in init_attr_trackers
107
+ # => when attr_map is avoided, it doesn't work as it should
108
+ if map_file = config.people.fields_mapper
109
+ mappings = map_file ? file_manager.load_json(map_file) : []
110
+ else
111
+ mappings = []
112
+ end
113
+ attr_map = Eco::Data::Mapper.new(mappings)
113
114
 
114
- fields_mapper_file = config.people.fields_mapper
115
- fields_mapper = Eco::Data::Mapper.new(file_manager.load_json(fields_mapper_file))
116
- @entry_factory = Eco::API::Common::People::EntryFactory.new({
117
- schema: @schema,
115
+ @entry_factory = Eco::API::Common::People::EntryFactory.new({
116
+ schema: @schema,
118
117
  person_parser: config.people.parser,
119
- fields_mapper: fields_mapper,
120
- logger: logger
118
+ attr_map: attr_map,
119
+ logger: logger
121
120
  })
121
+ self
122
122
  end
123
123
 
124
124
  def new_preset(input)
@@ -140,14 +140,16 @@ module Eco
140
140
  @entry_factory.new(data, dependencies: dependencies)
141
141
  end
142
142
 
143
+ def entries(*args)
144
+ @entry_factory.entries(*args)
145
+ end
146
+
147
+ def export(*args)
148
+ @entry_factory.export(*args)
149
+ end
150
+
143
151
  def csv_entries(file)
144
- rows = []
145
- if Eco::API::Common::Session::FileManager.file_exists?(file)
146
- CSV.foreach(file, headers: true, encoding: Eco::API::Common::Session::FileManager.encoding(file)).with_index do |row, i|
147
- rows.push(row)
148
- end
149
- end
150
- @entry_factory.entries(rows)
152
+ return entries(file: file, format: :csv)
151
153
  end
152
154
 
153
155
  def discarded_entries
@@ -160,7 +162,7 @@ module Eco
160
162
  args = { session: self }.merge(params)
161
163
  fatal("Undefined usecase '#{name}' of type '#{type.to_s}'") if !@use_cases.defined?(name, type: type)
162
164
  logger.debug("Session: going to process '#{name}' defined case")
163
- @use_cases.case(name, type: type).process(**args)
165
+ @use_cases.case(name, type: type).launch(**args)
164
166
  end
165
167
 
166
168
  end