eco-helpers 0.6.17 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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