mxhero-api 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd9797bb2cc13eac686ff6ce3c752396de59706b
4
- data.tar.gz: 9bc4cbf33c069f94bc9bf3e1fb762a9b27e0962d
3
+ metadata.gz: 535eca4642e82189a54e53e6c6cf5fd33d9f5a95
4
+ data.tar.gz: 98e5d823eac1440b0770e14f098dc4837de59c7d
5
5
  SHA512:
6
- metadata.gz: 1dde47f1599375cad99c0fd481f37ec44e25ba548a5c09393c007efff1662efe53c4e68f0110b6d5435b865639b62fc5dfdd82f4518b5c2ac0da50ee048982b8
7
- data.tar.gz: 90e1f1bb6c9c12b9e6f76ebec3afc78fd79d005ff658c3387ad1be66e8c313e1167ffcbfe74012b5eab750963a5a9383edafa4c9f8d185451a593e95a5a85036
6
+ metadata.gz: 969b79fbd3b9f95d86646be9b97f7d85d248cb9b1ee97237a6480458e3a98e1b6c3783a92d45d9da9d0344924b5dfdc2c12a0d31accbb08386acd60a819ab3b7
7
+ data.tar.gz: c3042de5c0ba0e3ccb34ae2edf360198dc86e47d86842a4dfda182c67aaea9ae0b16c703ac956373f244e0787a337a5226fa0169aa5ee5c421e1483f009ce54c
data/README.md CHANGED
@@ -82,6 +82,20 @@ Some examples, **complete documentation in the [API client documentation](http:/
82
82
 
83
83
  Complete documentation in the [API client documentation](http://www.rubydoc.info/gems/mxhero-api/MxHero/API/Client.html)
84
84
 
85
+ ## Run test
86
+
87
+ Run all test
88
+
89
+ rake test
90
+
91
+ Run specific method
92
+
93
+ ruby test/test_emailsync.rb --name=test_delete -v
94
+
95
+ Or:
96
+
97
+ rake test TEST=test/test_foobar.rb TESTOPTS="--name=test_foobar1 -v"
98
+
85
99
  ## Build a new version
86
100
 
87
101
  rake version:bump
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.3
1
+ 1.1.4
@@ -12,6 +12,7 @@ module MxHero
12
12
  # @param body [String] (default: nil)
13
13
  # @param [Hash] more_options
14
14
  # @option more_options [Boolean] :throw_exception (default: true) throw exception if the response status are between 500 and 600
15
+ # @return [HTTP::Message](http://www.rubydoc.info/gems/httpclient/HTTP/Message)
15
16
  def call(method, url, body = nil, more_options = {})
16
17
  unless @client
17
18
  @client ||= HTTPClient.new
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+ require_relative 'communication'
3
+ require_relative 'urls'
4
+ #require_relative 'response'
5
+
6
+ module MxHero::API
7
+
8
+ class EmailSync
9
+
10
+ include Communication
11
+ include Urls
12
+
13
+ #attr_reader :domain
14
+
15
+ def initialize(config = {})
16
+ @service_url = config[:api_url]
17
+ @username = config[:username]
18
+ @password = config[:password]
19
+ @verbose = config[:verbose] || false
20
+ end
21
+
22
+ def all(domain, params = {})
23
+ wrap_response_from call(:get, url(domain, params))
24
+ end
25
+
26
+ def task_by_id(domain, id)
27
+ return if id.nil? || id.empty?
28
+ wrap_response_from call(:get, "#{url(domain)}#{id}")
29
+ end
30
+
31
+ def delete(domain, id)
32
+ return if id.nil? || id.empty?
33
+ wrap_response_from call(:delete, "#{url(domain)}#{id}")
34
+ end
35
+
36
+ # Make a request in the endpoin /emailsync/#{domain}
37
+ # @param method [Symbol] indicate the HTTP verb (:get, :post, :put, etc)
38
+ # @param path [String] the path after the base URL (base url: #{api_url}/emailsync/#{domain})
39
+ # @param [Hash] more
40
+ # @option more [Hash] :params the URL parameters to add in the URL (ex. {limit: 10} => ?limit=10)
41
+ # @option more [Hash] :body the body content to send in POST or PUT
42
+ #
43
+ # @return [HTTP::Message](http://www.rubydoc.info/gems/httpclient/HTTP/Message)
44
+ # Useful methods: status, content
45
+ def request(domain, method, path = '/', more = {})
46
+ url = "#{@service_url}/emailsync/#{domain}#{path}#{parse_params(more[:params])}"
47
+ call(method, url, more[:body])
48
+ end
49
+
50
+ private
51
+
52
+ def url(domain, params = {})
53
+ "#{@service_url}/emailsync/#{domain}/#{parse_params(params)}"
54
+ end
55
+
56
+ def parse_params(params = {})
57
+ return if blank?(params)
58
+ '?' << params.map do |key, value|
59
+ "#{URI::encode(key.to_s)}=#{URI::encode(value.to_s)}"
60
+ end.join('&')
61
+ end
62
+
63
+ def wrap_response_from(response)
64
+ Response.new(response.status, json_parse(default_content(response.content)))
65
+ end
66
+
67
+ def blank?(value)
68
+ value.nil? || value.empty?
69
+ end
70
+
71
+ def default_content(content)
72
+ blank?(content) ? '{}' : content
73
+ end
74
+
75
+
76
+ end
77
+
78
+ end
@@ -4,505 +4,508 @@
4
4
  require 'date'
5
5
  require 'cgi'
6
6
 
7
- require 'communication'
8
- require 'urls'
9
- require 'groups'
10
- require 'dto'
11
- require 'directories'
12
- require 'pst-converter'
13
- require 'resource'
14
- require 'resources/account'
15
- require 'resources/domain'
16
- require 'resources/group'
7
+ require_relative 'response'
8
+ require_relative 'communication'
9
+ require_relative 'urls'
10
+ require_relative 'groups'
11
+ require_relative 'dto'
12
+ require_relative 'directories'
13
+ require_relative 'pst-converter'
14
+ require_relative 'resource'
15
+ require_relative 'resources/account'
16
+ require_relative 'resources/domain'
17
+ require_relative 'resources/group'
18
+ require_relative 'email-sync'
19
+
17
20
 
18
21
  module MxHero::API
19
22
 
20
- # A client to interact with mxhero engine API
21
- class Client
22
- include Communication
23
- include Urls
24
-
25
- # @param [Hash] config the options of configuration
26
- # @option config [String] :api_url The URL to consume the API
27
- # @option config [String] :username The username for access the API
28
- # @option config [String] :password The password for the user that access the API
29
- # @option config [Boolean] :verbose (false) If true puts information about http operations
30
- def initialize(config = {})
31
- @service_url = config[:api_url]
32
- @username = config[:username]
33
- @password = config[:password]
34
- @verbose = config[:verbose] || false
35
- end
36
-
37
- # Expose directories api
38
- #
39
- # @return MxHero::API::Directories
40
- def directories(domain)
41
- @directories ||= Directories.new(domain, api_url: @service_url,
42
- username: @username, password: @password, verbose: @verbose)
43
- end
44
-
45
- # Find a rule by domain and ID
46
- #
47
- # @param domain [String]
48
- # @param id [Integer] the rule id
49
- #
50
- # @return [Hash, nil] the Rule information or nil if not exist
51
- #
52
- # @raise an exception when the status code isn't 200
53
- def domain_rule(domain, id)
54
- url = domain_rule_url(domain, id)
55
- response = call(:get, url)
56
- raise 'an error ocurred when try to communicate with the API' if response.status != 200
57
- json_parse(response.content)
58
- end
59
-
60
- # Update a rule
61
- # @return [MxHero::API::Response] When the rule is update correctly then return MxHero::API::Response object without msg (msg nil)
62
- # In case of error, the message is completed with the cause of error
63
- def update_rule(rule)
64
- url = domain_rule_url(rule[:domain], rule[:id])
65
- response = call(:put, url, rule.to_json)
66
- parse_response(response)
67
- end
68
-
69
- # In case of error, the message is completed with the cause of error
70
- def rule_status(domain, rule_id, enabled = true)
71
- url = domain_rule_url(domain, rule_id)+"/status?enabled=#{enabled}"
72
- response = call(:put, url)
73
- parse_response(response)
74
- end
75
-
76
- # Retrive all the domains
77
- #
78
- # TODO: Improve the response. We really need manage pagination here?
79
- #
80
- # @return [Hash] with the list of domains
81
- # * :elements [Array<Hash>] the list of domains as a Hash, when any element contains:
82
- # * :domain [String]
83
- # * :server [String]
84
- # * :creationDate [Fixnum]
85
- # * :updateDate [Fixnum]
86
- # * :aliases
87
- # * :ldap
88
- # * :totalElements
89
- # * :totalPages
90
- # * :actualPage
91
- #
92
- # @raise an exception when the status code isn't 200
93
- def domains(params = {})
94
- url = domains_url
95
- limit, offset = params.values_at(:limit, :offset)
96
- url = paginate(domains_url, { limit: limit, offset: offset }) if limit && offset
97
- response = call(:get, url)
98
- raise 'an error ocurred when try to communicate with the API' if response.status != 200
99
- response_as_a_hash = json_parse(response.content)
100
- response_as_a_hash
101
- end
102
-
103
-
104
- # Move COS to trial
105
- # @return true | false
106
- def move_to_trial(domain)
107
- url = domain_by_id_url(domain) + '/cos/trial'
108
- response = call(:put, url)
109
- response.status == 200
110
- end
111
-
112
-
113
- # Create a new domain base on domain_obj hash
114
- #
115
- # @param domain_obj The domain to be created. For example:
116
- # [Hash] with detailed domain
117
- # * :domain [String]
118
- # * :server [String]
119
- # * :inbound [Boolean]
120
- # * :outbound [Boolean]
121
- # * :features [Array<Hash>]
122
- # * :cos [Hash]
123
- # * :source [String] (gapps|on_premise|ms_agent|office365)
124
- # * :aliases [Array<String>]
125
- # * :ldap [Hash]
126
- #
127
- # @return [Boolean] true if was successfully created
128
- #
129
- def create_domain(domain_obj = {})
130
- response = call(:post, domains_url, domain_obj.to_json, throw_exception: false)
131
- response.status == 201
132
- end
133
-
134
- # Create a new domain base on domain_obj hash
135
- #
136
- # @param domain_obj The domain to be created. For example:
137
- # [Hash] with detailed domain
138
- # * :domain [String]
139
- # * :server [String]
140
- # * :inbound [Boolean]
141
- # * :outbound [Boolean]
142
- # * :features [Array<Hash>]
143
- # * :cos [Hash]
144
- # * :source [String] (gapps|on_premise|ms_agent|office365)
145
- # * :aliases [Array<String>]
146
- # * :ldap [Hash]
147
- #
148
- # @return [Boolean] true if was successfully created
149
- #
150
- def add_feature(domain_name, feature_component)
151
- feature = {
152
- feature: feature_component,
153
- maxRulesAmount: 1
154
- }
155
- response = call(:post, features_url(domain_name), feature.to_json, throw_exception: false)
156
- response.status == 200
157
- end
158
-
159
- # Retrive the domain information
160
- #
161
- # @param name The domain name or id. For example: 'mydomain.com'
162
- # @return [Domain] or nil if not found
163
- #
164
- # @raise an exception when the status code is not 200 (ok) or 404 (not found)
165
- #
166
- def domain(name)
167
- domain_info = fetch domain_by_id_url(name), on_error: "An error ocurred when try to fetch the domain #{name}."
168
- return nil unless domain_info
169
- Domain.new domain_info
170
- end
171
-
172
- #def update_cos(domain, cos)
173
- # domain_by_id_url(name) + "cos/#{cos}"
174
- # response = call(:post, url, msg.to_json, throw_exception: false)
175
- #end
176
-
177
-
178
- # Fetch the LDAP information of the domain
179
- #
180
- # @return [Hash] with
181
- # * :domain
182
- # * :directoryType
183
- # * :addres
184
- # * :port
185
- # * :sslFlag [Boolean]
186
- # * :user
187
- # * :password
188
- # * :filter
189
- # * :base
190
- # * :nextUpdate
191
- # * :lastUpdate
192
- # * :error
193
- # * :overrideFlag
194
- # * :dnAuthenticate
195
- # * :properties [Array]
196
- #
197
- def ldap_info(domain)
198
- fetch domain_by_id_url(domain) + '/adldap',
199
- on_error: "An error was ocurred when try to fecht the ldap information of #{domain}"
200
- end
201
-
202
-
203
-
204
- #
205
- # Retrive all the account from one domain
206
- #
207
- # @params [String] domain
208
- # @params [String] filter_account the account to filter in the list. This can be a part of an account.
209
- # @param [Hash] refinement
210
- # @option refinement [Fixnum] :limit of elements per page
211
- # @option refinement [Fixnum] :offset number of page (start in 1)
212
- # @option refinement [String] :account filter accounts that start with this value
213
- # @option refinement [Boolean] :without_group filter accounts without group
214
- #
215
- #
216
- # @return [Hash] with the following elements:
217
- # * :elements [Array<Hash>] the list of accounts as a Hash, when any element contains:
218
- # * :account [String] example: alex
219
- # * :domain [String] example: mxhero.com
220
- # * :createdDate [Fixnum] example: 1375909565000 (epoch format)
221
- # * :updatedDate [Fixnum]
222
- # * :group [String]
223
- # * :aliases [Array<Hash>] the list of aliases of one account
224
- # * :name [String]
225
- # * :domain [String]
226
- # * :dataSource [String]
227
- # * :dataSource [String]
228
- # * :totalElements [Fixnum]
229
- # * :totalPages [Fixnum]
230
- # * :actualPage [Fixnum]
231
- #
232
- # @raise an exception when the status code isn't 200
233
- def accounts_by_domain(domain, refinement = {}) #filter_account = nil, pagination = {})
234
- params = refinement.dup
235
- filter_account = params.delete(:account)
236
- filter_account = CGI::escape(filter_account) if filter_account
237
- without_group = params.delete(:without_group) || false
238
- limit, offset = params.values_at(:limit, :offset)
239
-
240
- if without_group
241
- url = accounts_without_group_url(domain, filter_account)
242
- else
243
- url = paginate accounts_by_domain_url(domain, filter_account), { limit: limit, offset: offset }
244
- end
245
- response = call(:get, url)
246
- json_parse(response.content)
247
- end
248
-
249
- def accounts_without_group_url(domain, filter_account)
250
- domain_by_id_url(domain) + "/groups/accounts/available?account=#{filter_account}"
251
- end
252
-
253
- def verbose?
254
- @verbose
255
- end
256
-
257
- def verbose=(verbose)
258
- @verbose = verbose
259
- end
260
-
261
- # @param domain [String]
262
- # @param [Hash] msg
263
- # @option msg [String] :domain
264
- # @option msg [Boolean] :twoWays
265
- # @option msg [Boolean] :enabled
266
- # @option msg [String] :name
267
- # @option msg [Integer] :created in epoch format
268
- # @option msg [Hash] :fromDirection
269
- # @option msg [Hash] :toDirection
270
- # @option msg [Array<Hash>] :properties
271
- # @option msg [String] :component
272
- #
273
- # @return [MxHero::API::Response]
274
- def create_rule_for_domain(domain, msg)
275
- url = rules_for_domain_url(domain)
276
- response = call(:post, url, msg.to_json, throw_exception: false)
277
- parse_response(response)
278
- end
279
-
280
- ## Create a rule
281
- ##
282
- ## @param [Hash] msg
283
- ## @option msg [String] :domain
284
- ## @option msg [Boolean] :twoWays
285
- ## @option msg [Boolean] :enabled
286
- ## @option msg [String] :name
287
- ## @option msg [Integer] :created in epoch format
288
- ## @option msg [Hash] :fromDirection
289
- ## @option msg [Hash] :toDirection
290
- ## @option msg [Array<Hash>] :properties
291
- ## @option msg [String] :component
292
- ##
293
- ## [MxHero::API::Response]
294
- #def create_rule(msg)
295
- # response = call(:post, rules_url, msg.to_json, throw_exception: false)
296
- # parse_response(response)
297
- #end
298
-
299
- # Retrieve all the rules for one domain
300
- #
301
- # @param [String] domain
302
- # @param [String] component Filter the list of rules by this component [optional]
303
- #
304
- # @return [MxHero::API::Response] reponse
305
- # the key :msg contains an array of rules for the domain.
306
- def rules_for_domain(domain, component = nil)
307
- url = rules_for_domain_url(domain)
308
- url << "?component=#{component}" if component
309
- response = call(:get, url)
310
- parse_response(response, on_empty: [])
311
- end
312
-
313
- # @return [Boolean] true when operation it's ok
314
- def delete_rule(domain, id)
315
- url = domain_rule_url(domain, id)
316
- response = call(:delete, url)
317
- return true if response.status == 200
318
- return false
319
- end
320
-
321
- # @param [String] domain
322
- # @param [String] account Ex.: test or mxhero (the user name)
323
- # @return [MxHero::API::Response] reponse
324
- # the key :msg contains a Hash with the key, value of any property.
325
- # Example:
326
- #
327
- # { 'email': 'test@mxhero.com', 'name': 'John', 'lastname': 'Doe', ... }
328
- #
329
- def account_properties(domain, account)
330
- url = account_properties_url(domain, account)
331
- response = call(:get, url)
332
- if response.status == 200
333
- props = {}
334
- json_parse(response.content).each { |property| props[property[:name]] = property[:value] }
335
- return Response.new(response.code, props)
336
- end
337
- parse_response(response)
338
- end
339
-
340
- # @param [String] domain
341
- # @param [String] account
342
- # @param [Hash] properties The properties of the account. Ex.: { 'email': 'test@mxhero.com', 'name': 'John', 'lastname': 'Doe', ... }
343
- #
344
- # @return [MxHero::API::Response]. On success not return msg.
345
- def update_account_properties(domain, account, properties)
346
- url = account_properties_url(domain, account)
347
- response = call(:put, url, account_properties_to_json(properties))
348
- parse_response(response)
349
- end
350
-
351
- #
352
- # @param [String] domain
353
- # @param [Array<Hash>] accounts. An array of hash with :account and :properties. The :properties
354
- # contains a Hash with the equivalent of name and value.
355
- # @param [String] scope :groups, :properties or :both (default: properties)
356
- #
357
- def update_accounts(domain, accounts, scope = :properties)
358
- scope_param = scope == :both ? 'groups,properties' : scope.to_s
359
- #url = "/domains/#{domain}/accounts/upload?scope=#{scope_param}"
360
- url = accounts_by_domain_url(domain) + "/upload?scope=#{scope_param}"
361
-
362
- message = []
363
- accounts.each do |account|
364
- properties = remap_properties(account[:properties])
365
- message << { account: account[:account], properties: properties, group: account[:group], domain: domain }
366
- #message << { account: account[:account], properties: properties, group: account[:group] }
367
- end
368
- response = call(:put, url, message.to_json) # accounts to json
369
- parse_response(response)
370
- end
371
-
372
- # @return [Hash|String|nil] can return a hash with the key and value of any
373
- # system property. If use a parameter (key) return the string of this value.
374
- # In the two cases return nil when not found values
375
- #
376
- def system_properties(key = nil)
377
- response = call(:get, system_properties_url(key))
378
- if response.status == 200
379
- parsed = json_parse(response.content)
380
- if parsed.is_a? Array
381
- props = {}
382
- parsed.each { |property| props[property[:key]] = property[:value] }
383
- return props
384
- else
385
- return parsed[:value]
386
- end
387
- end
388
-
389
- nil
390
- end
391
-
392
- # Update or create a system property
393
- def save_system_property(key, value)
394
- property = { key: key, value: value }.to_json
395
- response = if system_properties(key).nil?
396
- call(:post, system_properties_url, property)
397
- else
398
- call(:put, system_properties_url(key), property)
399
- end
400
-
401
- parse_response(response).success?
402
- end
403
-
404
- # Obtain the list of users admin in a specific domain
405
- # @return [Array<UserVO>|nil] when there is no users for that domain.
406
- # If the domain doesn't exist then return nil
407
- def users_for_domain(domain)
408
- users = nil
409
- response = call(:get, users_for_domain_url(domain), throw_exception: false)
410
- if response.status == 200
411
- users = json_parse(response.content)
412
- end
413
- users
414
- end
415
-
416
- # Obtain the list of domains to one user
417
- # @return [Array<String>|nil] when the user exist but don't have domains the list is empty.
418
- # If the user isn't exist then return nil
419
- def user_domains(user)
420
- domains = nil
421
- response = call(:get, user_domains_url(user))
422
- if response.status == 200
423
- content = json_parse(response.content)
424
- domains = content.map { |info| info[:domain] }
425
- end
426
- domains
427
- end
428
-
429
- # Fetch the user
430
- # @return [MxHero::API::Response | nil]
431
- def fetch_user(user)
432
- response = call(:get, user_url(user))
433
- if response.status == 200
434
- return parse_response(response)
435
- end
436
- nil
437
- end
438
-
439
-
440
- # Create a new user
441
- # @param [Hash] user_info
442
- # @option user_info [String] :name
443
- # @option user_info [String] :lastName
444
- # @option user_info [String] :notifyEmail
445
- # @option user_info [String] :userName
446
- # @option user_info [String] :locale
447
- # @option user_info [String] :password
448
- #
449
- # @param [Array<String>] domains
450
- #
451
- def create_user(user_info, *domains)
452
- user = {
453
- name: "", lastName: "", notifyEmail: "",
454
- userName: "", locale: "en_US", password: "1234",
455
- authorities: ["ROLE_DOMAIN_ADMIN"],
456
- created: DateTime.now.strftime('%Q'),
457
- domains: domains.map { |domain| { domain: domain } }
458
- }
459
- user.merge!(user_info)
460
- response = call(:post, users_url, user.to_json, throw_exception: false)
461
- response.status == 201
462
- end
463
-
464
- # Associate domains with an existing user
465
- # @param [String] user
466
- # @param [String] domains
467
- #
468
- def associate_user_domain(user, domain)
469
- domain_obj = { domain: domain }
470
- response = call(:post, user_domains_url(user), domain_obj.to_json, throw_exception: false)
471
- response.status == 200
472
- end
473
-
474
- # Unassociate specific domain from an user admin
475
- # @param [String] user
476
- # @param [String] domain
477
- #
478
- def unassociate_user_domain(user, domain)
479
- response = call(:delete, user_with_domain_url(user,domain), throw_exception: false)
480
- response.status == 200
481
- end
482
-
483
-
484
- # Update user
485
- # @param [Hash] user retrieve to update
486
- #
487
- # @param user_name [String]
488
- #
489
- def update_user(user, user_name)
490
- response = call(:put, user_url(user_name), user.to_json, throw_exception: false)
491
- parse_response(response)
492
- end
493
-
494
- # Validate if the an user and password match
495
- #
496
- def valid_user_credentials?(user, password)
497
- validate_user_credential_url = user_url(user) + "password/#{password}"
498
- response = call(:get, validate_user_credential_url)
499
- response.status == 204
500
- end
501
-
502
- def set_new_password(user_name, new_password)
503
- response = call(:put, user_url_set_password(user_name, new_password), throw_exception: false)
504
- response.status == 200
505
- end
23
+ # A client to interact with mxhero engine API
24
+ class Client
25
+ include Communication
26
+ include Urls
27
+
28
+ # @param [Hash] config the options of configuration
29
+ # @option config [String] :api_url The URL to consume the API
30
+ # @option config [String] :username The username for access the API
31
+ # @option config [String] :password The password for the user that access the API
32
+ # @option config [Boolean] :verbose (false) If true puts information about http operations
33
+ def initialize(config = {})
34
+ @service_url = config[:api_url]
35
+ @username = config[:username]
36
+ @password = config[:password]
37
+ @verbose = config[:verbose] || false
38
+ end
39
+
40
+ # Expose directories api
41
+ #
42
+ # @return MxHero::API::Directories
43
+ def directories(domain)
44
+ @directories ||= Directories.new(domain, api_url: @service_url,
45
+ username: @username, password: @password, verbose: @verbose)
46
+ end
47
+
48
+ # Find a rule by domain and ID
49
+ #
50
+ # @param domain [String]
51
+ # @param id [Integer] the rule id
52
+ #
53
+ # @return [Hash, nil] the Rule information or nil if not exist
54
+ #
55
+ # @raise an exception when the status code isn't 200
56
+ def domain_rule(domain, id)
57
+ url = domain_rule_url(domain, id)
58
+ response = call(:get, url)
59
+ raise 'an error ocurred when try to communicate with the API' if response.status != 200
60
+ json_parse(response.content)
61
+ end
62
+
63
+ # Update a rule
64
+ # @return [MxHero::API::Response] When the rule is update correctly then return MxHero::API::Response object without msg (msg nil)
65
+ # In case of error, the message is completed with the cause of error
66
+ def update_rule(rule)
67
+ url = domain_rule_url(rule[:domain], rule[:id])
68
+ response = call(:put, url, rule.to_json)
69
+ parse_response(response)
70
+ end
71
+
72
+ # In case of error, the message is completed with the cause of error
73
+ def rule_status(domain, rule_id, enabled = true)
74
+ url = domain_rule_url(domain, rule_id)+"/status?enabled=#{enabled}"
75
+ response = call(:put, url)
76
+ parse_response(response)
77
+ end
78
+
79
+ # Retrive all the domains
80
+ #
81
+ # TODO: Improve the response. We really need manage pagination here?
82
+ #
83
+ # @return [Hash] with the list of domains
84
+ # * :elements [Array<Hash>] the list of domains as a Hash, when any element contains:
85
+ # * :domain [String]
86
+ # * :server [String]
87
+ # * :creationDate [Fixnum]
88
+ # * :updateDate [Fixnum]
89
+ # * :aliases
90
+ # * :ldap
91
+ # * :totalElements
92
+ # * :totalPages
93
+ # * :actualPage
94
+ #
95
+ # @raise an exception when the status code isn't 200
96
+ def domains(params = {})
97
+ url = domains_url
98
+ limit, offset = params.values_at(:limit, :offset)
99
+ url = paginate(domains_url, { limit: limit, offset: offset }) if limit && offset
100
+ response = call(:get, url)
101
+ raise 'an error ocurred when try to communicate with the API' if response.status != 200
102
+ response_as_a_hash = json_parse(response.content)
103
+ response_as_a_hash
104
+ end
105
+
106
+
107
+ # Move COS to trial
108
+ # @return true | false
109
+ def move_to_trial(domain)
110
+ url = domain_by_id_url(domain) + '/cos/trial'
111
+ response = call(:put, url)
112
+ response.status == 200
113
+ end
114
+
115
+
116
+ # Create a new domain base on domain_obj hash
117
+ #
118
+ # @param domain_obj The domain to be created. For example:
119
+ # [Hash] with detailed domain
120
+ # * :domain [String]
121
+ # * :server [String]
122
+ # * :inbound [Boolean]
123
+ # * :outbound [Boolean]
124
+ # * :features [Array<Hash>]
125
+ # * :cos [Hash]
126
+ # * :source [String] (gapps|on_premise|ms_agent|office365)
127
+ # * :aliases [Array<String>]
128
+ # * :ldap [Hash]
129
+ #
130
+ # @return [Boolean] true if was successfully created
131
+ #
132
+ def create_domain(domain_obj = {})
133
+ response = call(:post, domains_url, domain_obj.to_json, throw_exception: false)
134
+ response.status == 201
135
+ end
136
+
137
+ # Create a new domain base on domain_obj hash
138
+ #
139
+ # @param domain_obj The domain to be created. For example:
140
+ # [Hash] with detailed domain
141
+ # * :domain [String]
142
+ # * :server [String]
143
+ # * :inbound [Boolean]
144
+ # * :outbound [Boolean]
145
+ # * :features [Array<Hash>]
146
+ # * :cos [Hash]
147
+ # * :source [String] (gapps|on_premise|ms_agent|office365)
148
+ # * :aliases [Array<String>]
149
+ # * :ldap [Hash]
150
+ #
151
+ # @return [Boolean] true if was successfully created
152
+ #
153
+ def add_feature(domain_name, feature_component)
154
+ feature = {
155
+ feature: feature_component,
156
+ maxRulesAmount: 1
157
+ }
158
+ response = call(:post, features_url(domain_name), feature.to_json, throw_exception: false)
159
+ response.status == 200
160
+ end
161
+
162
+ # Retrive the domain information
163
+ #
164
+ # @param name The domain name or id. For example: 'mydomain.com'
165
+ # @return [Domain] or nil if not found
166
+ #
167
+ # @raise an exception when the status code is not 200 (ok) or 404 (not found)
168
+ #
169
+ def domain(name)
170
+ domain_info = fetch domain_by_id_url(name), on_error: "An error ocurred when try to fetch the domain #{name}."
171
+ return nil unless domain_info
172
+ Domain.new domain_info
173
+ end
174
+
175
+ #def update_cos(domain, cos)
176
+ # domain_by_id_url(name) + "cos/#{cos}"
177
+ # response = call(:post, url, msg.to_json, throw_exception: false)
178
+ #end
179
+
180
+
181
+ # Fetch the LDAP information of the domain
182
+ #
183
+ # @return [Hash] with
184
+ # * :domain
185
+ # * :directoryType
186
+ # * :addres
187
+ # * :port
188
+ # * :sslFlag [Boolean]
189
+ # * :user
190
+ # * :password
191
+ # * :filter
192
+ # * :base
193
+ # * :nextUpdate
194
+ # * :lastUpdate
195
+ # * :error
196
+ # * :overrideFlag
197
+ # * :dnAuthenticate
198
+ # * :properties [Array]
199
+ #
200
+ def ldap_info(domain)
201
+ fetch domain_by_id_url(domain) + '/adldap',
202
+ on_error: "An error was ocurred when try to fecht the ldap information of #{domain}"
203
+ end
204
+
205
+
206
+
207
+ #
208
+ # Retrive all the account from one domain
209
+ #
210
+ # @params [String] domain
211
+ # @params [String] filter_account the account to filter in the list. This can be a part of an account.
212
+ # @param [Hash] refinement
213
+ # @option refinement [Fixnum] :limit of elements per page
214
+ # @option refinement [Fixnum] :offset number of page (start in 1)
215
+ # @option refinement [String] :account filter accounts that start with this value
216
+ # @option refinement [Boolean] :without_group filter accounts without group
217
+ #
218
+ #
219
+ # @return [Hash] with the following elements:
220
+ # * :elements [Array<Hash>] the list of accounts as a Hash, when any element contains:
221
+ # * :account [String] example: alex
222
+ # * :domain [String] example: mxhero.com
223
+ # * :createdDate [Fixnum] example: 1375909565000 (epoch format)
224
+ # * :updatedDate [Fixnum]
225
+ # * :group [String]
226
+ # * :aliases [Array<Hash>] the list of aliases of one account
227
+ # * :name [String]
228
+ # * :domain [String]
229
+ # * :dataSource [String]
230
+ # * :dataSource [String]
231
+ # * :totalElements [Fixnum]
232
+ # * :totalPages [Fixnum]
233
+ # * :actualPage [Fixnum]
234
+ #
235
+ # @raise an exception when the status code isn't 200
236
+ def accounts_by_domain(domain, refinement = {}) #filter_account = nil, pagination = {})
237
+ params = refinement.dup
238
+ filter_account = params.delete(:account)
239
+ filter_account = CGI::escape(filter_account) if filter_account
240
+ without_group = params.delete(:without_group) || false
241
+ limit, offset = params.values_at(:limit, :offset)
242
+
243
+ if without_group
244
+ url = accounts_without_group_url(domain, filter_account)
245
+ else
246
+ url = paginate accounts_by_domain_url(domain, filter_account), { limit: limit, offset: offset }
247
+ end
248
+ response = call(:get, url)
249
+ json_parse(response.content)
250
+ end
251
+
252
+ def accounts_without_group_url(domain, filter_account)
253
+ domain_by_id_url(domain) + "/groups/accounts/available?account=#{filter_account}"
254
+ end
255
+
256
+ def verbose?
257
+ @verbose
258
+ end
259
+
260
+ def verbose=(verbose)
261
+ @verbose = verbose
262
+ end
263
+
264
+ # @param domain [String]
265
+ # @param [Hash] msg
266
+ # @option msg [String] :domain
267
+ # @option msg [Boolean] :twoWays
268
+ # @option msg [Boolean] :enabled
269
+ # @option msg [String] :name
270
+ # @option msg [Integer] :created in epoch format
271
+ # @option msg [Hash] :fromDirection
272
+ # @option msg [Hash] :toDirection
273
+ # @option msg [Array<Hash>] :properties
274
+ # @option msg [String] :component
275
+ #
276
+ # @return [MxHero::API::Response]
277
+ def create_rule_for_domain(domain, msg)
278
+ url = rules_for_domain_url(domain)
279
+ response = call(:post, url, msg.to_json, throw_exception: false)
280
+ parse_response(response)
281
+ end
282
+
283
+ ## Create a rule
284
+ ##
285
+ ## @param [Hash] msg
286
+ ## @option msg [String] :domain
287
+ ## @option msg [Boolean] :twoWays
288
+ ## @option msg [Boolean] :enabled
289
+ ## @option msg [String] :name
290
+ ## @option msg [Integer] :created in epoch format
291
+ ## @option msg [Hash] :fromDirection
292
+ ## @option msg [Hash] :toDirection
293
+ ## @option msg [Array<Hash>] :properties
294
+ ## @option msg [String] :component
295
+ ##
296
+ ## [MxHero::API::Response]
297
+ #def create_rule(msg)
298
+ # response = call(:post, rules_url, msg.to_json, throw_exception: false)
299
+ # parse_response(response)
300
+ #end
301
+
302
+ # Retrieve all the rules for one domain
303
+ #
304
+ # @param [String] domain
305
+ # @param [String] component Filter the list of rules by this component [optional]
306
+ #
307
+ # @return [MxHero::API::Response] reponse
308
+ # the key :msg contains an array of rules for the domain.
309
+ def rules_for_domain(domain, component = nil)
310
+ url = rules_for_domain_url(domain)
311
+ url << "?component=#{component}" if component
312
+ response = call(:get, url)
313
+ parse_response(response, on_empty: [])
314
+ end
315
+
316
+ # @return [Boolean] true when operation it's ok
317
+ def delete_rule(domain, id)
318
+ url = domain_rule_url(domain, id)
319
+ response = call(:delete, url)
320
+ return true if response.status == 200
321
+ return false
322
+ end
323
+
324
+ # @param [String] domain
325
+ # @param [String] account Ex.: test or mxhero (the user name)
326
+ # @return [MxHero::API::Response] reponse
327
+ # the key :msg contains a Hash with the key, value of any property.
328
+ # Example:
329
+ #
330
+ # { 'email': 'test@mxhero.com', 'name': 'John', 'lastname': 'Doe', ... }
331
+ #
332
+ def account_properties(domain, account)
333
+ url = account_properties_url(domain, account)
334
+ response = call(:get, url)
335
+ if response.status == 200
336
+ props = {}
337
+ json_parse(response.content).each { |property| props[property[:name]] = property[:value] }
338
+ return Response.new(response.code, props)
339
+ end
340
+ parse_response(response)
341
+ end
342
+
343
+ # @param [String] domain
344
+ # @param [String] account
345
+ # @param [Hash] properties The properties of the account. Ex.: { 'email': 'test@mxhero.com', 'name': 'John', 'lastname': 'Doe', ... }
346
+ #
347
+ # @return [MxHero::API::Response]. On success not return msg.
348
+ def update_account_properties(domain, account, properties)
349
+ url = account_properties_url(domain, account)
350
+ response = call(:put, url, account_properties_to_json(properties))
351
+ parse_response(response)
352
+ end
353
+
354
+ #
355
+ # @param [String] domain
356
+ # @param [Array<Hash>] accounts. An array of hash with :account and :properties. The :properties
357
+ # contains a Hash with the equivalent of name and value.
358
+ # @param [String] scope :groups, :properties or :both (default: properties)
359
+ #
360
+ def update_accounts(domain, accounts, scope = :properties)
361
+ scope_param = scope == :both ? 'groups,properties' : scope.to_s
362
+ #url = "/domains/#{domain}/accounts/upload?scope=#{scope_param}"
363
+ url = accounts_by_domain_url(domain) + "/upload?scope=#{scope_param}"
364
+
365
+ message = []
366
+ accounts.each do |account|
367
+ properties = remap_properties(account[:properties])
368
+ message << { account: account[:account], properties: properties, group: account[:group], domain: domain }
369
+ #message << { account: account[:account], properties: properties, group: account[:group] }
370
+ end
371
+ response = call(:put, url, message.to_json) # accounts to json
372
+ parse_response(response)
373
+ end
374
+
375
+ # @return [Hash|String|nil] can return a hash with the key and value of any
376
+ # system property. If use a parameter (key) return the string of this value.
377
+ # In the two cases return nil when not found values
378
+ #
379
+ def system_properties(key = nil)
380
+ response = call(:get, system_properties_url(key))
381
+ if response.status == 200
382
+ parsed = json_parse(response.content)
383
+ if parsed.is_a? Array
384
+ props = {}
385
+ parsed.each { |property| props[property[:key]] = property[:value] }
386
+ return props
387
+ else
388
+ return parsed[:value]
389
+ end
390
+ end
391
+
392
+ nil
393
+ end
394
+
395
+ # Update or create a system property
396
+ def save_system_property(key, value)
397
+ property = { key: key, value: value }.to_json
398
+ response = if system_properties(key).nil?
399
+ call(:post, system_properties_url, property)
400
+ else
401
+ call(:put, system_properties_url(key), property)
402
+ end
403
+
404
+ parse_response(response).success?
405
+ end
406
+
407
+ # Obtain the list of users admin in a specific domain
408
+ # @return [Array<UserVO>|nil] when there is no users for that domain.
409
+ # If the domain doesn't exist then return nil
410
+ def users_for_domain(domain)
411
+ users = nil
412
+ response = call(:get, users_for_domain_url(domain), throw_exception: false)
413
+ if response.status == 200
414
+ users = json_parse(response.content)
415
+ end
416
+ users
417
+ end
418
+
419
+ # Obtain the list of domains to one user
420
+ # @return [Array<String>|nil] when the user exist but don't have domains the list is empty.
421
+ # If the user isn't exist then return nil
422
+ def user_domains(user)
423
+ domains = nil
424
+ response = call(:get, user_domains_url(user))
425
+ if response.status == 200
426
+ content = json_parse(response.content)
427
+ domains = content.map { |info| info[:domain] }
428
+ end
429
+ domains
430
+ end
431
+
432
+ # Fetch the user
433
+ # @return [MxHero::API::Response | nil]
434
+ def fetch_user(user)
435
+ response = call(:get, user_url(user))
436
+ if response.status == 200
437
+ return parse_response(response)
438
+ end
439
+ nil
440
+ end
441
+
442
+
443
+ # Create a new user
444
+ # @param [Hash] user_info
445
+ # @option user_info [String] :name
446
+ # @option user_info [String] :lastName
447
+ # @option user_info [String] :notifyEmail
448
+ # @option user_info [String] :userName
449
+ # @option user_info [String] :locale
450
+ # @option user_info [String] :password
451
+ #
452
+ # @param [Array<String>] domains
453
+ #
454
+ def create_user(user_info, *domains)
455
+ user = {
456
+ name: "", lastName: "", notifyEmail: "",
457
+ userName: "", locale: "en_US", password: "1234",
458
+ authorities: ["ROLE_DOMAIN_ADMIN"],
459
+ created: DateTime.now.strftime('%Q'),
460
+ domains: domains.map { |domain| { domain: domain } }
461
+ }
462
+ user.merge!(user_info)
463
+ response = call(:post, users_url, user.to_json, throw_exception: false)
464
+ response.status == 201
465
+ end
466
+
467
+ # Associate domains with an existing user
468
+ # @param [String] user
469
+ # @param [String] domains
470
+ #
471
+ def associate_user_domain(user, domain)
472
+ domain_obj = { domain: domain }
473
+ response = call(:post, user_domains_url(user), domain_obj.to_json, throw_exception: false)
474
+ response.status == 200
475
+ end
476
+
477
+ # Unassociate specific domain from an user admin
478
+ # @param [String] user
479
+ # @param [String] domain
480
+ #
481
+ def unassociate_user_domain(user, domain)
482
+ response = call(:delete, user_with_domain_url(user,domain), throw_exception: false)
483
+ response.status == 200
484
+ end
485
+
486
+
487
+ # Update user
488
+ # @param [Hash] user retrieve to update
489
+ #
490
+ # @param user_name [String]
491
+ #
492
+ def update_user(user, user_name)
493
+ response = call(:put, user_url(user_name), user.to_json, throw_exception: false)
494
+ parse_response(response)
495
+ end
496
+
497
+ # Validate if the an user and password match
498
+ #
499
+ def valid_user_credentials?(user, password)
500
+ validate_user_credential_url = user_url(user) + "password/#{password}"
501
+ response = call(:get, validate_user_credential_url)
502
+ response.status == 204
503
+ end
504
+
505
+ def set_new_password(user_name, new_password)
506
+ response = call(:put, user_url_set_password(user_name, new_password), throw_exception: false)
507
+ response.status == 200
508
+ end
506
509
 
507
510
  # test_msg example:
508
511
  # {
@@ -538,126 +541,127 @@ module MxHero::API
538
541
  parse_response(response)
539
542
  end
540
543
 
541
- # --------------------------------------------------------------------------------------------------------------------------------
542
- private
543
-
544
- def users_url
545
- service_url + "/users"
546
- end
547
-
548
- def user_url(user)
549
- users_url + "/#{user}/"
550
- end
551
-
552
- def user_domains_url(user)
553
- user_url(user) + "domains"
554
- end
555
-
556
- def users_for_domain_url(domain)
557
- users_url + "/domain/#{domain}/"
558
- end
559
-
560
- def user_with_domain_url(user,domain)
561
- user_url(user) + "domains/#{domain}/"
562
- end
563
-
564
- def user_url_set_password(user,new_password)
565
- pass_esc = CGI::escape(new_password)
566
- users_url + "/#{user}/setPassword?newPassword=#{pass_esc}"
567
- end
568
-
569
- # Fetch an element from an URL. That element maybe not found
570
- # @return a Hash when the element exist. Or return nil when not found.
571
- #
572
- # @raise RuntimeError when an error ocurrs.
573
- def fetch(url, msg)
574
- response = call(:get, url)
575
- return json_parse(response.content) if response.ok?
576
- return nil if response.code == 404
577
-
578
- error = msg[:on_error] + " HTTP code: #{response.code}"
579
- if response.content.include?('message')
580
- hash = json_parse(response.content)
581
- error << " Response message: #{hash[:message]}"
582
- end
583
-
584
- raise error
585
- end
586
-
587
- def remap_properties(properties)
588
- return nil if properties.nil?
589
- properties.keys.map { |name| { name: name, value: properties[name] } }
590
- end
591
-
592
- # Complete the URL with the pagination info (:limit and :offset)
593
- # @param [String] original URL. Ex.: http://www.example.com/api/accounts
594
- # @param [Hash] pagination
595
- # @option pagination [Fixnum] :limit of elements per page
596
- # @option pagination [Fixnum] :offset number of page (start in 1)
597
- #
598
- # @return [String] the URL with the pagination parameters.
599
- # Ex.: url: http://www.example.com/api/accounts
600
- # pagination: { limit: 4, offset: 2 }
601
- # return > http://www.example.com/api/accounts?limit=4&offset=2
602
- def paginate(url, pagination)
603
- paginated = url.dup
604
- connector = url.include?('?') ? '&' : '?'
605
- [ :limit, :offset ].map do |elem|
606
- if pagination.key? elem
607
- paginated << "#{connector}#{elem.to_s}=#{pagination[elem]}"
608
- connector = '&'
609
- end
610
- end
611
- paginated
612
- end
613
-
614
- def account_properties_to_json(properties)
615
- out = []
616
- properties.each do |key, value|
617
- out << { name: key, value: value }
618
- end
619
- out.to_json
620
- end
621
-
622
- def rules_for_domain_url(domain)
623
- service_url + "/domains/#{domain}/rules"
624
- end
625
-
626
- def rules_url
627
- service_url + '/rules'
628
- end
629
-
630
- def accounts_by_domain_url(domain, filter_account = nil)
631
- filter = filter_account ? "?account=#{filter_account}" : ''
632
- domain_by_id_url(domain) + 'accounts' + filter
633
- end
634
-
635
- def domain_rule_url(domain, id)
636
- rules_for_domain_url(domain) + "/#{id}"
637
- end
638
-
639
- def features_url(domain)
640
- domain_by_id_url(domain) + "/features"
641
- end
642
-
643
- def account_properties_url(domain, account)
644
- accounts_by_domain_url(domain) + "/#{account}/properties"
645
- end
646
-
647
- def system_properties_url(key = nil)
648
- fixed_key = key.nil? ? nil : "#{key}/"
649
- service_url + "/system/properties/#{fixed_key}"
650
- end
651
-
652
- # @return [MxHero::API::Response] a response object
653
- def parse_response(response, opts = { on_empty: nil })
654
- json = response.content
655
- hash = json.nil? || json.empty? ? opts[:on_empty] : json_parse(json)
656
- Response.new(response.code, hash)
657
- end
658
-
659
-
660
-
661
- end
544
+
545
+ # --------------------------------------------------------------------------------------------------------------------------------
546
+ private
547
+
548
+ def users_url
549
+ service_url + "/users"
550
+ end
551
+
552
+ def user_url(user)
553
+ users_url + "/#{user}/"
554
+ end
555
+
556
+ def user_domains_url(user)
557
+ user_url(user) + "domains"
558
+ end
559
+
560
+ def users_for_domain_url(domain)
561
+ users_url + "/domain/#{domain}/"
562
+ end
563
+
564
+ def user_with_domain_url(user,domain)
565
+ user_url(user) + "domains/#{domain}/"
566
+ end
567
+
568
+ def user_url_set_password(user,new_password)
569
+ pass_esc = CGI::escape(new_password)
570
+ users_url + "/#{user}/setPassword?newPassword=#{pass_esc}"
571
+ end
572
+
573
+ # Fetch an element from an URL. That element maybe not found
574
+ # @return a Hash when the element exist. Or return nil when not found.
575
+ #
576
+ # @raise RuntimeError when an error ocurrs.
577
+ def fetch(url, msg)
578
+ response = call(:get, url)
579
+ return json_parse(response.content) if response.ok?
580
+ return nil if response.code == 404
581
+
582
+ error = msg[:on_error] + " HTTP code: #{response.code}"
583
+ if response.content.include?('message')
584
+ hash = json_parse(response.content)
585
+ error << " Response message: #{hash[:message]}"
586
+ end
587
+
588
+ raise error
589
+ end
590
+
591
+ def remap_properties(properties)
592
+ return nil if properties.nil?
593
+ properties.keys.map { |name| { name: name, value: properties[name] } }
594
+ end
595
+
596
+ # Complete the URL with the pagination info (:limit and :offset)
597
+ # @param [String] original URL. Ex.: http://www.example.com/api/accounts
598
+ # @param [Hash] pagination
599
+ # @option pagination [Fixnum] :limit of elements per page
600
+ # @option pagination [Fixnum] :offset number of page (start in 1)
601
+ #
602
+ # @return [String] the URL with the pagination parameters.
603
+ # Ex.: url: http://www.example.com/api/accounts
604
+ # pagination: { limit: 4, offset: 2 }
605
+ # return > http://www.example.com/api/accounts?limit=4&offset=2
606
+ def paginate(url, pagination)
607
+ paginated = url.dup
608
+ connector = url.include?('?') ? '&' : '?'
609
+ [ :limit, :offset ].map do |elem|
610
+ if pagination.key? elem
611
+ paginated << "#{connector}#{elem.to_s}=#{pagination[elem]}"
612
+ connector = '&'
613
+ end
614
+ end
615
+ paginated
616
+ end
617
+
618
+ def account_properties_to_json(properties)
619
+ out = []
620
+ properties.each do |key, value|
621
+ out << { name: key, value: value }
622
+ end
623
+ out.to_json
624
+ end
625
+
626
+ def rules_for_domain_url(domain)
627
+ service_url + "/domains/#{domain}/rules"
628
+ end
629
+
630
+ def rules_url
631
+ service_url + '/rules'
632
+ end
633
+
634
+ def accounts_by_domain_url(domain, filter_account = nil)
635
+ filter = filter_account ? "?account=#{filter_account}" : ''
636
+ domain_by_id_url(domain) + 'accounts' + filter
637
+ end
638
+
639
+ def domain_rule_url(domain, id)
640
+ rules_for_domain_url(domain) + "/#{id}"
641
+ end
642
+
643
+ def features_url(domain)
644
+ domain_by_id_url(domain) + "/features"
645
+ end
646
+
647
+ def account_properties_url(domain, account)
648
+ accounts_by_domain_url(domain) + "/#{account}/properties"
649
+ end
650
+
651
+ def system_properties_url(key = nil)
652
+ fixed_key = key.nil? ? nil : "#{key}/"
653
+ service_url + "/system/properties/#{fixed_key}"
654
+ end
655
+
656
+ # @return [MxHero::API::Response] a response object
657
+ def parse_response(response, opts = { on_empty: nil })
658
+ json = response.content
659
+ hash = json.nil? || json.empty? ? opts[:on_empty] : json_parse(json)
660
+ Response.new(response.code, hash)
661
+ end
662
+
663
+
664
+
665
+ end
662
666
 
663
667
  end