ecoportal-api 0.7.4 → 0.8.4

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.
@@ -2,29 +2,26 @@ module Ecoportal
2
2
  module API
3
3
  class Internal
4
4
  class Account < Common::BaseModel
5
- passthrough :policy_group_ids, :landing_page_id, :permissions_preset, :permissions_custom,
6
- :preferences, :prefilter, :login_provider_ids, :starred_ids, :accept_eula,
7
- :send_invites, :default_tag
5
+ PROPERTIES = [
6
+ "user_id", "policy_group_ids", "default_tag", "prefilter",
7
+ "permissions_custom", "permissions_merged", "preferences",
8
+ "login_provider_ids", "starred_ids", "landing_page_id",
9
+ "accept_eula", "send_invites"
10
+ ]
11
+ passthrough *PROPERTIES.map(&:to_sym)
8
12
 
9
13
  class_resolver :preferences_class, "Ecoportal::API::Internal::Preferences"
10
14
  class_resolver :permissions_class, "Ecoportal::API::Internal::Permissions"
11
15
 
12
16
  embeds_one :permissions, key: "permissions_custom", klass: :permissions_class
17
+ embeds_one :perms_merged, key: "permissions_merged", klass: :permissions_class
13
18
  embeds_one :preferences, klass: :preferences_class
14
19
 
15
20
  # Sets the `policy_group_ids`
16
21
  # @note it preserves the original order
17
22
  # @param value [Array<String>] the policy group ids to be set.
18
23
  def policy_group_ids=(value)
19
- unless value.is_a?(Array)
20
- raise "policy_group_ids= needs to be passed an Array, got #{value.class}"
21
- end
22
-
23
- value.uniq!
24
- ini_ids = (original_doc && original_doc["policy_group_ids"]) || []
25
- # preserve original order to avoid false updates
26
- doc["policy_group_ids"] = (ini_ids & value) + (value - ini_ids)
27
- doc["policy_group_ids"].compact
24
+ set_uniq_array_keep_order("policy_group_ids", value)
28
25
  end
29
26
 
30
27
  # @return [Array<String>] the policy group ids of this user.
@@ -34,10 +31,7 @@ module Ecoportal
34
31
 
35
32
  # Sets the `login_provider_ids`
36
33
  def login_provider_ids=(value)
37
- unless value.is_a?(Array)
38
- raise "login_provider_ids= needs to be passed an Array, got #{value.class}"
39
- end
40
- doc["login_provider_ids"] = value.compact
34
+ set_uniq_array_keep_order("login_provider_ids", value)
41
35
  end
42
36
 
43
37
  # @return [Array<String>] the login provider ids of this user.
@@ -47,10 +41,7 @@ module Ecoportal
47
41
 
48
42
  # Sets the `starred_ids`
49
43
  def starred_ids=(value)
50
- unless value.is_a?(Array)
51
- raise "starred_ids= needs to be passed an Array, got #{value.class}"
52
- end
53
- doc["starred_ids"] = value.compact
44
+ set_uniq_array_keep_order("starred_ids", value)
54
45
  end
55
46
 
56
47
  # @return [Array<String>] the starred page ids of this user.
@@ -58,20 +49,6 @@ module Ecoportal
58
49
  doc["starred_ids"] ||= []
59
50
  end
60
51
 
61
- # Sets the `permissions_preset`.
62
- # @note basically the same as `permissions_preset=` but when `"custom"`, it's changed to `nil`
63
- # @param value [nil, String] preset name.
64
- def preset=(value)
65
- self.permissions_preset = value == "custom" ? nil : value
66
- end
67
-
68
- # Gets the `permissions_preset`.
69
- # @note basically the same as `permissions_preset` but when 'nil', it returns `"custom"` instead
70
- # @return [nil, String] preset name.
71
- def preset
72
- self.permissions_preset.nil? ? "custom" : self.permissions_preset
73
- end
74
-
75
52
  # It preserves the values of keys that are not defined in `value`.
76
53
  # @param value [Hash] the abilities that you want to update.
77
54
  def permissions_custom=(value)
@@ -88,15 +65,16 @@ module Ecoportal
88
65
 
89
66
  def as_json
90
67
  super.tap do |hash|
91
- if preset == "custom"
92
- hash["permissions_custom"] = permissions.as_json
93
- else
94
- hash.delete "permissions_custom"
95
- end
68
+ hash["permissions_custom"] = permissions.as_json
69
+ hash["permissions_merged"] = perms_merged.as_json
96
70
  hash["preferences"] = preferences.as_json
97
71
  end
98
72
  end
99
73
 
74
+ def as_update(ref = :last, ignore: [])
75
+ super(ref, ignore: ignore | ["user_id", "permissions_merged", "prefilter"])
76
+ end
77
+
100
78
  end
101
79
  end
102
80
  end
@@ -3,9 +3,10 @@ module Ecoportal
3
3
  class Internal
4
4
  class Permissions < Common::BaseModel
5
5
  passthrough :files, :data, :reports
6
- passthrough :organization, :person_core, :person_core_create, :person_core_edit
7
- passthrough :person_account, :person_details
8
- passthrough :pages, :page_editor, :registers, :tasks
6
+ passthrough :organization, :pages, :page_editor, :registers, :tasks
7
+ passthrough :person_core, :person_core_create, :person_core_edit
8
+ passthrough :person_details, :person_account, :person_abilities
9
+ passthrough :visitor_management, :broadcast_notifications, :cross_register_reporting
9
10
  end
10
11
  end
11
12
  end
@@ -11,10 +11,14 @@ module Ecoportal
11
11
  super.update("account" => account&.as_json)
12
12
  end
13
13
 
14
+ def as_update(ref = :last, ignore: [])
15
+ super(ref, ignore: ignore | ["user_id", "permissions_merged", "prefilter"])
16
+ end
17
+
14
18
  # Sets the Account to the person, depending on the paramter received:
15
19
  # - `nil`: blanks the account.
16
20
  # - `Account`: sets a copy of the object param as account.
17
- # - `Hash`: slices the properties of `Account`.
21
+ # - `Hash`: slices the properties of `Account` (keeping the value of `user_id` if there was already account).
18
22
  # @note this method does not make dirty the account (meaning that `as_json` will be an empty hash `{}`)
19
23
  # @param value [nil, Account, Hash] value to be set.
20
24
  # @return [nil, Account] the resulting `Account` set to the person.
@@ -25,7 +29,9 @@ module Ecoportal
25
29
  when Internal::Account
26
30
  doc["account"] = JSON.parse(value.to_json)
27
31
  when Hash
28
- doc["account"] = value.slice(*%w[policy_group_ids default_tag landing_page_id permissions_preset permissions_custom preferences prefilter login_provider_ids starred_ids])
32
+ user_id = account.user_id if account
33
+ doc["account"] = value.slice(*Internal::Account::PROPERTIES)
34
+ doc["account"]["user_id"] = user_id if user_id
29
35
  else
30
36
  # TODO
31
37
  raise "Invalid set on account: Need nil, Account or Hash; got #{value.class}"
@@ -36,11 +36,19 @@ module Ecoportal
36
36
  puts "\n" unless silent
37
37
  loop do
38
38
  params.update(cursor_id: cursor_id) if cursor_id
39
+ body = nil; response = nil
40
+ loop do
41
+ response = client.get("/people", params: params)
42
+ body = response && body_data(response.body)
43
+ break if response.success?
44
+ puts "Request failed - Status #{response.status}: #{body}"
45
+ end
39
46
  response = client.get("/people", params: params)
40
- raise "Request failed - Status #{response.status}: #{response.body}" unless response.success?
47
+ #body = response && body_data(response.body)
48
+ #raise "Request failed - Status #{response.status}: #{body}" unless response.success?
41
49
 
42
- unless silent || (total = response.body["total_results"]) == 0
43
- results += response.body["results"].length
50
+ unless silent || (total = body["total_results"]) == 0
51
+ results += body["results"].length
44
52
  percent = results * 100 / total
45
53
  msg = "People GET"
46
54
  msg += " (search=#{params[:q]})" if params.key?(:q)
@@ -48,10 +56,10 @@ module Ecoportal
48
56
  $stdout.flush
49
57
  end
50
58
 
51
- response.body["results"].each do |person|
59
+ body["results"].each do |person|
52
60
  yield person_class.new(person)
53
61
  end
54
- break unless (cursor_id = response.body["cursor_id"])
62
+ break unless (cursor_id = body["cursor_id"])
55
63
  end
56
64
  self
57
65
  end
@@ -70,10 +78,13 @@ module Ecoportal
70
78
  # Gets a person via api.
71
79
  # @note if the request has `success?` the returned `object.result` gives an object with that `Person`.
72
80
  # @param doc [String, Hash, Person] data containing an `id` (internal or external) of the target person.
73
- # @return [WrappedResponse] an object with the api response.
81
+ # @return [Person] the person with `id` (internal or external) contained in `doc`.
74
82
  def get(doc)
75
- response = client.get("/people/"+CGI.escape(get_id(doc)))
76
- Common::WrappedResponse.new(response, person_class)
83
+ id = get_id(doc)
84
+ response = client.get("/people/"+CGI.escape(id))
85
+ body = body_data(response.body)
86
+ return person_class.new(body) if response.success?
87
+ raise "Could not get person #{id} - Error #{reponse.status}: #{body}"
77
88
  end
78
89
 
79
90
  # Requests an update of a person via api.
@@ -107,35 +118,36 @@ module Ecoportal
107
118
  # @return [Response] an object with the api response.
108
119
  def delete(doc)
109
120
  id = get_id(doc)
110
- client.delete("/people/"+CGI.escape(id))
121
+ client.delete("/people/"+CGI.escape(id))
111
122
  end
112
123
 
113
124
  # Creates a `BatchOperation` and yields it to the given bock.
114
125
  # @yield [batch_op] adds multiple api requests for the current batch.
115
126
  # @yieldparam batch_op [BatchOperation]
127
+ # @param job_mode [Boolean] whether or not it should use batch jobs
128
+ # @return [Ecoportal::API::Common::Response] the results of the batch
116
129
  def batch(job_mode: true, &block)
117
130
  return job(&block) if job_mode
118
131
  operation = Common::BatchOperation.new("/people", person_class, logger: client.logger)
119
132
  yield operation
120
133
  # The batch operation is responsible for logging the output
121
- client.without_response_logging do
122
- client.post("/people/batch", data: operation.as_json).tap do |response|
123
- operation.process_response(response)
124
- end
134
+ client.post("/people/batch", data: operation.as_json).tap do |response|
135
+ operation.process_response(response)
125
136
  end
126
137
  end
127
138
 
139
+ # @return [Ecoportal::API::Common::Response] the results of the batch job
128
140
  def job
129
141
  operation = Common::BatchOperation.new("/people", person_class, logger: client.logger)
130
142
  yield operation
131
- # The batch operation is responsible for logging the output
132
143
  job_id = create_job(operation)
133
144
  status = wait_for_job_completion(job_id)
134
145
 
135
146
  if status&.complete?
136
- operation.process_response job_result(job_id, operation)
147
+ job_result(job_id, operation)
137
148
  else
138
- raise "Job `#{job_id}` not complete. Probably timeout after #{JOB_TIMEOUT} seconds. Current status: #{status}"
149
+ msg = "Job `#{job_id}` not complete. Probably timeout after #{JOB_TIMEOUT} seconds. Current status: #{status}"
150
+ raise API::Errors::TimeOut.new msg
139
151
  end
140
152
  end
141
153
 
@@ -150,22 +162,20 @@ module Ecoportal
150
162
  JobStatus = Struct.new(:id, :complete?, :errored?, :progress)
151
163
  def job_status(job_id)
152
164
  response = client.get("/people/job/#{CGI.escape(job_id)}/status")
153
-
154
- raise "Status error" unless response.success?
165
+ body = response && body_data(response.body)
166
+ raise "Status error (#{response.status}) - Errors: #{body}" unless response.success?
155
167
  JobStatus.new(
156
- response.body["id"],
157
- response.body["complete"],
158
- response.body["errored"],
159
- response.body["progress"]
168
+ body["id"],
169
+ body["complete"],
170
+ body["errored"],
171
+ body["progress"]
160
172
  )
161
173
  end
162
174
 
175
+ # @return [Ecoportal::API::Common::Response] the results of the batch job
163
176
  def job_result(job_id, operation)
164
- # The batch operation is responsible for logging the output
165
- client.without_response_logging do
166
- client.get("/people/job/#{CGI.escape(job_id)}").tap do |response|
167
- operation.process_response(response)
168
- end
177
+ client.get("/people/job/#{CGI.escape(job_id)}").tap do |response|
178
+ operation.process_response(response)
169
179
  end
170
180
  end
171
181
 
@@ -182,15 +192,22 @@ module Ecoportal
182
192
  end
183
193
  end
184
194
 
195
+ # @return [String] the `id` of the created batch job
185
196
  def create_job(operation)
186
197
  job_id = nil
187
- client.without_response_logging do
188
- client.post("/people/job", data: operation.as_json).tap do |response|
189
- job_id = response.body["id"]
190
- end
198
+ client.post("/people/job", data: operation.as_json).tap do |response|
199
+ job_id = body_data(response.body)["id"] if response.success?
200
+ raise "Could not create job - Error (#{response.status}): #{body_data(response.body)}" unless job_id
191
201
  end
192
202
  job_id
193
203
  end
204
+
205
+ # Hook for other api versions to obtain the raw data of a response
206
+ # @note this was introduced to allow `v2` to reuse this class
207
+ def body_data(body)
208
+ body
209
+ end
210
+
194
211
  end
195
212
  end
196
213
  end
@@ -59,17 +59,13 @@ module Ecoportal
59
59
  unless value.is_a?(Array)
60
60
  raise "filter_tags= needs to be passed an Array, got #{value.class}"
61
61
  end
62
- end_tags = value.map do |tag|
62
+ end_tags = value.compact.map do |tag|
63
63
  unless tag.match(VALID_TAG_REGEX)
64
64
  raise "Invalid filter tag #{tag.inspect}"
65
65
  end
66
66
  tag.upcase
67
- end.uniq
68
-
69
- ini_tags = (original_doc && original_doc["filter_tags"]) || []
70
- # preserve original order to avoid false updates
71
- doc["filter_tags"] = (ini_tags & end_tags) + (end_tags - ini_tags)
72
- doc["filter_tags"].compact
67
+ end
68
+ set_uniq_array_keep_order("filter_tags", end_tags)
73
69
  end
74
70
 
75
71
  # @return [Array<String>] the filter tags of this person.
@@ -81,6 +77,10 @@ module Ecoportal
81
77
  super.merge "details" => details&.as_json
82
78
  end
83
79
 
80
+ def as_update(ref = :last, ignore: [])
81
+ super(ignore: ignore | ["subordinates"])
82
+ end
83
+
84
84
  # Sets the PersonDetails to the person, depending on the paramter received:
85
85
  # - `nil`: blanks the details.
86
86
  # - `PersonDetails`: sets a copy of the object param as details.
@@ -6,25 +6,24 @@ module Ecoportal
6
6
  passthrough :id, :alt_id, :type, :name, :shared, :multiple
7
7
 
8
8
  def value
9
- return @value if defined?(@value)
10
- @value = case type
11
- when "text", "phone_number", "number", "boolean", "select"
12
- doc["value"]
13
- when "date"
14
- if doc["value"]
15
- maybe_multiple(doc["value"]) do |v|
16
- Date.iso8601(v)
17
- end
18
- end
19
- else
20
- raise "Unknown type #{type}"
21
- end
9
+ case type
10
+ when "text", "phone_number", "number", "boolean", "select"
11
+ doc["value"]
12
+ when "date"
13
+ if doc["value"]
14
+ maybe_multiple(doc["value"]) do |v|
15
+ Date.iso8601(v)
16
+ end
17
+ end
18
+ else
19
+ raise "Unknown type #{type}"
20
+ end
22
21
  end
23
22
 
24
23
  def value=(value)
25
24
  case type
26
25
  when "text", "phone_number", "select"
27
- doc["value"] = @value = maybe_multiple(value) do |v|
26
+ doc["value"] = maybe_multiple(value) do |v|
28
27
  v&.to_s
29
28
  end
30
29
  when "number"
@@ -33,23 +32,21 @@ module Ecoportal
33
32
  raise "Invalid number type #{v.class}"
34
33
  end
35
34
  end
36
- doc["value"] = @value = value
35
+ doc["value"] = value
37
36
  when "boolean"
38
- doc["value"] = @value = !!value
37
+ doc["value"] = !!value
39
38
  when "date"
40
39
  maybe_multiple(value) do |v|
41
40
  unless v.nil? || v.respond_to?(:to_date)
42
41
  raise "Invalid date type #{v.class}"
43
42
  end
44
43
  end
45
- @value = value
46
- doc["value"] = maybe_multiple(@value) do |v|
44
+ doc["value"] = maybe_multiple(value) do |v|
47
45
  v&.to_date&.to_s
48
46
  end
49
47
  else
50
48
  raise "Unknown type #{type}"
51
49
  end
52
- @value
53
50
  end
54
51
 
55
52
  def maybe_multiple(value)
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- VERSION = "0.7.4"
3
+ VERSION = "0.8.4"
4
4
  end
5
5
  end
data/lib/ecoportal/api.rb CHANGED
@@ -2,6 +2,7 @@ require "cgi"
2
2
  require "logger"
3
3
  require "hash-polyfill"
4
4
  require "ecoportal/api/version"
5
+ require "dotenv/load"
5
6
 
6
7
  module Ecoportal
7
8
  module API
@@ -10,6 +11,6 @@ end
10
11
 
11
12
  require "ecoportal/api/logger"
12
13
  require "ecoportal/api/common"
14
+ require "ecoportal/api/errors"
13
15
  require "ecoportal/api/v1"
14
- require "ecoportal/api/v2"
15
16
  require "ecoportal/api/internal"