eco-helpers 2.0.6 → 2.0.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 402f80f7e80fd4ecc9a97a9e96a0823ab4e26d63541540e14774db2dbf97ef60
4
- data.tar.gz: 3d097ed8af5c5e1c0ecacb227b0a77e4f1d6d8bb15e77599a008aa1af361b230
3
+ metadata.gz: 61ef9270db24cf1582814423b75bc1f3a74bf88cd14281862658c972d1f94f05
4
+ data.tar.gz: 30ac39b330426fcb8840b7e7456d240e6e7324030aea00b6950328708bbeb53b
5
5
  SHA512:
6
- metadata.gz: c083c3f62d2f29c427f56a2b34b11e4cd238198a95e728e1afeaa4345ccab4c507b798b10427adca14c547161d210d0662d4ece666b67d6464052992d0cade62
7
- data.tar.gz: 840bf5e3b90b3a9398a2eb2c5dc989e1ad321705d0785d5cb0b89a696756a721b2e66804a7a3fe7adc82f76611a58fba7379131c994312b01c2d576c93339df0
6
+ metadata.gz: 4dcfa4714c6b245c017194eb6b3fb623702472c260f5717b5485141fb9765fd7e10f891938e65978b7bc13142cc45e06efbc430db9cb63270355f6341e0991d3
7
+ data.tar.gz: 7cd4382209bef6d5b0db07b2adb90237500050b4ac9340ec39457f7f23d1131bc6562367bc5cf005fdcc4f3af1553dafd446aa02e551549b1bbb90c08e51e15d
data/CHANGELOG.md CHANGED
@@ -1,7 +1,56 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [2.0.6] - 2021-02-xx
4
+ ## [2.0.11] - 2021-03-xx
5
+
6
+ ### Added
7
+
8
+ ### Changed
9
+
10
+ ### Fixed
11
+ - `Eco::API::Session::Batch:Errors#errors` changed `Array#filter` call to `Array#select` call
12
+
13
+ ## [2.0.10] - 2021-03-26
14
+
15
+ ### Added
16
+ - `Eco::API::Common::People::PersonParser`
17
+ - `#defined_attrs`: list of all attribute defined parsers (regardless they belong to the model)
18
+ - `Eco::API::Organization::TagTree` methods
19
+ - `#total_depth` to know the total depth of a tree
20
+ - `#flat?` to know if the tagtree has only 1 level
21
+
22
+ ### Changed
23
+ - `Eco::API::Common::People::PersonParser`
24
+ - Renamed `#all_attrs` to `#all_model_attrs`
25
+ - Ranamed `#defined_attrs` to `#defined_model_attrs`
26
+ - Ranamed `#undefined_attrs` to `#undefined_model_attrs`
27
+
28
+ ### Fixed
29
+
30
+ ## [2.0.9] - 2021-03-19
31
+
32
+ ### Added
33
+ ### Changed
34
+ - `Eco::API::Session::Batch:Errors#person_ref` moved to the public method
35
+
36
+ ### Fixed
37
+
38
+ ## [2.0.8] - 2021-03-09
39
+
40
+ ### Added
41
+ ### Changed
42
+ ### Fixed
43
+ - `Ecoportal::API::V1::Person#identity` adjust behavior
44
+
45
+ ## [2.0.7] - 2021-03-09
46
+
47
+ ### Added
48
+ ### Changed
49
+ ### Fixed
50
+ - `Eco::API::Session::Batch::JobsGroups` and `Eco::API::Session::Batch::Jobs`: when new `Batch::Job`s are creating during launch, they remained unlaunched
51
+ - this fix makes `#launch` method to iterate until there are no pending
52
+
53
+ ## [2.0.6] - 2021-03-08
5
54
 
6
55
  ### Added
7
56
  ### Changed
data/eco-helpers.gemspec CHANGED
@@ -31,7 +31,6 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "redcarpet", ">= 3.5.1", "< 3.6"
32
32
 
33
33
  spec.add_dependency 'ecoportal-api', '>= 0.8.2', '< 0.9'
34
- #spec.add_dependency 'ecoportal-api', '>= 0.7.5', '< 0.8'
35
34
  spec.add_dependency 'ecoportal-api-v2', '>= 0.8.6', '< 0.9'
36
35
  spec.add_dependency 'aws-sdk-s3', '>= 1.83.0', '< 2'
37
36
  spec.add_dependency 'aws-sdk-ses', '>= 1.36.0', '< 2'
@@ -154,14 +154,20 @@ module Eco
154
154
  final_entry["default_tag"]
155
155
  end
156
156
 
157
- # Provides a reference of this person.
157
+ # Provides a reference to this person entry.
158
+ # @return [String] string summary of this person identity.
159
+ def identify
160
+ str_id = id ? "id: '#{id}'; " : ""
161
+ "(row: #{idx}) '#{name}' (#{str_id}ext_id: '#{external_id}'; email: '#{email}')"
162
+ end
163
+
164
+ # Provides a reference of this person entry.
158
165
  # @return [String] string summary of this person identity.
159
166
  def to_s(options)
160
167
  options = into_a(options)
161
168
  case
162
169
  when options.include?(:identify)
163
- str_id = id ? "id: '#{id}'; " : ""
164
- "(row: #{idx}) '#{name}' (#{str_id}ext_id: '#{external_id}'; email: '#{email}')"
170
+ identify
165
171
  else
166
172
  final_entry.each.map do |k, v|
167
173
  "'#{k}': '#{v.to_json}'"
@@ -250,7 +256,7 @@ module Eco
250
256
  # @param mapped_entry [Hash] that with **internal** names but **external** values and types.
251
257
  # @return [Hash] with **external** names, values and types.
252
258
  def _external_serializing(mapped_entry)
253
- target_attrs = @emap.all_attrs | @emap.aliased_attrs
259
+ target_attrs = @emap.all_model_attrs | @emap.aliased_attrs
254
260
  rest_keys = mapped_entry.keys - target_attrs
255
261
  target_attrs -= ["send_invites"]
256
262
  external_entry = target_attrs.each_with_object({}) do |attr, hash|
@@ -6,14 +6,14 @@ module Eco
6
6
  # @attr_reader core_attrs [Array<String>] core attributes that are present in the person entry.
7
7
  # @attr_reader details_attrs [Array<String>] schema details attributes that are present in the person entry.
8
8
  # @attr_reader account_attrs [Array<String>] account attributes that are present in the person entry.
9
- # @attr_reader all_attrs [Array<String>] all the attrs that are present in the person entry.
9
+ # @attr_reader all_model_attrs [Array<String>] all the attrs that are present in the person entry.
10
10
  # @attr_reader internal_attrs [Array<String>] all the internally named attributes that the person entry has.
11
11
  # @attr_reader aliased_attrs [Array<String>] only those internal attributes present in the person entry that have an internal/external name mapping.
12
12
  # @attr_reader direct_attrs [Array<String>] only those internal attributes present in the person entry that do **not** have an internal/external name mapping.
13
13
  class PersonEntryAttributeMapper
14
14
  @@cached_warnings = {}
15
15
 
16
- attr_reader :core_attrs, :details_attrs, :account_attrs, :all_attrs
16
+ attr_reader :core_attrs, :details_attrs, :account_attrs, :all_model_attrs
17
17
  attr_reader :internal_attrs, :aliased_attrs, :direct_attrs
18
18
 
19
19
  # Helper class tied to `PersonEntry` that allows to track which attributes of a person entry are present
@@ -41,14 +41,14 @@ module Eco
41
41
  init_attr_trackers
42
42
  else # SERIALIZING
43
43
  @person = data
44
- @internal_attrs = @person_parser.all_attrs
44
+ @internal_attrs = @person_parser.all_model_attrs
45
45
  @aliased_attrs = @attr_map.list(:internal)
46
46
  end
47
47
 
48
48
  @core_attrs = @person_parser.target_attrs_core(@internal_attrs)
49
49
  @details_attrs = @person_parser.target_attrs_details(@internal_attrs)
50
50
  @account_attrs = @person_parser.target_attrs_account(@internal_attrs)
51
- @all_attrs = @core_attrs | @account_attrs | @details_attrs
51
+ @all_model_attrs = @core_attrs | @account_attrs | @details_attrs
52
52
  end
53
53
 
54
54
  # To know if currently the object is in parse or serialize mode.
@@ -98,7 +98,7 @@ module Eco
98
98
  end
99
99
  end
100
100
 
101
- return nil unless @person_parser.all_attrs.include?(attr)
101
+ return nil unless @person_parser.all_model_attrs.include?(attr)
102
102
  end
103
103
 
104
104
  # Serializing helper also used to do a reverse mapping when parsing:
@@ -146,9 +146,9 @@ module Eco
146
146
  # when parsing:
147
147
  def init_attr_trackers
148
148
  # (def) all internal attributes we can expect
149
- def_all_attrs = @person_parser.all_attrs
149
+ def_all_attrs = @person_parser.all_model_attrs
150
150
  # (def) internal attrs with no aliasing nor parser definition (expected to be direct)
151
- def_unlinked = @person_parser.undefined_attrs.select { |attr| !to_external(attr) }
151
+ def_unlinked = @person_parser.undefined_model_attrs.select { |attr| !to_external(attr) }
152
152
  # (def) those with parser or alias:
153
153
  def_linked = def_all_attrs - def_unlinked
154
154
 
@@ -168,7 +168,7 @@ module Eco
168
168
  # (data) virtual internal attrs (the internal names of those virtual attrs)
169
169
  data_vi_int_aliased = data_vi_ext_alias.map do |attr|
170
170
  # to_internal(attr) can't be used here, becauase virtual fields would get filtered out,
171
- # as they are not recognized by @parser.all_attrs.include?(attr)
171
+ # as they are not recognized by @parser.all_model_attrs.include?(attr)
172
172
  @attr_map.to_internal(attr)
173
173
  end.compact
174
174
 
@@ -7,7 +7,7 @@ module Eco
7
7
  #
8
8
  # @attr_reader schema [Ecoportal::API::V1::PersonSchema, nil] schema of person details that this parser will be based upon.
9
9
  # @attr_reader details_attrs [Array<String>] internal names of schema details attributes.
10
- # @attr_reader all_attrs [Array<String>] all the internal name attributes, including _core_, _account_ and _details_.
10
+ # @attr_reader all_model_attrs [Array<String>] all the internal name attributes, including _core_, _account_ and _details_.
11
11
  class PersonParser
12
12
  extend Eco::API::Common::ClassAutoLoader
13
13
  autoloads_children_of "Eco::API::Common::Loaders::Parser"
@@ -19,8 +19,7 @@ module Eco
19
19
  FORMAT = [:csv, :xml, :json]
20
20
 
21
21
  attr_reader :schema
22
- attr_reader :details_attrs, :all_attrs
23
- attr_reader :defined_attrs
22
+ attr_reader :details_attrs, :all_model_attrs
24
23
  attr_reader :patch_version
25
24
 
26
25
  # @example Example of usage:
@@ -46,7 +45,7 @@ module Eco
46
45
  @details_attrs = @schema&.fields.map { |fld| fld.alt_id }
47
46
  end
48
47
 
49
- @all_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
48
+ @all_model_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
50
49
  self.class.autoload_children(self)
51
50
  end
52
51
 
@@ -60,6 +59,11 @@ module Eco
60
59
 
61
60
  # @!group Scopping attributes (identifying, presence & active)
62
61
 
62
+ # All the internal name attributes, including _core_, _account_ and _details_.
63
+ def all_attrs(include_defined_parsers: false)
64
+ all_model_attrs | defined_model_attrs
65
+ end
66
+
63
67
  # Scopes `source_attrs` using the _**core** attributes_.
64
68
  # @note use this helper to know which among your attributes are **core** ones.
65
69
  # @param source_attrs [Array<String>]
@@ -93,14 +97,21 @@ module Eco
93
97
  @parsers.keys
94
98
  end
95
99
 
100
+ # Returns a list of all the internal attributes that have a parser defined.
101
+ # @note These attributes do not necessarily belong to the model. They could be virtual attributes
102
+ # @return [Array<String>] list of all attribute defined parsers.
103
+ def defined_attrs
104
+ defined_list - symbol_keys
105
+ end
106
+
96
107
  # Returns a list of all the internal attributes of the model that have a parser defined.
97
108
  # @note
98
109
  # - it excludes any parser that is not in the model, such as type parsers (i.e. `:boolean`, `:multiple`)
99
110
  # - the list is sorted according `CORE_ATTRS` + `ACCOUNT_ATTRS` + schema attrs
100
- # @return [Array<String>] list of all attribute defined parsers.
101
- def defined_attrs
111
+ # @return [Array<String>] list of all attribute defined parsers in the model.
112
+ def defined_model_attrs
102
113
  defined = @parsers.keys
103
- defined = (all_attrs | defined) & defined
114
+ defined = (all_model_attrs | defined) & defined
104
115
  defined - symbol_keys
105
116
  end
106
117
 
@@ -118,7 +129,7 @@ module Eco
118
129
  # @param process [Symbol] either `:parse` or `:serialize`, depending if we want to parse or serialize the `attr`.
119
130
  # @return [Array<String>] list of all attribute defined parsers that should be active for the given `source_data`.
120
131
  def active_attrs(source_data, phase = :any, process: :parse)
121
- defined_attrs.select do |attr|
132
+ defined_model_attrs.select do |attr|
122
133
  if process == :serialize
123
134
  @parsers[attr].serializer_active?(phase)
124
135
  else
@@ -130,8 +141,8 @@ module Eco
130
141
  # Returns a list of all the internal attributes of the model that do **not** have a parser defined.
131
142
  # @note it excludes any parser that is **not** in the model, such as type parsers (i.e. :boolean, :multiple)
132
143
  # @return [Array<String>] list of all attributes without a defined parser.
133
- def undefined_attrs
134
- all_attrs - defined_attrs
144
+ def undefined_model_attrs
145
+ all_model_attrs - defined_model_attrs
135
146
  end
136
147
 
137
148
  # @param attr [String] internal name of an attribute.
@@ -238,7 +249,7 @@ module Eco
238
249
  end
239
250
 
240
251
  def valid_attr?(attr)
241
- attr.is_a?(String) && (!@schema || @all_attrs.include?(attr))
252
+ attr.is_a?(String) && (!@schema || @all_model_attrs.include?(attr))
242
253
  end
243
254
 
244
255
  def valid_type?(attr)
@@ -13,8 +13,8 @@ module Ecoportal
13
13
  original_doc["details"] = JSON.parse(doc["details"])
14
14
  end
15
15
 
16
- def identify
17
- if entry
16
+ def identify(section = :person)
17
+ if entry && section == :entry
18
18
  entry.to_s(:identify)
19
19
  else
20
20
  str_id = id ? "id: '#{id}'; " : ""
@@ -4,7 +4,7 @@ module Eco
4
4
 
5
5
  # Provides helpers to deal with tagtrees.
6
6
  class TagTree
7
- attr_reader :tag, :nodes
7
+ attr_reader :tag, :nodes, :children_count
8
8
  attr_reader :depth, :path
9
9
  attr_reader :enviro
10
10
 
@@ -37,6 +37,7 @@ module Eco
37
37
 
38
38
  nodes = @source.is_a?(Array) ? @source : @source.dig('nodes') || []
39
39
  @nodes = nodes.map {|cnode| TagTree.new(cnode, depth: @depth + 1, path: @path.dup, enviro: @enviro)}
40
+ @children_count = @nodes.count
40
41
 
41
42
  init_hashes
42
43
  end
@@ -46,6 +47,21 @@ module Eco
46
47
  @has_tags.empty?
47
48
  end
48
49
 
50
+ # @return [Integer] the highest `depth` of all the children.
51
+ def total_depth
52
+ @total_depth ||= if children_count > 0
53
+ deepest_node = nodes.max_by {|node| node.total_depth}
54
+ deepest_node.depth
55
+ else
56
+ depth
57
+ end
58
+ end
59
+
60
+ # @return [Integer] if there's only top level.
61
+ def flat?
62
+ self.total_depth <= 0
63
+ end
64
+
49
65
  # Gets all the tags of the current node tree.
50
66
  # @note
51
67
  # - this will include the upper level tag(s) as well
@@ -147,7 +163,8 @@ module Eco
147
163
  # * take the deepest tag (the one that is further down in the tree)
148
164
  # * if there are different options (several nodes at the same depth):
149
165
  # * take the common node between them (i.e. you have Hamilton and Auckland -> take New Zealand)
150
- # * if there's no common node between them, take the `first` (unless they are at top level of the tree)
166
+ # * if there's no common node between them, take the `first`, unless they are at top level of the tree
167
+ # * to the above, take the `first` also on top level, but only if there's 1 level for the entire tree
151
168
  # @param [Array<String>] values list of tags.
152
169
  # @return [String] default tag.
153
170
  def default_tag(*values)
@@ -169,7 +186,7 @@ module Eco
169
186
  common = nodes.reduce(self.tags.reverse) {|com, cnode| com & cnode.path.reverse}
170
187
  default_tag = common.first if common.length > 0 && depth > 0
171
188
  end
172
- default_tag = nodes.first&.tag if !default_tag && depth > 0
189
+ default_tag = nodes.first&.tag if !default_tag && ( (depth > 0) || flat?)
173
190
  default_tag
174
191
  end
175
192
 
@@ -111,6 +111,11 @@ module Eco
111
111
  end
112
112
  # @!endgroup
113
113
 
114
+ def person_ref(entry)
115
+ row_str = (row = get_row(entry)) ? "(row: #{row}) " : nil
116
+ "#{row_str}(id: '#{get_attr(entry, :id)}') '#{get_attr(entry, :name)}' ('#{get_attr(entry, :external_id)}': '#{get_attr(entry, :email)}')"
117
+ end
118
+
114
119
  private
115
120
 
116
121
  # Input entries that got **error** response from the _Server_.
@@ -119,7 +124,7 @@ module Eco
119
124
  # - please, observe that this can only happen if there were repeated entries in the `source_queue`
120
125
  # @return [Array<Hash>, Array<Ecoportal::API::V1::Person>, Array<Ecoportal::API::Internal::Person>]
121
126
  def entries
122
- queue.filter.with_index do |query, i|
127
+ queue.select.with_index do |query, i|
123
128
  unless response = status[i]
124
129
  msg = "Error: query with no response. You might have duplicated entries in your queue.\n"
125
130
  msg += "Queue length: #{queue.length}; Queue elements class: #{queue.first.class}\n"
@@ -136,11 +141,6 @@ module Eco
136
141
  end
137
142
  end
138
143
 
139
- def person_ref(entry)
140
- row_str = (row = get_row(entry)) ? "(row: #{row}) " : nil
141
- "#{row_str}(id: '#{get_attr(entry, :id)}') '#{get_attr(entry, :name)}' ('#{get_attr(entry, :external_id)}': '#{get_attr(entry, :email)}')"
142
- end
143
-
144
144
  def get_attr(entry, attr)
145
145
  if entry.respond_to?(attr.to_sym)
146
146
  entry.public_send(attr.to_sym)
@@ -45,25 +45,22 @@ module Eco
45
45
  # @!group Pure feedback methods
46
46
 
47
47
  # Slightly modifies the behaviour of `Ecoportal::API::Common::BaseModel#as_update`, so schema details fields show the `alt_id`
48
+ # It also fixes possible patch updates that are incomplete or unnecessary.
48
49
  # @note for better feedback
49
50
  # @param entry [Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
50
- def as_update(entry)
51
+ # @param add_feedback [Boolean] if `true` it tweak the hash update with additional data.
52
+ def as_update(entry, add_feedback: true)
51
53
  case
52
54
  when entry.is_a?(Hash)
53
55
  hash = entry
54
56
  else #entry.is_a?(Ecoportal::API::V1::Person)
55
57
  if only_ids?
56
- hash = {
57
- "id" => entry.id,
58
- "external_id" => entry.external_id,
59
- "email" => entry.email
60
- }
61
58
  hash = entry.as_json.slice("id", "external_id", "email")
62
59
  else
63
60
  hash = entry.as_update
64
- #if entry.details
65
- if hash["details"]
66
- if hfields = hash.dig("details", "fields")
61
+
62
+ if add_feedback && details = hash["details"]
63
+ if hfields = details["fields"]
67
64
  hfields.each do |fld|
68
65
  fld.merge!("alt_id" => entry.details.get_field(fld["id"]).alt_id)
69
66
  end
@@ -169,7 +169,8 @@ module Eco
169
169
 
170
170
  unless simulate
171
171
  if pqueue.length > 0
172
- backup_update(requests)
172
+ req_backup = pqueue.map {|e| as_update(e, add_feedback: false)}
173
+ backup_update(req_backup)
173
174
  session.batch.launch(pqueue, method: type).tap do |job_status|
174
175
  @status = job_status
175
176
  status.root = self
@@ -217,7 +218,7 @@ module Eco
217
218
  [].tap do |msg|
218
219
  subjobs.map {|subjob| msg << subjob.summary}
219
220
  end.join("\n")
220
- end
221
+ end
221
222
 
222
223
  def as_update(*args)
223
224
  feedback.as_update(*args)
@@ -94,7 +94,7 @@ module Eco
94
94
  callback.call(job, job_status) if callback
95
95
  end
96
96
  end
97
-
97
+ launch(simulate: simulate) if pending?
98
98
  return status
99
99
  end
100
100
 
@@ -96,6 +96,7 @@ module Eco
96
96
  self.class.counter(DELAY_BETWEEN_GROUPS) if !simulate && idx < @order.length - 1
97
97
  end
98
98
  end
99
+ launch(simulate: simulate) if pending?
99
100
  return status
100
101
  end
101
102
 
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = "2.0.6"
2
+ VERSION = "2.0.11"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.6
4
+ version: 2.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura