spark_api 1.3.16 → 1.3.17
Sign up to get free protection for your applications and to get access to all the features.
- 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
|