spark_api 1.3.16 → 1.3.17
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.
- data/README.md +1 -0
- data/VERSION +1 -1
- data/lib/spark_api.rb +4 -0
- data/lib/spark_api/authentication.rb +3 -3
- data/lib/spark_api/authentication/api_auth.rb +6 -6
- data/lib/spark_api/authentication/oauth2.rb +5 -5
- data/lib/spark_api/authentication/oauth2_impl/faraday_middleware.rb +6 -6
- data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +4 -4
- data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb +3 -3
- data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb +1 -1
- data/lib/spark_api/connection.rb +1 -1
- data/lib/spark_api/faraday_middleware.rb +2 -2
- data/lib/spark_api/models/listing.rb +13 -8
- data/lib/spark_api/models/listing_cart.rb +2 -2
- data/lib/spark_api/multi_client.rb +1 -1
- data/lib/spark_api/request.rb +6 -5
- data/spec/fixtures/listing_carts/put.json +9 -0
- data/spec/fixtures/listing_carts/put_ids.json +9 -0
- data/spec/fixtures/listing_carts/put_name.json +5 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/unit/spark_api/models/listing_cart_spec.rb +12 -2
- data/spec/unit/spark_api/models/listing_spec.rb +22 -0
- data/spec/unit/spark_api_spec.rb +8 -0
- metadata +512 -396
- checksums.yaml +0 -7
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.3.
|
1
|
+
1.3.17
|
data/lib/spark_api.rb
CHANGED
@@ -22,8 +22,8 @@ module SparkApi
|
|
22
22
|
start_time = Time.now
|
23
23
|
request_time = Time.now - start_time
|
24
24
|
new_session = @authenticator.authenticate
|
25
|
-
SparkApi.logger.info
|
26
|
-
SparkApi.logger.debug
|
25
|
+
SparkApi.logger.info { "[#{(request_time * 1000).to_i}ms]" }
|
26
|
+
SparkApi.logger.debug { "Session: #{new_session.inspect}" }
|
27
27
|
new_session
|
28
28
|
end
|
29
29
|
|
@@ -34,7 +34,7 @@ module SparkApi
|
|
34
34
|
|
35
35
|
# Delete the current session
|
36
36
|
def logout
|
37
|
-
SparkApi.logger.info
|
37
|
+
SparkApi.logger.info { "Logging out." }
|
38
38
|
@authenticator.logout
|
39
39
|
end
|
40
40
|
|
@@ -17,15 +17,15 @@ module SparkApi
|
|
17
17
|
|
18
18
|
def authenticate
|
19
19
|
sig = sign("#{@client.api_secret}ApiKey#{@client.api_key}")
|
20
|
-
SparkApi.logger.debug
|
20
|
+
SparkApi.logger.debug { "Authenticating to #{@client.endpoint}" }
|
21
21
|
start_time = Time.now
|
22
22
|
request_path = "/#{@client.version}/session?ApiKey=#{@client.api_key}&ApiSig=#{sig}"
|
23
23
|
resp = @client.connection(true).post request_path, ""
|
24
24
|
request_time = Time.now - start_time
|
25
|
-
SparkApi.logger.info
|
26
|
-
SparkApi.logger.debug
|
25
|
+
SparkApi.logger.info { "[#{(request_time * 1000).to_i}ms] Api: POST #{request_path}" }
|
26
|
+
SparkApi.logger.debug { "Authentication Response: #{resp.inspect}" }
|
27
27
|
@session = Session.new(resp.body.results.first)
|
28
|
-
SparkApi.logger.debug
|
28
|
+
SparkApi.logger.debug { "Authentication: #{@session.inspect}" }
|
29
29
|
@session
|
30
30
|
end
|
31
31
|
|
@@ -74,11 +74,11 @@ module SparkApi
|
|
74
74
|
request_opts.merge!(options)
|
75
75
|
sig = sign_token(escaped_path, request_opts, body)
|
76
76
|
request_path = "#{escaped_path}?#{build_url_parameters({"ApiSig"=>sig}.merge(request_opts))}"
|
77
|
-
SparkApi.logger.debug
|
77
|
+
SparkApi.logger.debug { "Request: #{request_path}" }
|
78
78
|
if body.nil?
|
79
79
|
response = @client.connection.send(method, request_path)
|
80
80
|
else
|
81
|
-
SparkApi.logger.debug
|
81
|
+
SparkApi.logger.debug { "Data: #{body}" }
|
82
82
|
response = @client.connection.send(method, request_path, body)
|
83
83
|
end
|
84
84
|
response
|
@@ -50,11 +50,11 @@ module SparkApi
|
|
50
50
|
|
51
51
|
parameter_string = options.size > 0 ? "?#{build_url_parameters(options)}" : ""
|
52
52
|
request_path = "#{escaped_path}#{parameter_string}"
|
53
|
-
SparkApi.logger.debug
|
53
|
+
SparkApi.logger.debug { "Request: #{request_path}" }
|
54
54
|
if body.nil?
|
55
55
|
response = connection.send(method, request_path)
|
56
56
|
else
|
57
|
-
SparkApi.logger.debug
|
57
|
+
SparkApi.logger.debug { "Data: #{body}" }
|
58
58
|
response = connection.send(method, request_path, body)
|
59
59
|
end
|
60
60
|
response
|
@@ -76,14 +76,14 @@ module SparkApi
|
|
76
76
|
# Create a sparkbar token based on the current user's access token
|
77
77
|
def sparkbar_token()
|
78
78
|
raise ClientError, "OAuth2Provider must configure the sparkbar_uri to use sparkbar tokens" if provider.sparkbar_uri.nil?
|
79
|
-
SparkApi.logger.debug
|
79
|
+
SparkApi.logger.debug { "[sparkbar] create token to #{provider.sparkbar_uri}" }
|
80
80
|
uri = URI.parse(provider.sparkbar_uri)
|
81
81
|
request_path = "#{uri.path}"
|
82
82
|
|
83
|
-
SparkApi.logger.info
|
83
|
+
SparkApi.logger.info { "[sparkbar] create token to #{request_path}, #{session.access_token.inspect}" }
|
84
84
|
response = sparkbar_connection("#{uri.scheme}://#{uri.host}").post(request_path, "access_token=#{session.access_token}").body
|
85
85
|
token = response["token"]
|
86
|
-
SparkApi.logger.debug
|
86
|
+
SparkApi.logger.debug { "[sparkbar] New token created #{token}" }
|
87
87
|
token
|
88
88
|
end
|
89
89
|
|
@@ -14,22 +14,22 @@ module SparkApi
|
|
14
14
|
|
15
15
|
def on_complete(env)
|
16
16
|
body = MultiJson.decode(env[:body])
|
17
|
-
SparkApi.logger.debug
|
17
|
+
SparkApi.logger.debug { "[oauth2] Response Body: #{body.inspect}" }
|
18
18
|
unless body.is_a?(Hash)
|
19
19
|
raise InvalidResponse, "The server response could not be understood"
|
20
20
|
end
|
21
21
|
case env[:status]
|
22
22
|
when 200..299
|
23
|
-
SparkApi.logger.debug
|
23
|
+
SparkApi.logger.debug{ "[oauth2] Success!" }
|
24
24
|
session = OAuthSession.new(body)
|
25
25
|
else
|
26
26
|
# Handle the WWW-Authenticate Response Header Field if present. This can be returned by
|
27
27
|
# OAuth2 implementations and wouldn't hurt to log.
|
28
28
|
auth_header_error = env[:request_headers]["WWW-Authenticate"]
|
29
|
-
SparkApi.logger.warn
|
29
|
+
SparkApi.logger.warn { "Authentication error #{auth_header_error}" } unless auth_header_error.nil?
|
30
30
|
raise ClientError, {:message => body["error"], :code =>0, :status => env[:status]}
|
31
31
|
end
|
32
|
-
SparkApi.logger.debug
|
32
|
+
SparkApi.logger.debug { "[oauth2] Session=#{session.inspect}" }
|
33
33
|
env[:body] = session
|
34
34
|
end
|
35
35
|
|
@@ -46,13 +46,13 @@ module SparkApi
|
|
46
46
|
|
47
47
|
def on_complete(env)
|
48
48
|
body = MultiJson.decode(env[:body])
|
49
|
-
SparkApi.logger.debug
|
49
|
+
SparkApi.logger.debug{ "[sparkbar] Response Body: #{body.inspect}" }
|
50
50
|
unless body.is_a?(Hash)
|
51
51
|
raise InvalidResponse, "The server response could not be understood"
|
52
52
|
end
|
53
53
|
case env[:status]
|
54
54
|
when 200..299
|
55
|
-
SparkApi.logger.debug
|
55
|
+
SparkApi.logger.debug{ "[sparkbar] Success!" }
|
56
56
|
if body.include?("token")
|
57
57
|
env[:body] = body
|
58
58
|
return
|
@@ -17,7 +17,7 @@ module SparkApi
|
|
17
17
|
else
|
18
18
|
raise ClientError, "Unsupported grant type [#{provider.grant_type}]"
|
19
19
|
end
|
20
|
-
SparkApi.logger.debug
|
20
|
+
SparkApi.logger.debug { "[oauth2] setup #{granter.class.name}" }
|
21
21
|
granter
|
22
22
|
end
|
23
23
|
|
@@ -38,16 +38,16 @@ module SparkApi
|
|
38
38
|
protected
|
39
39
|
|
40
40
|
def create_session(token_params)
|
41
|
-
SparkApi.logger.debug
|
41
|
+
SparkApi.logger.debug { "[oauth2] create_session to #{provider.access_uri} params #{token_params}" }
|
42
42
|
uri = URI.parse(provider.access_uri)
|
43
43
|
request_path = "#{uri.path}"
|
44
44
|
response = oauth_access_connection("#{uri.scheme}://#{uri.host}").post(request_path, "#{token_params}").body
|
45
45
|
response.expires_in = provider.session_timeout if response.expires_in.nil?
|
46
|
-
SparkApi.logger.debug
|
46
|
+
SparkApi.logger.debug { "[oauth2] New session created #{response}" }
|
47
47
|
response
|
48
48
|
rescue Faraday::Error::ConnectionFailed => e
|
49
49
|
if @client.ssl_verify && e.message =~ /certificate verify failed/
|
50
|
-
SparkApi.logger.error
|
50
|
+
SparkApi.logger.error { SparkApi::Errors.ssl_verification_error }
|
51
51
|
end
|
52
52
|
raise e
|
53
53
|
end
|
@@ -10,7 +10,7 @@ module SparkApi
|
|
10
10
|
end
|
11
11
|
def authenticate
|
12
12
|
if(provider.code.nil?)
|
13
|
-
SparkApi.logger.debug
|
13
|
+
SparkApi.logger.debug { "[oauth2] No authoriztion code present. Redirecting to #{authorization_url}." }
|
14
14
|
provider.redirect(authorization_url)
|
15
15
|
end
|
16
16
|
if needs_refreshing?
|
@@ -21,12 +21,12 @@ module SparkApi
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def refresh()
|
24
|
-
SparkApi.logger.debug
|
24
|
+
SparkApi.logger.debug { "[oauth2] Refresh oauth session." }
|
25
25
|
refresher = GrantTypeRefresh.new(client,provider,session)
|
26
26
|
refresher.params = {"redirect_uri" => @provider.redirect_uri}
|
27
27
|
refresher.authenticate
|
28
28
|
rescue ClientError => e
|
29
|
-
SparkApi.logger.info
|
29
|
+
SparkApi.logger.info { "[oauth2] Refreshing token failed, the library will try and authenticate from scratch: #{e.message}" }
|
30
30
|
nil
|
31
31
|
end
|
32
32
|
|
@@ -12,7 +12,7 @@ module SparkApi
|
|
12
12
|
def authenticate
|
13
13
|
new_session = nil
|
14
14
|
unless @session.refresh_token.nil?
|
15
|
-
SparkApi.logger.debug
|
15
|
+
SparkApi.logger.debug { "[oauth2] Refreshing authentication to #{provider.access_uri} using [#{session.refresh_token}]" }
|
16
16
|
new_session = create_session(token_params)
|
17
17
|
end
|
18
18
|
new_session
|
data/lib/spark_api/connection.rb
CHANGED
@@ -19,7 +19,7 @@ module SparkApi
|
|
19
19
|
env[:body] = decompress_body(env)
|
20
20
|
|
21
21
|
body = MultiJson.decode(env[:body])
|
22
|
-
SparkApi.logger.debug
|
22
|
+
SparkApi.logger.debug{ "Response Body: #{body.inspect}" }
|
23
23
|
unless body.is_a?(Hash) && body.key?("D")
|
24
24
|
raise InvalidResponse, "The server response could not be understood"
|
25
25
|
end
|
@@ -60,7 +60,7 @@ module SparkApi
|
|
60
60
|
when 500
|
61
61
|
raise ClientError, {:message => response.message, :code => response.code, :status => env[:status]}
|
62
62
|
when 200..299
|
63
|
-
SparkApi.logger.debug
|
63
|
+
SparkApi.logger.debug { "Success!" }
|
64
64
|
else
|
65
65
|
raise ClientError, {:message => response.message, :code => response.code, :status => env[:status]}
|
66
66
|
end
|
@@ -111,7 +111,6 @@ module SparkApi
|
|
111
111
|
Note.build_subclass.tap do |note|
|
112
112
|
note.prefix = "/listings/#{self.ListingKey}"
|
113
113
|
note.element_name = "/my/notes"
|
114
|
-
SparkApi.logger.info("Note.path: #{note.path}")
|
115
114
|
end
|
116
115
|
end
|
117
116
|
|
@@ -148,7 +147,6 @@ module SparkApi
|
|
148
147
|
return save!(arguments)
|
149
148
|
rescue BadResourceRequest => e
|
150
149
|
self.errors << {:code => e.code, :message => e.message}
|
151
|
-
SparkApi.logger.debug("BHDEBUG: #{e.inspect}")
|
152
150
|
if e.code == 1053
|
153
151
|
@constraints = []
|
154
152
|
e.details.each do |detail|
|
@@ -157,16 +155,16 @@ module SparkApi
|
|
157
155
|
end
|
158
156
|
end
|
159
157
|
end
|
160
|
-
SparkApi.logger.warn
|
158
|
+
SparkApi.logger.warn { "Failed to save resource #{self}: #{e.message}" }
|
161
159
|
rescue NotFound => e
|
162
|
-
SparkApi.logger.error
|
160
|
+
SparkApi.logger.error { "Failed to save resource #{self}: #{e.message}" }
|
163
161
|
end
|
164
162
|
false
|
165
163
|
end
|
166
164
|
def save!(arguments={})
|
167
165
|
writable_changed_keys = changed & WRITEABLE_FIELDS
|
168
166
|
if writable_changed_keys.empty?
|
169
|
-
SparkApi.logger.warn
|
167
|
+
SparkApi.logger.warn { "No supported listing change detected" }
|
170
168
|
else
|
171
169
|
results = connection.put "#{self.class.path}/#{self.Id}", build_hash(writable_changed_keys), arguments
|
172
170
|
@contstraints = []
|
@@ -183,9 +181,9 @@ module SparkApi
|
|
183
181
|
begin
|
184
182
|
return reorder_photos!(arguments)
|
185
183
|
rescue BadResourceRequest => e
|
186
|
-
SparkApi.logger.warn
|
184
|
+
SparkApi.logger.warn { "Failed to save resource #{self}: #{e.message}" }
|
187
185
|
rescue NotFound => e
|
188
|
-
SparkApi.logger.error
|
186
|
+
SparkApi.logger.error { "Failed to save resource #{self}: #{e.message}" }
|
189
187
|
end
|
190
188
|
false
|
191
189
|
end
|
@@ -209,7 +207,14 @@ module SparkApi
|
|
209
207
|
def ExpirationDate=(value)
|
210
208
|
write_attribute("ExpirationDate", value)
|
211
209
|
end
|
212
|
-
|
210
|
+
|
211
|
+
def respond_to?(method_symbol, include_all=false)
|
212
|
+
if super
|
213
|
+
true
|
214
|
+
else
|
215
|
+
attributes['StandardFields'].include?(method_symbol.to_s) rescue false
|
216
|
+
end
|
217
|
+
end
|
213
218
|
|
214
219
|
private
|
215
220
|
|
@@ -13,10 +13,10 @@ module SparkApi
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def ListingIds=(listing_ids)
|
16
|
-
|
16
|
+
write_attribute("ListingIds", Array(listing_ids))
|
17
17
|
end
|
18
18
|
def Name=(name)
|
19
|
-
|
19
|
+
write_attribute("Name", name)
|
20
20
|
end
|
21
21
|
|
22
22
|
def path
|
@@ -43,7 +43,7 @@ module SparkApi
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def activate_client_from_config(symbol)
|
46
|
-
SparkApi.logger.debug
|
46
|
+
SparkApi.logger.debug { "Loading multiclient [#{symbol.to_s}] from config" }
|
47
47
|
yaml = YamlConfig.build(symbol.to_s)
|
48
48
|
if(yaml.oauth2?)
|
49
49
|
Client.new(yaml.client_keys.merge({
|
data/lib/spark_api/request.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'json'
|
1
2
|
require 'cgi'
|
2
3
|
|
3
4
|
module SparkApi
|
@@ -70,27 +71,27 @@ module SparkApi
|
|
70
71
|
response = authenticator.request(method, request_path, nil, request_opts)
|
71
72
|
else
|
72
73
|
post_data = process_request_body(body)
|
73
|
-
SparkApi.logger.debug
|
74
|
+
SparkApi.logger.debug { "#{method.to_s.upcase} Data: #{post_data}" }
|
74
75
|
response = authenticator.request(method, request_path, post_data, request_opts)
|
75
76
|
end
|
76
77
|
request_time = Time.now - start_time
|
77
|
-
SparkApi.logger.debug
|
78
|
+
SparkApi.logger.debug { "[#{(request_time * 1000).to_i}ms] Api: #{method.to_s.upcase} #{request_path}" }
|
78
79
|
rescue PermissionDenied => e
|
79
80
|
if(ResponseCodes::SESSION_TOKEN_EXPIRED == e.code)
|
80
81
|
unless (attempts +=1) > 1
|
81
|
-
SparkApi.logger.debug
|
82
|
+
SparkApi.logger.debug { "Retrying authentication" }
|
82
83
|
authenticate
|
83
84
|
retry
|
84
85
|
end
|
85
86
|
end
|
86
87
|
# No luck authenticating... KABOOM!
|
87
|
-
SparkApi.logger.error
|
88
|
+
SparkApi.logger.error { "Authentication failed or server is sending us expired tokens, nothing we can do here." }
|
88
89
|
raise
|
89
90
|
end
|
90
91
|
response.body
|
91
92
|
rescue Faraday::Error::ConnectionFailed => e
|
92
93
|
if self.ssl_verify && e.message =~ /certificate verify failed/
|
93
|
-
SparkApi.logger.error
|
94
|
+
SparkApi.logger.error { SparkApi::Errors.ssl_verification_error }
|
94
95
|
end
|
95
96
|
raise e
|
96
97
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -43,14 +43,24 @@ describe ListingCart do
|
|
43
43
|
resource.ListingCount.should eq(10)
|
44
44
|
end
|
45
45
|
|
46
|
-
on_put_it "should save a listing cart" do
|
46
|
+
on_put_it "should save a listing cart Name" do
|
47
47
|
stub_api_get("/#{subject.class.element_name}", 'listing_carts/listing_cart.json')
|
48
48
|
resource = subject.class.get.first
|
49
|
-
stub_api_put("/#{subject.class.element_name}/#{resource.Id}", 'listing_carts/
|
49
|
+
stub_api_put("/#{subject.class.element_name}/#{resource.Id}", 'listing_carts/put_name.json', 'success.json')
|
50
50
|
resource.Name = "My Cart's Name"
|
51
|
+
resource.changed?.should be(true)
|
52
|
+
resource.save.should be(true)
|
53
|
+
resource.ResourceUri.should eq("/v1/listingcarts/20100912153422758914000000")
|
54
|
+
end
|
55
|
+
|
56
|
+
on_put_it "should save a listing cart ListingIds" do
|
57
|
+
stub_api_get("/#{subject.class.element_name}", 'listing_carts/listing_cart.json')
|
58
|
+
resource = subject.class.get.first
|
59
|
+
stub_api_put("/#{subject.class.element_name}/#{resource.Id}", 'listing_carts/put_ids.json', 'success.json')
|
51
60
|
resource.ListingIds = ['20110112234857732941000000',
|
52
61
|
'20110302120238448431000000',
|
53
62
|
'20110510011212354751000000']
|
63
|
+
resource.changed?.should be(true)
|
54
64
|
resource.save.should be(true)
|
55
65
|
resource.ResourceUri.should eq("/v1/listingcarts/20100912153422758914000000")
|
56
66
|
end
|
@@ -97,6 +97,28 @@ describe Listing do
|
|
97
97
|
it "should return full address" do
|
98
98
|
@listing.full_address.should eq("100 Someone's St, Fargo, ND 55320")
|
99
99
|
end
|
100
|
+
|
101
|
+
it "should provide shortcut methods to standard fields" do
|
102
|
+
@listing.StreetName.should eq("Someone's")
|
103
|
+
@listing.YearBuilt.should eq(nil)
|
104
|
+
@listing.BuildingAreaTotal.should eq("1321.0")
|
105
|
+
@listing.PublicRemarks.should eq(nil)
|
106
|
+
@listing.PostalCode.should eq("55320")
|
107
|
+
@listing.ListPrice.should eq("100000.0")
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should report that it responds to shortcut methods to standard fields" do
|
111
|
+
@listing.should respond_to(:StreetName)
|
112
|
+
@listing.should respond_to(:YearBuilt)
|
113
|
+
@listing.should respond_to(:BuildingAreaTotal)
|
114
|
+
@listing.should respond_to(:PublicRemarks)
|
115
|
+
@listing.should respond_to(:PostalCode)
|
116
|
+
@listing.should respond_to(:ListPrice)
|
117
|
+
|
118
|
+
@listing.should_not respond_to(:BogusField)
|
119
|
+
@listing.StandardFields['BogusField'] = 'bogus'
|
120
|
+
@listing.should respond_to(:BogusField)
|
121
|
+
end
|
100
122
|
end
|
101
123
|
|
102
124
|
describe "class methods" do
|