ecoportal-api 0.9.7 → 0.10.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.
@@ -1,13 +1,14 @@
1
1
  module Ecoportal
2
2
  module API
3
3
  class V1
4
- # @attr_reader client [Common::Client] a `Common::Client` object that holds the configuration of the api connection.
4
+ # @attr_reader client [Common::Client] a `Common::Client` object that
5
+ # holds the configuration of the api connection.
5
6
  class People
6
7
  extend Common::BaseClass
7
- include Enumerable
8
8
  include Common::DocHelpers
9
+ include Enumerable
9
10
 
10
- JOB_TIMEOUT = 240
11
+ JOB_TIMEOUT = 240
11
12
  DELAY_STATUS_CHECK = 5
12
13
 
13
14
  class_resolver :person_class, "Ecoportal::API::V1::Person"
@@ -30,35 +31,49 @@ module Ecoportal
30
31
  # @param silent [Boolean] `false` to show percentage of progress.
31
32
  # @yield [person] does some stuff with the person.
32
33
  # @yieldparam person [Person]
33
- def each(params: {}, silent: false, &block)
34
- return to_enum(:each, params: params, silent: silent) unless block
35
- cursor_id = nil; results = 0
34
+ def each(params: {}, silent: false) # rubocop:disable Metrics/AbcSize
35
+ return to_enum(:each, params: params, silent: silent) unless block_given?
36
+
37
+ cursor_id = nil
38
+ results = 0
39
+
36
40
  puts "\n" unless silent
41
+
37
42
  loop do
38
43
  params.update(cursor_id: cursor_id) if cursor_id
39
- body = nil; response = nil; count = 5
44
+
45
+ body = nil
46
+ response = nil
47
+ count = 5
48
+
40
49
  loop do
41
50
  response = client.get("/people", params: params)
42
51
  body = response && body_data(response.body)
43
52
  break if response.success? || count <= 0
53
+
44
54
  puts "Request failed - Status #{response.status}: #{body}"
45
55
  count -= 1
56
+
46
57
  sleep(0.5)
47
58
  end
59
+
48
60
  raise "Request failed - Status #{response.status}: #{body}" unless response.success?
49
61
 
50
- unless silent || (total = body["total_results"]) == 0
62
+ unless silent || (total = body["total_results"])&.zero?
51
63
  results += body["results"].length
52
64
  percent = results * 100 / total
65
+
53
66
  msg = "People GET"
54
- msg += " (search=#{params[:q]})" if params.key?(:q)
55
- print "#{msg}: #{percent.round}% (of #{total})\r"
67
+ msg << " (search=#{params[:q]})" if params.key?(:q)
68
+
69
+ print "#{msg}: #{percent.round}% (of #{total}): #{results}\r"
56
70
  $stdout.flush
57
71
  end
58
72
 
59
73
  body["results"].each do |person|
60
74
  yield person_class.new(person)
61
75
  end
76
+
62
77
  break unless (cursor_id = body["cursor_id"])
63
78
  end
64
79
  self
@@ -81,9 +96,10 @@ module Ecoportal
81
96
  # @return [Person] the person with `id` (internal or external) contained in `doc`.
82
97
  def get(doc)
83
98
  id = get_id(doc)
84
- response = client.get("/people/"+CGI.escape(id))
99
+ response = client.get("/people/#{CGI.escape(id)}")
85
100
  body = body_data(response.body)
86
101
  return person_class.new(body) if response.success?
102
+
87
103
  raise "Could not get person #{id} - Error #{response.status}: #{body}"
88
104
  end
89
105
 
@@ -93,7 +109,7 @@ module Ecoportal
93
109
  def update(doc)
94
110
  body = get_body(doc)
95
111
  id = get_id(doc)
96
- client.patch("/people/"+CGI.escape(id), data: body)
112
+ client.patch("/people/#{CGI.escape(id)}", data: body)
97
113
  end
98
114
 
99
115
  # Requests to create a person via api.
@@ -110,7 +126,7 @@ module Ecoportal
110
126
  def upsert(doc)
111
127
  body = get_body(doc)
112
128
  id = get_id(doc)
113
- client.post("/people/"+CGI.escape(id), data: body)
129
+ client.post("/people/#{CGI.escape(id)}", data: body)
114
130
  end
115
131
 
116
132
  # Requests to completelly remove from an organization an existing person via api.
@@ -118,7 +134,7 @@ module Ecoportal
118
134
  # @return [Response] an object with the api response.
119
135
  def delete(doc)
120
136
  id = get_id(doc)
121
- client.delete("/people/"+CGI.escape(id))
137
+ client.delete("/people/#{CGI.escape(id)}")
122
138
  end
123
139
 
124
140
  # Creates a `BatchOperation` and yields it to the given bock.
@@ -128,8 +144,15 @@ module Ecoportal
128
144
  # @return [Ecoportal::API::Common::Response] the results of the batch
129
145
  def batch(job_mode: true, &block)
130
146
  return job(&block) if job_mode
131
- operation = Common::BatchOperation.new("/people", person_class, logger: client.logger)
147
+
148
+ operation = Common::BatchOperation.new(
149
+ "/people",
150
+ person_class,
151
+ logger: client.logger
152
+ )
153
+
132
154
  yield operation
155
+
133
156
  # The batch operation is responsible for logging the output
134
157
  client.post("/people/batch", data: operation.as_json).tap do |response|
135
158
  operation.process_response(response)
@@ -138,16 +161,25 @@ module Ecoportal
138
161
 
139
162
  # @return [Ecoportal::API::Common::Response] the results of the batch job
140
163
  def job
141
- operation = Common::BatchOperation.new("/people", person_class, logger: client.logger)
164
+ operation = Common::BatchOperation.new(
165
+ "/people",
166
+ person_class,
167
+ logger: client.logger
168
+ )
169
+
142
170
  yield operation
171
+
143
172
  job_id = create_job(operation)
144
173
  status = wait_for_job_completion(job_id)
145
174
 
146
175
  if status&.complete?
147
176
  job_result(job_id, operation)
148
177
  else
149
- msg = "Job `#{job_id}` not complete. Probably timeout after #{JOB_TIMEOUT} seconds. Current status: #{status}"
150
- raise API::Errors::TimeOut.new msg
178
+ msg = "Job `#{job_id}` not complete. "
179
+ msg << "Probably timeout after #{JOB_TIMEOUT} seconds. "
180
+ msg << "Current status: #{status}"
181
+
182
+ raise API::Errors::TimeOut, msg
151
183
  end
152
184
  end
153
185
 
@@ -160,10 +192,15 @@ module Ecoportal
160
192
  private
161
193
 
162
194
  JobStatus = Struct.new(:id, :complete?, :errored?, :progress)
195
+
163
196
  def job_status(job_id)
164
197
  response = client.get("/people/job/#{CGI.escape(job_id)}/status")
165
198
  body = response && body_data(response.body)
166
- raise "Status error (#{response.status}) - Errors: #{body}" unless response.success?
199
+
200
+ msg = "Status error (#{response.status}) - "
201
+ msg << "Errors: #{body}"
202
+ raise msg unless response.success?
203
+
167
204
  JobStatus.new(
168
205
  body["id"],
169
206
  body["complete"],
@@ -183,10 +220,12 @@ module Ecoportal
183
220
  # timeout library is evil. So we make poor-man timeout.
184
221
  # https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/
185
222
  before = Time.now
186
- while true
223
+
224
+ loop do
187
225
  status = job_status(job_id)
188
226
  break status if status.complete?
189
227
  break status if Time.now >= before + JOB_TIMEOUT
228
+
190
229
  sleep(DELAY_STATUS_CHECK)
191
230
  status
192
231
  end
@@ -207,7 +246,6 @@ module Ecoportal
207
246
  def body_data(body)
208
247
  body
209
248
  end
210
-
211
249
  end
212
250
  end
213
251
  end
@@ -9,14 +9,16 @@ module Ecoportal
9
9
  # @attr details [PersonDetails, nil] the details of the person or `nil` if missing.
10
10
  class Person < Common::BaseModel
11
11
  passthrough :id, :external_id, :name, :email, :filter_tags
12
+ passthrough :archived
12
13
  passthrough :supervisor_id, :contractor_organization_id
14
+ passthrough :brand_id
13
15
  passthrough :freemium
14
16
 
15
17
  class_resolver :person_schema_class, "Ecoportal::API::V1::PersonSchema"
16
18
  class_resolver :person_details_class, "Ecoportal::API::V1::PersonDetails"
17
19
  embeds_one :details, nullable: true, klass: :person_details_class
18
20
 
19
- VALID_TAG_REGEX = /^[A-Za-z0-9 &_'\/.-]+$/
21
+ VALID_TAG_REGEX = /^[A-Za-z0-9 &_'\/.-]+$/
20
22
  VALID_EMAIL_REGEX = /^[^@\s]+@[^@\s]+\.[^@\s]+$/
21
23
 
22
24
  # Gets the supervisor (`Person`) of this person, with given his `supervisor_id`.
@@ -47,9 +49,8 @@ module Ecoportal
47
49
  # Sets the email of a person.
48
50
  # @param value [String, nil] the email of this person.
49
51
  def email=(value)
50
- unless !value || value.match(VALID_EMAIL_REGEX)
51
- raise "Invalid email #{value.inspect}"
52
- end
52
+ raise "Invalid email #{value.inspect}" if value && !value.match(VALID_EMAIL_REGEX)
53
+
53
54
  doc["email"] = value&.downcase
54
55
  end
55
56
 
@@ -58,15 +59,16 @@ module Ecoportal
58
59
  # @raise [Exception] if there was any invalid string tag.
59
60
  # @param value [Array<String>] array of tags.
60
61
  def filter_tags=(value)
61
- unless value.is_a?(Array)
62
- raise "filter_tags= needs to be passed an Array, got #{value.class}"
63
- end
62
+ msg = "filter_tags= needs to be passed an Array, got #{value.class}"
63
+ raise ArgumentError, msg unless value.is_a?(Array)
64
+
64
65
  end_tags = value.compact.map do |tag|
65
- unless tag.match(VALID_TAG_REGEX)
66
- raise "Invalid filter tag #{tag.inspect}"
67
- end
66
+ msg = "Invalid filter tag #{tag.inspect}"
67
+ raise ArgumentError, msg unless tag.match(VALID_TAG_REGEX)
68
+
68
69
  tag.upcase
69
70
  end
71
+
70
72
  set_uniq_array_keep_order("filter_tags", end_tags)
71
73
  end
72
74
 
@@ -105,8 +107,10 @@ module Ecoportal
105
107
  end
106
108
 
107
109
  # Sets the PersonDetails to the person, depending on the parameter received:
108
- # - `PersonSchema`: initializes the `PersonDetails` as per the schema specified (`schema_id` and `fields`).
109
- # - `String`: it just sets the `schema_id` on the `PersonDetails` (as `fields` is not include, `details[key]=` will throw error).
110
+ # - `PersonSchema`: initializes the `PersonDetails` as per the schema specified
111
+ # (`schema_id` and `fields`).
112
+ # - `String`: it just sets the `schema_id` on the `PersonDetails`
113
+ # (as `fields` is not include, `details[key]=` will throw error).
110
114
  # (see #details=)
111
115
  # @note
112
116
  # - this method alone only sets the internal structure of the details.
@@ -130,7 +134,6 @@ module Ecoportal
130
134
  }
131
135
  end
132
136
  end
133
-
134
137
  end
135
138
  end
136
139
  end
@@ -40,7 +40,8 @@ module Ecoportal
40
40
 
41
41
  # Gets the value of one specific field of the PersonDetails.
42
42
  # @param id [String] the `id` or the `alt_id` of the target field.
43
- # @return [String, Array<String>, Boolean, Array<Boolean>, Date, Array<Date>, Numberic, Array<Numeric>] the value of field or `nil` if missing.
43
+ # @return [String, Array<String>, Boolean, Array<Boolean>, Date, Array<Date>, Numberic, Array<Numeric>]
44
+ # the value of field or `nil` if missing.
44
45
  def [](id)
45
46
  get_field(id)&.value
46
47
  end
@@ -50,11 +51,10 @@ module Ecoportal
50
51
  # @param id [String] the `id` or the `alt_id` of the target field.
51
52
  # @return [void]
52
53
  def []=(id, value)
53
- if field = get_field(id)
54
- field.value = value
55
- else
56
- raise MissingId.new("details[#{id.inspect}] is missing. Did you forget to load the schema?")
57
- end
54
+ msg = "details[#{id.inspect}] is missing. Did you forget to load the schema?"
55
+ raise MissingId, msg unless (field = get_field(id))
56
+
57
+ field.value = value
58
58
  end
59
59
 
60
60
  # Checks if an `id` or `alt_id` exists
@@ -67,12 +67,14 @@ module Ecoportal
67
67
 
68
68
  # @return [Boolean] `true` if `id` exists and `value` has changed, `false` otherwise
69
69
  def changed?(id, doc = :original)
70
- return false unless field = get_field(id)
70
+ return false unless (field = get_field(id))
71
+
71
72
  field.as_update.key?("value")
72
73
  end
73
74
 
74
75
  def original_value(id)
75
- return nil unless field = get_field(id)
76
+ return nil unless (field = get_field(id))
77
+
76
78
  field.original_doc["value"]
77
79
  end
78
80
 
@@ -87,7 +89,6 @@ module Ecoportal
87
89
  @fields_by_alt_id[wrapped.alt_id] = wrapped
88
90
  end
89
91
  end
90
-
91
92
  end
92
93
  end
93
94
  end
@@ -30,6 +30,7 @@ module Ecoportal
30
30
  def index_fields
31
31
  @fields_by_id = {}
32
32
  @fields_by_alt_id = {}
33
+
33
34
  doc["fields"].each do |field|
34
35
  wrapped = schema_field_class.new(field)
35
36
  @fields_by_id[wrapped.id] = wrapped
@@ -45,7 +46,6 @@ module Ecoportal
45
46
  )
46
47
  end
47
48
  end
48
-
49
49
  end
50
50
  end
51
51
  end
@@ -38,8 +38,6 @@ module Ecoportal
38
38
  return to_enum(:each) unless block
39
39
  get_all.each(&block)
40
40
  end
41
-
42
-
43
41
  end
44
42
  end
45
43
  end
@@ -22,11 +22,10 @@ module Ecoportal
22
22
  Date.parse(line) rescue return nil, false
23
23
  end
24
24
  end.compact
25
- if multiple
26
- return values, true
27
- else
28
- return values.first, true
29
- end
25
+
26
+ out = values
27
+ out = values.first unless multiple
28
+ [out, true]
30
29
  end
31
30
  end
32
31
  end
@@ -6,29 +6,27 @@ module Ecoportal
6
6
  passthrough :id, :alt_id, :type, :name, :shared, :multiple
7
7
 
8
8
  def clear
9
- if multiple
10
- doc["value"] = []
11
- else
12
- doc["value"] = nil
13
- end
9
+ return doc["value"] = [] if multiple
10
+
11
+ doc["value"] = nil
14
12
  end
15
13
 
16
14
  def value
17
15
  case type
18
16
  when "text", "phone_number", "number", "boolean", "select"
19
- doc["value"]
17
+ doc["value"]
20
18
  when "date"
21
- if doc["value"]
22
- maybe_multiple(doc["value"]) do |v|
23
- Date.iso8601(v)
24
- end
25
- end
19
+ if doc["value"]
20
+ maybe_multiple(doc["value"]) do |v|
21
+ Date.iso8601(v)
22
+ end
23
+ end
26
24
  else
27
- raise "Unknown type #{type}"
25
+ raise "Unknown type #{type}"
28
26
  end
29
27
  end
30
28
 
31
- def value=(value)
29
+ def value=(value) # rubocop:disable Metrics/AbcSize
32
30
  case type
33
31
  when "text", "phone_number", "select"
34
32
  doc["value"] = maybe_multiple(value) do |v|
@@ -36,19 +34,21 @@ module Ecoportal
36
34
  end
37
35
  when "number"
38
36
  maybe_multiple(value) do |v|
39
- unless v.nil? || v.is_a?(Numeric)
40
- raise "Invalid number type #{v.class}"
41
- end
37
+ next if v.nil? || v.is_a?(Numeric)
38
+
39
+ raise "Invalid number type #{v.class}"
42
40
  end
41
+
43
42
  doc["value"] = value
44
43
  when "boolean"
45
44
  doc["value"] = !!value
46
45
  when "date"
47
46
  maybe_multiple(value) do |v|
48
- unless v.nil? || v.respond_to?(:to_date)
49
- raise "Invalid date type #{v.class}"
50
- end
47
+ next if v.nil? || v.respond_to?(:to_date)
48
+
49
+ raise "Invalid date type #{v.class}"
51
50
  end
51
+
52
52
  doc["value"] = maybe_multiple(value) do |v|
53
53
  v&.to_date&.to_s
54
54
  end
@@ -57,12 +57,11 @@ module Ecoportal
57
57
  end
58
58
  end
59
59
 
60
- def maybe_multiple(value)
60
+ def maybe_multiple(value, &block)
61
61
  if multiple
62
- unless value.is_a?(Array)
63
- raise "Expected Array, got #{value.class}"
64
- end
65
- value.map {|v| yield v }
62
+ raise "Expected Array, got #{value.class}" unless value.is_a?(Array)
63
+
64
+ value.map(&block)
66
65
  else
67
66
  yield value
68
67
  end
@@ -6,9 +6,10 @@ module Ecoportal
6
6
  extend Common::BaseClass
7
7
  include Common::Logging
8
8
 
9
- VERSION = "v1"
10
- class_resolver :people_class, "Ecoportal::API::V1::People"
11
- class_resolver :person_schemas_class, "Ecoportal::API::V1::PersonSchemas"
9
+ VERSION = "v1".freeze
10
+
11
+ class_resolver :people_class, "Ecoportal::API::V1::People"
12
+ class_resolver :person_schemas_class, "Ecoportal::API::V1::PersonSchemas"
12
13
 
13
14
  attr_reader :client, :logger
14
15
 
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- VERSION = "0.9.7"
3
+ VERSION = "0.10.1".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecoportal-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tapio Saarinen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-06 00:00:00.000000000 Z
11
+ date: 2024-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 2.4.12
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '3'
23
- type: :development
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 2.4.12
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '3'
33
13
  - !ruby/object:Gem::Dependency
34
14
  name: rspec
35
15
  requirement: !ruby/object:Gem::Requirement
@@ -125,65 +105,59 @@ dependencies:
125
105
  - !ruby/object:Gem::Version
126
106
  version: '0.14'
127
107
  - !ruby/object:Gem::Dependency
128
- name: http
108
+ name: dotenv
129
109
  requirement: !ruby/object:Gem::Requirement
130
110
  requirements:
131
111
  - - "~>"
132
112
  - !ruby/object:Gem::Version
133
- version: '5.1'
134
- - - "<"
135
- - !ruby/object:Gem::Version
136
- version: '6'
113
+ version: '3'
137
114
  type: :runtime
138
115
  prerelease: false
139
116
  version_requirements: !ruby/object:Gem::Requirement
140
117
  requirements:
141
118
  - - "~>"
142
119
  - !ruby/object:Gem::Version
143
- version: '5.1'
144
- - - "<"
145
- - !ruby/object:Gem::Version
146
- version: '6'
120
+ version: '3'
147
121
  - !ruby/object:Gem::Dependency
148
- name: dotenv
122
+ name: elastic-apm
149
123
  requirement: !ruby/object:Gem::Requirement
150
124
  requirements:
151
125
  - - ">="
152
126
  - !ruby/object:Gem::Version
153
- version: '2.8'
127
+ version: '4.7'
154
128
  - - "<"
155
129
  - !ruby/object:Gem::Version
156
- version: '3'
130
+ version: '5'
157
131
  type: :runtime
158
132
  prerelease: false
159
133
  version_requirements: !ruby/object:Gem::Requirement
160
134
  requirements:
161
135
  - - ">="
162
136
  - !ruby/object:Gem::Version
163
- version: '2.8'
137
+ version: '4.7'
164
138
  - - "<"
165
139
  - !ruby/object:Gem::Version
166
- version: '3'
140
+ version: '5'
167
141
  - !ruby/object:Gem::Dependency
168
- name: elastic-apm
142
+ name: http
169
143
  requirement: !ruby/object:Gem::Requirement
170
144
  requirements:
171
- - - ">="
145
+ - - "~>"
172
146
  - !ruby/object:Gem::Version
173
- version: '4.7'
147
+ version: '5.1'
174
148
  - - "<"
175
149
  - !ruby/object:Gem::Version
176
- version: '5'
150
+ version: '6'
177
151
  type: :runtime
178
152
  prerelease: false
179
153
  version_requirements: !ruby/object:Gem::Requirement
180
154
  requirements:
181
- - - ">="
155
+ - - "~>"
182
156
  - !ruby/object:Gem::Version
183
- version: '4.7'
157
+ version: '5.1'
184
158
  - - "<"
185
159
  - !ruby/object:Gem::Version
186
- version: '5'
160
+ version: '6'
187
161
  description:
188
162
  email:
189
163
  - tapio@ecoportal.co.nz
@@ -195,8 +169,10 @@ extensions: []
195
169
  extra_rdoc_files: []
196
170
  files:
197
171
  - ".gitignore"
172
+ - ".markdownlint.json"
198
173
  - ".rspec"
199
174
  - ".rubocop.yml"
175
+ - ".ruby-version"
200
176
  - ".yardopts"
201
177
  - CHANGELOG.md
202
178
  - Gemfile
@@ -250,7 +226,8 @@ files:
250
226
  homepage: https://www.ecoportal.com
251
227
  licenses:
252
228
  - MIT
253
- metadata: {}
229
+ metadata:
230
+ rubygems_mfa_required: 'true'
254
231
  post_install_message:
255
232
  rdoc_options: []
256
233
  require_paths:
@@ -259,14 +236,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
259
236
  requirements:
260
237
  - - ">="
261
238
  - !ruby/object:Gem::Version
262
- version: 2.7.2
239
+ version: 3.2.2
263
240
  required_rubygems_version: !ruby/object:Gem::Requirement
264
241
  requirements:
265
242
  - - ">="
266
243
  - !ruby/object:Gem::Version
267
244
  version: '0'
268
245
  requirements: []
269
- rubygems_version: 3.4.12
246
+ rubygems_version: 3.5.6
270
247
  signing_key:
271
248
  specification_version: 4
272
249
  summary: A collection of helpers for interacting with the ecoPortal MS's various APIs