zuora_api 1.6.15 → 1.6.16

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
  SHA1:
3
- metadata.gz: b9c9111752188cb90238bb392e0aae06b418b8ed
4
- data.tar.gz: 7ef09b01663e686f0ca345df80d811dbb6985f51
3
+ metadata.gz: cf22e129425646f0333a0fbfba46454caed076d8
4
+ data.tar.gz: 8bef1bdcdc8d148b6450846f8d8fc014f6964543
5
5
  SHA512:
6
- metadata.gz: 98acc03915f4858ea36879443524d29787cbc3b3cf910fad20c512c3dbbdbc65c77de6e53e6bb131738af2e43f20d1411fb693f41bc4e586cf76ca1f801eca93
7
- data.tar.gz: 1e750f3eb7156be665471ccac1a374f8fbc3b399388aa61670a590d837c2b6984202d37bc1bdfacc9527cdce58ec46b4d02acb56df80b1e36046ceac147b3078
6
+ metadata.gz: b7f61fe146b9593d91315f95e91dbc073229b80e71274630c76b5c30d099b12ed4b282c54cdac7106bb02141f490cfd2d2df8d881623af200be415435d77070f
7
+ data.tar.gz: 7a4e6c34d8c7019c1d1d474b7c946db1d85b075ea173bc4571fb29ae15d28113857002e5ec03f809b8c681e4dc8345f80840adede4f5ff899e931eddaac2b636
@@ -4,23 +4,200 @@ require "uri"
4
4
 
5
5
  module ZuoraAPI
6
6
  class Login
7
- ENVIRONMENTS = [SANDBOX = 'Sandbox', PRODUCTION = 'Production', PREFORMANCE = 'Preformance', SERVICES = 'Services', UNKNOWN = 'Unknown' ]
7
+ ENVIRONMENTS = [SANDBOX = 'Sandbox', PRODUCTION = 'Production', PREFORMANCE = 'Preformance', SERVICES = 'Services', UNKNOWN = 'Unknown', STAGING = 'Staging' ]
8
8
  REGIONS = [EU = 'EU', US = 'US', NA = 'NA' ]
9
9
  MIN_Endpoint = '91.0'
10
10
  XML_SAVE_OPTIONS = Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
11
- attr_accessor :region, :url, :wsdl_number, :current_session, :environment, :status, :errors, :current_error, :user_info, :tenant_id, :tenant_name, :entity_id, :timeout_sleep
11
+ attr_accessor :region, :url, :wsdl_number, :current_session, :environment, :status, :errors, :current_error, :user_info, :tenant_id, :tenant_name, :entity_id, :timeout_sleep, :hostname, :zconnect_provider
12
12
 
13
13
  def initialize(url: nil, entity_id: nil, session: nil, status: nil, **keyword_args)
14
+ raise "URL is nil or empty, but URL is required" if url.nil? | url.empty?
15
+ # raise "URL is improper. URL must contain zuora.com, zuora.eu, or zuora.na" if /zuora.com|zuora.eu|zuora.na/ === url
14
16
  @url = url.gsub(/(\d{2}\.\d)$/, MIN_Endpoint)
17
+ @hostname = /(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url)[0] if !/(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url).nil?
15
18
  @entity_id = get_entity_id(entity_id: entity_id)
16
19
  @errors = Hash.new
17
20
  @current_session = session
18
21
  @status = status.blank? ? "Active" : status
19
22
  @user_info = Hash.new
23
+ self.update_region
20
24
  self.update_environment
25
+ self.update_zconnect_provider
21
26
  @timeout_sleep = 5
22
27
  end
23
28
 
29
+ def get_identity(cookies)
30
+ zsession = cookies["ZSession"]
31
+ zconnect_accesstoken = get_zconnect_accesstoken(cookies)
32
+ begin
33
+ if false && !zsession.blank?
34
+ # Does not currently exist / function properly
35
+ # use the zsession API when/if it exists
36
+ elsif !zconnect_accesstoken.blank?
37
+ code = zconnect_accesstoken.split("#!").last
38
+ encrypted_token, tenant_id = Base64.decode64(code).split(":")
39
+ begin
40
+ body = {'token' => encrypted_token}.to_json
41
+ rescue => ex
42
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Invalid ZConnect Cookie", {}, 400)
43
+ end
44
+ response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/identity", :body => body, :headers => { 'Content-Type' => 'application/json' })
45
+ output_json = JSON.parse(response.body)
46
+ else
47
+ if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
48
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}", {}, 400)
49
+ else
50
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present", {}, 400)
51
+ end
52
+ end
53
+ rescue JSON::ParserError => ex
54
+ output_json = {}
55
+ end
56
+ raise_errors(type: :JSON, body: output_json, response: response)
57
+ return output_json
58
+ end
59
+
60
+ def get_full_nav(cookies)
61
+ zsession = cookies["ZSession"]
62
+ zconnect_accesstoken = get_zconnect_accesstoken(cookies)
63
+ begin
64
+ if !zsession.blank?
65
+ response = HTTParty.get("https://#{self.hostname}/apps/v1/navigation", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
66
+ output_json = JSON.parse(response.body)
67
+ elsif !zconnect_accesstoken.blank?
68
+ response = HTTParty.get("https://#{self.hostname}/apps/zconnectsession/navigation", :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}",'Content-Type' => 'application/json'})
69
+ output_json = JSON.parse(response.body)
70
+ else
71
+ if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
72
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}", {}, 400)
73
+ else
74
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present", {}, 400)
75
+ end
76
+ end
77
+ rescue JSON::ParserError => ex
78
+ output_json = {}
79
+ end
80
+ raise_errors(type: :JSON, body: output_json, response: response)
81
+ return output_json
82
+ end
83
+
84
+ def set_nav(state, cookies)
85
+ zsession = cookies["ZSession"]
86
+ zconnect_accesstoken = get_zconnect_accesstoken(cookies)
87
+ begin
88
+ if !zsession.blank?
89
+ response = HTTParty.put("https://#{self.hostname}/apps/v1/preference/navigation", :body => state.to_json, :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
90
+ output_json = JSON.parse(response.body)
91
+ elsif !zconnect_accesstoken.blank?
92
+ response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/navigationstate", :body => state.to_json, :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}", 'Content-Type' => 'application/json'})
93
+ output_json = JSON.parse(response.body)
94
+ else
95
+ if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
96
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}", {}, 400)
97
+ else
98
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present", {}, 400)
99
+ end
100
+ end
101
+ rescue JSON::ParserError => ex
102
+ output_json = {}
103
+ end
104
+ raise_errors(type: :JSON, body: output_json, response: response)
105
+ return output_json
106
+ end
107
+
108
+ def refresh_nav(cookies)
109
+ zsession = cookies["ZSession"]
110
+ zconnect_accesstoken = get_zconnect_accesstoken(cookies)
111
+ begin
112
+ if !zsession.blank?
113
+ response = HTTParty.post("https://#{self.hostname}/apps/v1/navigation/fetch", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
114
+ output_json = JSON.parse(response.body)
115
+ elsif !zconnect_accesstoken.blank?
116
+ response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/refresh-navbarcache", :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}", 'Content-Type' => 'application/json'})
117
+ output_json = JSON.parse(response.body)
118
+ else
119
+ if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
120
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}", {}, 400)
121
+ else
122
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present", {}, 400)
123
+ end
124
+ end
125
+ rescue JSON::ParserError => ex
126
+ output_json = {}
127
+ end
128
+ raise_errors(type: :JSON, body: output_json, response: response)
129
+ return output_json
130
+ end
131
+
132
+ def get_zconnect_accesstoken(cookies)
133
+ accesstoken = nil
134
+ self.update_zconnect_provider
135
+ if !cookies[self.zconnect_provider].nil? && !cookies[self.zconnect_provider].empty?
136
+ accesstoken = cookies[self.zconnect_provider]
137
+ end
138
+ return accesstoken
139
+ end
140
+
141
+ def reporting_url(path)
142
+ map = {"US" => {"Sandbox" => "https://zconnectsandbox.zuora.com/api/rest/v1/",
143
+ "Production" => "https://zconnect.zuora.com/api/rest/v1/",
144
+ "Services"=> ""},
145
+ "EU" => {"Sandbox" => "https://zconnect.sandbox.eu.zuora.com/api/rest/v1/",
146
+ "Production" => "https://zconnect.eu.zuora.com/api/rest/v1/",
147
+ "Services"=> ""},
148
+ "NA" => {"Sandbox" => "https://zconnect.sandbox.na.zuora.com/api/rest/v1/",
149
+ "Production" => "https://zconnect.na.zuora.com/api/rest/v1/",
150
+ "Services"=> ""}
151
+ }
152
+ return map[zuora_client.region][zuora_client.environment].insert(-1, path)
153
+ end
154
+
155
+ # There are two ways to call this method. The first way is best.
156
+ # 1. Pass in cookies and optionally custom_authorities, name, and description
157
+ # 2. Pass in user_id, entity_ids, client_id, client_secret, and optionally custom_authorities, name, and description
158
+ # https://intranet.zuora.com/confluence/display/Sunburst/Create+an+OAuth+Client+through+API+Gateway#CreateanOAuthClientthroughAPIGateway-ZSession
159
+ def get_oauth_client (custom_authorities = [], info_name: "No Name", info_desc: "This client was created without a description.", user_id: nil, entity_ids: nil, client_id: nil, client_secret: nil, new_client_id: nil, new_client_secret: nil, cookies: nil)
160
+ authorization = ""
161
+ new_client_id = SecureRandom.uuid if new_client_id.blank?
162
+ new_client_secret = SecureRandom.hex(10) if new_client_secret.blank?
163
+
164
+ if !cookies.nil?
165
+ authorization = cookies["ZSession"]
166
+ authorization = "ZSession-a3N2w #{authorization}"
167
+ if entity_ids.blank? && cookies["ZuoraCurrentEntity"].present?
168
+ entity_ids = Array(cookies["ZuoraCurrentEntity"].unpack("a8a4a4a4a12").join('-'))
169
+ else
170
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Zuora Entity ID not provided", {}, 400)
171
+ end
172
+ if user_id.blank? && cookies["Zuora-User-Id"].present?
173
+ user_id = cookies["Zuora-User-Id"]
174
+ else
175
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Zuora User ID not provided", {}, 400)
176
+ end
177
+ elsif !client_id.nil? && !client_secret.nil?
178
+ bearer_response = HTTParty.post("https://#{self.hostname}/oauth/token", :headers => {'Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json'}, :body => {'client_id' => client_id, 'client_secret' => URI::encode(client_secret), 'grant_type' => 'client_credentials'})
179
+ bearer_hash = JSON.parse(bearer_response.body)
180
+ bearer_token = bearer_hash["access_token"]
181
+ authorization = "Bearer #{bearer_token}"
182
+ end
183
+
184
+ if !authorization.blank? && !user_id.blank? && !entity_ids.blank?
185
+ endpoint = self.rest_endpoint("genesis/clients")
186
+ oauth_response = HTTParty.post(endpoint, :headers => {'authorization' => authorization, 'Content-Type' => 'application/json'}, :body => {'clientId' => new_client_id, 'clientSecret' => new_client_secret, 'userId' => user_id, 'entityIds' => entity_ids, 'customAuthorities' => custom_authorities, 'additionalInformation' => {'description' => info_desc, 'name' => info_name}}.to_json)
187
+ output_json = JSON.parse(oauth_response.body)
188
+ if oauth_response.code == 201
189
+ output_json["clientSecret"] = new_client_secret
190
+ return output_json
191
+ elsif oauth_response.code == 401 && !oauth_response.message.blank?
192
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["message"], {}, oauth_response.code)
193
+ else
194
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["error"], {}, oauth_response.code)
195
+ end
196
+ else
197
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Insufficient credentials provided", {}, 400)
198
+ end
199
+ end
200
+
24
201
  def self.environments
25
202
  %w(Sandbox Production Services Performance Staging)
26
203
  end
@@ -58,45 +235,105 @@ module ZuoraAPI
58
235
  return entity_id
59
236
  end
60
237
 
238
+ def update_region
239
+ if !self.hostname.blank?
240
+ if /(?<=\.|\/|^)(eu)(?=\.|\/|$)/ === self.hostname
241
+ self.region = "EU"
242
+ elsif /(?<=\.|\/|^)(na)(?=\.|\/|$)/ === self.hostname
243
+ self.region = "NA"
244
+ else
245
+ self.region = "US"
246
+ end
247
+ else # This will never happen
248
+ # raise "Can't update region because URL is blank"
249
+ self.region = "Unknown"
250
+ end
251
+ end
252
+
61
253
  def update_environment
62
254
  if !self.url.blank?
63
- env_path = self.url.split('https://').last.split('.zuora.com').first
64
- self.region = self.url.include?("eu.") ? "EU" : self.url.include?("na.") ? "NA" : "US"
65
- if env_path == 'apisandbox' || self.url.include?('sandbox')
255
+ if /(?<=\.|\/|-|^)(apisandbox|sandbox)(?=\.|\/|-|$)/ === self.hostname
66
256
  self.environment = 'Sandbox'
67
- elsif env_path == 'www' || env_path == 'api' || self.url.include?('tls10.zuora.com') || self.url.include?('origin-www.zuora.com') || self.url.include?('zforsf.zuora.com') || self.url.include?('https://zuora.com') || self.url.include?('eu.zuora.com') || self.url.include?('https://na.zuora.com')
68
- self.environment = 'Production'
69
- elsif env_path.include?('service') || env_path.include?('ep-edge')
257
+ elsif /(?<=\.|\/|^)(service|services[\d]*|ep-edge)(?=\.|\/|$)/ === self.hostname
70
258
  self.environment = 'Services'
71
- elsif env_path.include?('pt')
259
+ elsif /(?<=\.|\/|-|^)(pt[\d]*)(?=\.|\/|-|$)/ === self.hostname
72
260
  self.environment = 'Performance'
73
- elsif env_path.include?('staging2') || env_path.include?('staging1')
74
- self.region = 'US'
261
+ elsif /(?<=\.|\/|^)(staging1|staging2|stg)(?=\.|\/|$)/ === self.hostname
75
262
  self.environment = 'Staging'
263
+ elsif is_prod_env
264
+ self.environment = 'Production'
76
265
  else
77
266
  self.environment = 'Unknown'
78
267
  end
268
+ else # this will never happen
269
+ raise "Can't determine environment from blank URL"
270
+ end
271
+ end
272
+
273
+ def is_prod_env
274
+ is_prod = false
275
+ www_or_api = /(?<=\.|\/|^)(www|api)(?=\.|\/|$)/ === self.hostname
276
+ host_prefix_match = /(^|tls10\.|origin-www\.|zforsf\.|eu\.|na\.)(zuora\.com)/ === self.hostname
277
+ if www_or_api || host_prefix_match
278
+ is_prod = true
79
279
  end
280
+ return is_prod
281
+ end
282
+
283
+ def update_zconnect_provider
284
+ region = update_region
285
+ environment = update_environment
286
+ mappings = {"US" => {"Sandbox" => "ZConnectSbx", "KubeSTG" => "ZConnectDev", "KubeDEV" => "ZConnectDev", "KubePROD" => "ZConnectDev", "Services" => "ZConnectQA", "Production" => "ZConnectProd", "Performance" => "ZConnectPT1", "Staging" => "ZConnectQA"},
287
+ "NA" => {"Sandbox" => "ZConnectSbxNA", "Services" => "ZConnectQANA", "Production" => "ZConnectProdNA", "Performance" => "ZConnectPT1NA"},
288
+ "EU" => {"Sandbox" => "ZConnectSbxEU", "Services" => "ZConnectQAEU", "Production" => "ZConnectProdEU", "Performance" => "ZConnectPT1EU"},
289
+ "Unknown" => {"Unknown" => "Unknown"}}
290
+ self.zconnect_provider = mappings[region][environment]
291
+ # raise "Can't find ZConnect Provider for #{region} region and #{environment} environment" if self.zconnect_provider.nil?
80
292
  end
81
293
 
82
294
  def aqua_endpoint(url="")
83
- return "#{self.url.split("/apps").first}/apps/api/".concat(url)
295
+ match = /.*(\/apps\/)/.match(self.url)
296
+ if !match.nil?
297
+ url_slash_apps_slash = match[0]
298
+ else
299
+ raise "self.url has no /apps in it"
300
+ end
301
+ return "#{url_slash_apps_slash}api/#{url}"
84
302
  end
85
303
 
86
304
  def rest_endpoint(url="")
87
- if self.environment == 'Sandbox'
88
- return self.region == "US" ? "https://rest.apisandbox.zuora.com/v1/".concat(url) : self.region == "EU" ? "https://rest.sandbox.eu.zuora.com/v1/".concat(url) : "https://rest.sandbox.na.zuora.com/v1/".concat(url)
89
- elsif self.environment == 'Production'
90
- return self.region == "US" ? "https://rest.zuora.com/v1/".concat(url) : self.region == "EU" ? "https://rest.eu.zuora.com/v1/".concat(url) : "https://rest.na.zuora.com/v1/".concat(url)
91
- elsif self.environment == 'Services'
92
- return self.url.split('/')[0..2].join('/').concat('/apps/v1/').concat(url)
93
- elsif self.environment == 'Performance'
94
- return self.url.split('/')[0..2].join('/').concat('/apps/v1/').concat(url)
95
- elsif self.environment == 'Staging'
96
- return "https://rest-staging2.zuora.com/v1/".concat(url)
97
- else self.environment == 'Unknown'
98
- return url
305
+ update_environment
306
+ endpoint = url
307
+
308
+ case self.environment
309
+ when 'Sandbox'
310
+ case self.region
311
+ when 'US'
312
+ endpoint = "https://rest.apisandbox.zuora.com/v1/".concat(url)
313
+ when 'EU'
314
+ endpoint = "https://rest.sandbox.eu.zuora.com/v1/".concat(url)
315
+ when 'NA'
316
+ endpoint = "https://rest.sandbox.na.zuora.com/v1/".concat(url)
317
+ end
318
+ when 'Production'
319
+ case self.region
320
+ when 'US'
321
+ endpoint = "https://rest.zuora.com/v1/".concat(url)
322
+ when 'EU'
323
+ endpoint = "https://rest.eu.zuora.com/v1/".concat(url)
324
+ when 'NA'
325
+ endpoint = "https://rest.na.zuora.com/v1/".concat(url)
326
+ end
327
+ when 'Services', 'Performance'
328
+ https = /https:\/\/|http:\/\//.match(self.url)[0]
329
+ host = self.hostname
330
+ endpoint = "#{https}#{host}/apps/v1/#{url}"
331
+ when 'Staging'
332
+ endpoint = "https://rest-staging2.zuora.com/".concat(url)
333
+ when 'Unknown'
334
+ raise "Environment unknown, returning passed in parameter unaltered"
99
335
  end
336
+ return endpoint
100
337
  end
101
338
 
102
339
  def fileURL(url="")
@@ -282,6 +519,10 @@ module ZuoraAPI
282
519
  raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new()
283
520
  end
284
521
 
522
+ if body['errorMessage']
523
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new(body['errorMessage'],body,response.code)
524
+ end
525
+
285
526
  if body.dig("reasons").nil? ? false : body.dig("reasons")[0].dig("code") == 90000020
286
527
  raise ZuoraAPI::Exceptions::BadEntityError.new("#{messages_array.join(', ')}", body, response.code)
287
528
  end
@@ -1,3 +1,3 @@
1
1
  module ZuoraAPI
2
- VERSION = "1.6.15"
2
+ VERSION = "1.6.16"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zuora_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.15
4
+ version: 1.6.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zuora Strategic Solutions Group
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-04 00:00:00.000000000 Z
11
+ date: 2018-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler