spark_api 1.1.2 → 1.2.0
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/History.txt +14 -0
- data/README.md +42 -233
- data/VERSION +1 -1
- data/lib/spark_api.rb +1 -0
- data/lib/spark_api/authentication/oauth2.rb +39 -9
- data/lib/spark_api/authentication/oauth2_impl/cli_provider.rb +96 -0
- data/lib/spark_api/authentication/oauth2_impl/faraday_middleware.rb +28 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +7 -2
- data/lib/spark_api/authentication/oauth2_impl/single_session_provider.rb +27 -0
- data/lib/spark_api/cli.rb +29 -10
- data/lib/spark_api/cli/api_auth.rb +1 -0
- data/lib/spark_api/cli/oauth2.rb +23 -8
- data/lib/spark_api/cli/setup.rb +31 -0
- data/lib/spark_api/configuration.rb +10 -2
- data/lib/spark_api/configuration/yaml.rb +6 -1
- data/lib/spark_api/connection.rb +1 -1
- data/lib/spark_api/errors.rb +48 -0
- data/lib/spark_api/models.rb +3 -0
- data/lib/spark_api/models/account.rb +9 -1
- data/lib/spark_api/models/base.rb +24 -19
- data/lib/spark_api/models/concerns.rb +7 -0
- data/lib/spark_api/models/concerns/destroyable.rb +32 -0
- data/lib/spark_api/models/concerns/savable.rb +66 -0
- data/lib/spark_api/models/contact.rb +6 -25
- data/lib/spark_api/models/dirty.rb +57 -0
- data/lib/spark_api/models/finders.rb +0 -4
- data/lib/spark_api/models/saved_search.rb +10 -0
- data/lib/spark_api/models/subresource.rb +5 -1
- data/lib/spark_api/models/subscription.rb +52 -0
- data/lib/spark_api/request.rb +17 -4
- data/lib/spark_api/response.rb +0 -37
- data/script/combined_flow_example.rb +3 -3
- data/script/oauth2_example.rb +3 -3
- data/spec/fixtures/base.json +3 -1
- data/spec/fixtures/contacts/new.json +2 -3
- data/spec/fixtures/contacts/new_empty.json +2 -3
- data/spec/fixtures/contacts/new_notify.json +1 -1
- data/spec/fixtures/{listings/saved_search.json → saved_searches/get.json} +1 -1
- data/spec/fixtures/saved_searches/new.json +8 -0
- data/spec/fixtures/saved_searches/post.json +12 -0
- data/spec/fixtures/saved_searches/update.json +6 -0
- data/spec/fixtures/subscriptions/get.json +19 -0
- data/spec/fixtures/subscriptions/new.json +13 -0
- data/spec/fixtures/subscriptions/post.json +10 -0
- data/spec/fixtures/subscriptions/put.json +12 -0
- data/spec/fixtures/subscriptions/subscribe.json +5 -0
- data/spec/fixtures/subscriptions/update.json +6 -0
- data/spec/mock_helper.rb +14 -6
- data/spec/oauth2_helper.rb +2 -0
- data/spec/spec_helper.rb +4 -7
- data/spec/unit/spark_api/authentication/api_auth_spec.rb +0 -1
- data/spec/unit/spark_api/authentication/oauth2_impl/faraday_middleware_spec.rb +32 -0
- data/spec/unit/spark_api/authentication/oauth2_impl/single_session_provider_spec.rb +9 -0
- data/spec/unit/spark_api/authentication/oauth2_spec.rb +29 -3
- data/spec/unit/spark_api/authentication_spec.rb +4 -10
- data/spec/unit/spark_api/configuration/yaml_spec.rb +4 -3
- data/spec/unit/spark_api/configuration_spec.rb +22 -8
- data/spec/unit/spark_api/models/account_spec.rb +5 -0
- data/spec/unit/spark_api/models/base_spec.rb +27 -0
- data/spec/unit/spark_api/models/concerns/destroyable_spec.rb +28 -0
- data/spec/unit/spark_api/models/concerns/savable_spec.rb +61 -0
- data/spec/unit/spark_api/models/contact_spec.rb +5 -5
- data/spec/unit/spark_api/models/dirty_spec.rb +46 -0
- data/spec/unit/spark_api/models/finders_spec.rb +0 -7
- data/spec/unit/spark_api/models/saved_search_spec.rb +34 -3
- data/spec/unit/spark_api/models/shared_listing_spec.rb +1 -1
- data/spec/unit/spark_api/models/subscription_spec.rb +106 -0
- data/spec/unit/spark_api/multi_client_spec.rb +14 -4
- data/spec/unit/spark_api/paginate_spec.rb +0 -1
- data/spec/unit/spark_api/request_spec.rb +10 -0
- data/spec/unit/spark_api_spec.rb +0 -3
- metadata +127 -45
- data/lib/spark_api/authentication/oauth2_impl/password_provider.rb +0 -24
@@ -35,6 +35,34 @@ module SparkApi
|
|
35
35
|
|
36
36
|
end
|
37
37
|
Faraday.register_middleware :response, :oauth2_impl => FaradayMiddleware
|
38
|
+
|
39
|
+
#==OAuth2 Faraday response middleware
|
40
|
+
# HTTP Response after filter to package oauth2 responses and bubble up basic api errors.
|
41
|
+
class SparkbarFaradayMiddleware < Faraday::Response::Middleware
|
42
|
+
|
43
|
+
def initialize(app)
|
44
|
+
super(app)
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_complete(env)
|
48
|
+
body = MultiJson.decode(env[:body])
|
49
|
+
SparkApi.logger.debug("[sparkbar] Response Body: #{body.inspect}")
|
50
|
+
unless body.is_a?(Hash)
|
51
|
+
raise InvalidResponse, "The server response could not be understood"
|
52
|
+
end
|
53
|
+
case env[:status]
|
54
|
+
when 200..299
|
55
|
+
SparkApi.logger.debug("[sparkbar] Success!")
|
56
|
+
if body.include?("token")
|
57
|
+
env[:body] = body
|
58
|
+
return
|
59
|
+
end
|
60
|
+
end
|
61
|
+
raise ClientError, {:message => "Unable to process sparkbar token #{body.inspect}", :code =>0, :status => env[:status]}
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
Faraday.register_middleware :response, :sparkbar_impl => SparkbarFaradayMiddleware
|
38
66
|
|
39
67
|
end
|
40
68
|
end
|
@@ -45,6 +45,11 @@ module SparkApi
|
|
45
45
|
response.expires_in = provider.session_timeout if response.expires_in.nil?
|
46
46
|
SparkApi.logger.debug("[oauth2] New session created #{response}")
|
47
47
|
response
|
48
|
+
rescue Faraday::Error::ConnectionFailed => e
|
49
|
+
if @client.ssl_verify && e.message =~ /certificate verify failed/
|
50
|
+
SparkApi.logger.error(SparkApi::Errors.ssl_verification_error)
|
51
|
+
end
|
52
|
+
raise e
|
48
53
|
end
|
49
54
|
|
50
55
|
def needs_refreshing?
|
@@ -66,9 +71,9 @@ module SparkApi
|
|
66
71
|
opts = {
|
67
72
|
:headers => @client.headers
|
68
73
|
}
|
69
|
-
|
74
|
+
|
75
|
+
opts[:ssl] = {:verify => false } unless @client.ssl_verify
|
70
76
|
opts[:url] = endpoint
|
71
|
-
Faraday.register_middleware :response, :faraday_middleware => FaradayMiddleware
|
72
77
|
conn = Faraday::Connection.new(opts) do |conn|
|
73
78
|
conn.response :oauth2_impl
|
74
79
|
conn.adapter Faraday.default_adapter
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SparkApi
|
2
|
+
module Authentication
|
3
|
+
|
4
|
+
class SingleSessionProvider < BaseOAuth2Provider
|
5
|
+
|
6
|
+
def initialize(credentials)
|
7
|
+
@access_token = credentials.delete(:access_token)
|
8
|
+
super(credentials)
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_session
|
12
|
+
@session ||= SparkApi::Authentication::OAuthSession.new({
|
13
|
+
:access_token => @access_token
|
14
|
+
})
|
15
|
+
end
|
16
|
+
|
17
|
+
def save_session session
|
18
|
+
@session = session
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy_session
|
22
|
+
@session = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/spark_api/cli.rb
CHANGED
@@ -14,9 +14,13 @@ module SparkApi
|
|
14
14
|
module CLI
|
15
15
|
class ConsoleCLI
|
16
16
|
OPTIONS_ENV = {
|
17
|
-
:endpoint
|
17
|
+
:endpoint => "API_ENDPOINT",
|
18
|
+
:no_verify => "NO_VERIFY",
|
18
19
|
# OAUTH2 Options
|
19
20
|
:access_uri => "ACCESS_URI",
|
21
|
+
:authorization_uri => "AUTHORIZATION_URI",
|
22
|
+
:redirect_uri => "REDIRECT_URI",
|
23
|
+
:code => "CODE",
|
20
24
|
:username=> "USERNAME",
|
21
25
|
:password=> "PASSWORD",
|
22
26
|
:client_id=> "CLIENT_ID",
|
@@ -53,6 +57,9 @@ module SparkApi
|
|
53
57
|
:endpoint => ENV[OPTIONS_ENV[:endpoint]],
|
54
58
|
# OAUTH2 Options
|
55
59
|
:access_uri => ENV[OPTIONS_ENV[:access_uri]],
|
60
|
+
:authorization_uri => ENV[OPTIONS_ENV[:authorization_uri]],
|
61
|
+
:redirect_uri => ENV[OPTIONS_ENV[:redirect_uri]],
|
62
|
+
:code => ENV[OPTIONS_ENV[:code]],
|
56
63
|
:username=> ENV[OPTIONS_ENV[:username]],
|
57
64
|
:password=> ENV[OPTIONS_ENV[:password]],
|
58
65
|
:client_id=> ENV[OPTIONS_ENV[:client_id]],
|
@@ -61,6 +68,7 @@ module SparkApi
|
|
61
68
|
:api_key => ENV[OPTIONS_ENV[:api_key]],
|
62
69
|
:api_secret => ENV[OPTIONS_ENV[:api_secret]],
|
63
70
|
:api_user => ENV[OPTIONS_ENV[:api_user]],
|
71
|
+
:no_verify => ENV.fetch(OPTIONS_ENV[:no_verify], false),
|
64
72
|
:console => ENV[OPTIONS_ENV[:console]]
|
65
73
|
}
|
66
74
|
cli_options = {}
|
@@ -77,15 +85,15 @@ module SparkApi
|
|
77
85
|
Options are:
|
78
86
|
BANNER
|
79
87
|
opts.separator ""
|
80
|
-
opts.on("-o","--oauth2",
|
81
|
-
"Run the API using OAuth2 credentials. The client defaults to using the Spark API authentication mode for access. ",
|
82
|
-
"See http://sparkplatform.com/docs/authentication/authentication for more information on authentication types.",
|
83
|
-
"Default: false") { |arg| cli_options[:oauth2] = arg }
|
84
88
|
opts.on("-e","--endpoint ENDPOINT",
|
85
89
|
"URI of the API.",
|
86
|
-
"Default: ENV['#{OPTIONS_ENV[:endpoint]}']") { |arg| cli_options[:endpoint] = arg }
|
90
|
+
"Default: ENV['#{OPTIONS_ENV[:endpoint]}'] or #{SparkApi::Configuration::DEFAULT_ENDPOINT}") { |arg| cli_options[:endpoint] = arg }
|
87
91
|
|
88
92
|
# OAUTH2
|
93
|
+
opts.on("-o","--oauth2",
|
94
|
+
"Run the API using OAuth2 credentials. The client defaults to using the Spark API authentication mode for access. ",
|
95
|
+
"See http://sparkplatform.com/docs/authentication/authentication for more information on authentication types.",
|
96
|
+
"Default: false") { |arg| cli_options[:oauth2] = arg }
|
89
97
|
opts.on("--client_id CLIENT_ID",
|
90
98
|
"OAuth2 client id",
|
91
99
|
"Default: ENV['#{OPTIONS_ENV[:client_id]}']") { |arg| cli_options[:client_id] = arg }
|
@@ -99,9 +107,17 @@ module SparkApi
|
|
99
107
|
"OAuth2 password",
|
100
108
|
"Default: ENV['#{OPTIONS_ENV[:password]}']") { |arg| cli_options[:password] = arg }
|
101
109
|
opts.on("--access_uri ACCESS_URI",
|
102
|
-
"OAuth2 path for granting access to the application",
|
103
|
-
"Default: ENV['#{OPTIONS_ENV[:access_uri]}']") { |arg| cli_options[:access_uri] = arg }
|
104
|
-
|
110
|
+
"OAuth2 path for granting access to the application using one of the supported grant types.",
|
111
|
+
"Default: ENV['#{OPTIONS_ENV[:access_uri]}'] or #{SparkApi::Configuration::DEFAULT_ACCESS_URI}") { |arg| cli_options[:access_uri] = arg }
|
112
|
+
opts.on("--redirect_uri REDIRECT_URI",
|
113
|
+
"OAuth2 application redirect for the client id. This needs to match whatever value is saved for the application's client_id",
|
114
|
+
"Default: ENV['#{OPTIONS_ENV[:redirect_uri]}'] or #{SparkApi::Configuration::DEFAULT_REDIRECT_URI}") { |arg| cli_options[:redirect_uri] = arg }
|
115
|
+
opts.on("--authorization_uri AUTHORIZATION_URI",
|
116
|
+
"OAuth2 authorization endpoint for a user. This is where the user should go to sign in and authorize client id.",
|
117
|
+
"Default: ENV['#{OPTIONS_ENV[:authorization_uri]}'] or #{SparkApi::Configuration::DEFAULT_AUTH_ENDPOINT}") { |arg| cli_options[:authorization_uri] = arg }
|
118
|
+
opts.on("--code CODE",
|
119
|
+
"OAuth2 authorization code used for granting application access to the API for a user") { |arg| cli_options[:code] = arg }
|
120
|
+
|
105
121
|
# API AUTH
|
106
122
|
opts.on("--api_key API_KEY",
|
107
123
|
"Authentication key for running the api using the default api authentication",
|
@@ -112,9 +128,12 @@ module SparkApi
|
|
112
128
|
opts.on("--api_user API_USER",
|
113
129
|
"ID of the Spark user to run the client as.",
|
114
130
|
"Default: ENV['#{OPTIONS_ENV[:api_user]}']") { |arg| cli_options[:api_user] = arg }
|
115
|
-
|
131
|
+
|
132
|
+
# General
|
116
133
|
opts.on("-f", "--file FILE",
|
117
134
|
"Load configuration for yaml file.") { |arg| file_options = parse_file_options(arg) }
|
135
|
+
opts.on("--no_verify",
|
136
|
+
"Disable SSL Certificate verification. This is useful for development servers.") { |arg| cli_options[:no_verify] = arg }
|
118
137
|
opts.on("-d", "--debug",
|
119
138
|
"Show detailed request logging information.") { |arg| cli_options[:debug] = arg }
|
120
139
|
opts.on("-v", "--version",
|
@@ -5,4 +5,5 @@ SparkApi.configure do |config|
|
|
5
5
|
config.api_secret = ENV["API_SECRET"]
|
6
6
|
config.api_user = ENV["API_USER"] if ENV["API_USER"]
|
7
7
|
config.endpoint = ENV["API_ENDPOINT"] if ENV["API_ENDPOINT"]
|
8
|
+
config.ssl_verify = ! (ENV["NO_VERIFY"].downcase=='true') if ENV["NO_VERIFY"]
|
8
9
|
end
|
data/lib/spark_api/cli/oauth2.rb
CHANGED
@@ -1,14 +1,29 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../cli/setup"
|
2
2
|
|
3
|
+
|
3
4
|
SparkApi.configure do |config|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
oauth = {
|
6
|
+
:authorization_uri=> ENV.fetch("AUTH_URI", SparkApi::Configuration::DEFAULT_AUTHORIZATION_URI),
|
7
|
+
:access_uri => ENV.fetch("ACCESS_URI", SparkApi::Configuration::DEFAULT_ACCESS_URI),
|
8
|
+
:redirect_uri => ENV.fetch("REDIRECT_URI", SparkApi::Configuration::DEFAULT_REDIRECT_URI),
|
9
|
+
:client_id=> ENV["CLIENT_ID"],
|
10
|
+
:client_secret=> ENV["CLIENT_SECRET"]
|
11
|
+
}
|
12
|
+
oauth[:username] = ENV["USERNAME"] if ENV.include?("USERNAME")
|
13
|
+
oauth[:password] = ENV["PASSWORD"] if ENV.include?("PASSWORD")
|
14
|
+
config.oauth2_provider = SparkApi::Authentication::OAuth2Impl::CLIProvider.new(oauth)
|
15
|
+
unless (oauth.include?(:username) && oauth.include?(:password))
|
16
|
+
config.oauth2_provider.grant_type = :authorization_code
|
17
|
+
config.oauth2_provider.code = ENV["CODE"] if ENV.include?("CODE")
|
18
|
+
end
|
12
19
|
config.authentication_mode = SparkApi::Authentication::OAuth2
|
13
20
|
config.endpoint = ENV["API_ENDPOINT"] if ENV["API_ENDPOINT"]
|
21
|
+
config.ssl_verify = ! (ENV["NO_VERIFY"].downcase=='true') if ENV["NO_VERIFY"]
|
14
22
|
end
|
23
|
+
|
24
|
+
# Enables saving and loading serialized oauth2 sessions for the system user.
|
25
|
+
def persist_sessions! my_alias = nil
|
26
|
+
warn "Warning: persistent session mode saves access tokens in clear text on the filesystem."
|
27
|
+
SparkApi.client.oauth2_provider.session_alias = my_alias unless my_alias.nil?
|
28
|
+
SparkApi.client.oauth2_provider.persistent_sessions = true
|
29
|
+
end
|
data/lib/spark_api/cli/setup.rb
CHANGED
@@ -45,3 +45,34 @@ include SparkApi::Models
|
|
45
45
|
def c
|
46
46
|
SparkApi.client
|
47
47
|
end
|
48
|
+
|
49
|
+
# Straight up HTTP functions y'all!!!
|
50
|
+
|
51
|
+
def get(path, options={})
|
52
|
+
c.get(path, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def post(path, body = nil, options={})
|
56
|
+
c.post(path, body, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def put(path, body = nil, options={})
|
60
|
+
c.put(path, body, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete(path, options={})
|
64
|
+
c.delete(path, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Handy session persistence
|
68
|
+
def save_oauth2_session! session_alias = "default"
|
69
|
+
|
70
|
+
rescue => e
|
71
|
+
puts "Unable to save the oauth2 session: #{e.message}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_oauth2_session session_alias = "default"
|
75
|
+
c.oauth2_provider.session = ""
|
76
|
+
rescue => e
|
77
|
+
puts "Unable to find a saved oauth2 session: #{e.message}"
|
78
|
+
end
|
@@ -5,13 +5,16 @@ module SparkApi
|
|
5
5
|
|
6
6
|
# valid configuration options
|
7
7
|
VALID_OPTION_KEYS = [:api_key, :api_secret, :api_user, :endpoint,
|
8
|
-
:user_agent, :version, :ssl, :oauth2_provider, :authentication_mode,
|
8
|
+
:user_agent, :version, :ssl, :ssl_verify, :oauth2_provider, :authentication_mode,
|
9
9
|
:auth_endpoint, :callback].freeze
|
10
10
|
OAUTH2_KEYS = [:authorization_uri, :access_uri, :client_id, :client_secret,
|
11
11
|
# Requirements for authorization_code grant type
|
12
12
|
:redirect_uri,
|
13
13
|
# Requirements for password grant type
|
14
|
-
:username, :password
|
14
|
+
:username, :password,
|
15
|
+
# Requirements for single session keys
|
16
|
+
:access_token,
|
17
|
+
:sparkbar_uri
|
15
18
|
]
|
16
19
|
|
17
20
|
require File.expand_path('../configuration/yaml', __FILE__)
|
@@ -23,10 +26,14 @@ module SparkApi
|
|
23
26
|
DEFAULT_API_SECRET = nil
|
24
27
|
DEFAULT_API_USER = nil
|
25
28
|
DEFAULT_ENDPOINT = 'https://api.sparkapi.com'
|
29
|
+
DEFAULT_REDIRECT_URI = "https://sparkplatform.com/oauth2/callback"
|
26
30
|
DEFAULT_AUTH_ENDPOINT = 'https://sparkplatform.com/openid' # Ignored for Spark API Auth
|
31
|
+
DEFAULT_AUTHORIZATION_URI = 'https://sparkplatform.com/oauth2'
|
27
32
|
DEFAULT_VERSION = 'v1'
|
33
|
+
DEFAULT_ACCESS_URI = "#{DEFAULT_ENDPOINT}/#{DEFAULT_VERSION}/oauth2/grant"
|
28
34
|
DEFAULT_USER_AGENT = "Spark API Ruby Gem #{VERSION}"
|
29
35
|
DEFAULT_SSL = true
|
36
|
+
DEFAULT_SSL_VERIFY = true
|
30
37
|
DEFAULT_OAUTH2 = nil
|
31
38
|
|
32
39
|
X_SPARK_API_USER_AGENT = "X-SparkApi-User-Agent"
|
@@ -57,6 +64,7 @@ module SparkApi
|
|
57
64
|
self.oauth2_provider = DEFAULT_OAUTH2
|
58
65
|
self.user_agent = DEFAULT_USER_AGENT
|
59
66
|
self.ssl = DEFAULT_SSL
|
67
|
+
self.ssl_verify = DEFAULT_SSL_VERIFY
|
60
68
|
self.version = DEFAULT_VERSION
|
61
69
|
self
|
62
70
|
end
|
@@ -5,7 +5,7 @@ module SparkApi
|
|
5
5
|
module Configuration
|
6
6
|
class YamlConfig
|
7
7
|
KEY_CONFIGURATIONS = VALID_OPTION_KEYS + [:oauth2] + OAUTH2_KEYS
|
8
|
-
DEFAULT_OAUTH2_PROVIDER = "SparkApi::Authentication::OAuth2Impl::
|
8
|
+
DEFAULT_OAUTH2_PROVIDER = "SparkApi::Authentication::OAuth2Impl::CLIProvider"
|
9
9
|
attr_accessor *KEY_CONFIGURATIONS
|
10
10
|
attr_reader :client_keys, :oauth2_keys, :provider
|
11
11
|
|
@@ -26,10 +26,15 @@ module SparkApi
|
|
26
26
|
def oauth2?
|
27
27
|
return oauth2 == true
|
28
28
|
end
|
29
|
+
|
30
|
+
def ssl_verify?
|
31
|
+
return ssl_verify == true
|
32
|
+
end
|
29
33
|
|
30
34
|
def name
|
31
35
|
@name
|
32
36
|
end
|
37
|
+
|
33
38
|
def api_env
|
34
39
|
if env.include? "SPARK_API_ENV"
|
35
40
|
env["SPARK_API_ENV"]
|
data/lib/spark_api/connection.rb
CHANGED
@@ -12,7 +12,7 @@ module SparkApi
|
|
12
12
|
:headers => headers
|
13
13
|
}
|
14
14
|
if(force_ssl || self.ssl)
|
15
|
-
opts[:ssl] = {:verify => false }
|
15
|
+
opts[:ssl] = {:verify => false } unless self.ssl_verify
|
16
16
|
opts[:url] = @endpoint.sub /^http:/, "https:"
|
17
17
|
else
|
18
18
|
opts[:url] = @endpoint.sub /^https:/, "http:"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SparkApi
|
2
|
+
|
3
|
+
# All known response codes listed in the API
|
4
|
+
module ResponseCodes
|
5
|
+
NOT_FOUND = 404
|
6
|
+
METHOD_NOT_ALLOWED = 405
|
7
|
+
INVALID_KEY = 1000
|
8
|
+
DISABLED_KEY = 1010
|
9
|
+
API_USER_REQUIRED = 1015
|
10
|
+
SESSION_TOKEN_EXPIRED = 1020
|
11
|
+
SSL_REQUIRED = 1030
|
12
|
+
INVALID_JSON = 1035
|
13
|
+
INVALID_FIELD = 1040
|
14
|
+
MISSING_PARAMETER = 1050
|
15
|
+
INVALID_PARAMETER = 1053
|
16
|
+
CONFLICTING_DATA = 1055
|
17
|
+
NOT_AVAILABLE= 1500
|
18
|
+
RATE_LIMIT_EXCEEDED = 1550
|
19
|
+
end
|
20
|
+
|
21
|
+
# Errors built from API responses
|
22
|
+
class InvalidResponse < StandardError; end
|
23
|
+
class ClientError < StandardError
|
24
|
+
attr_reader :code, :status, :details
|
25
|
+
def initialize (options = {})
|
26
|
+
# Support the standard initializer for errors
|
27
|
+
opts = options.is_a?(Hash) ? options : {:message => options.to_s}
|
28
|
+
@code = opts[:code]
|
29
|
+
@status = opts[:status]
|
30
|
+
@details = opts[:details]
|
31
|
+
super(opts[:message])
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
class NotFound < ClientError; end
|
36
|
+
class PermissionDenied < ClientError; end
|
37
|
+
class NotAllowed < ClientError; end
|
38
|
+
class BadResourceRequest < ClientError; end
|
39
|
+
|
40
|
+
# =Errors
|
41
|
+
# Error messages and other error handling
|
42
|
+
module Errors
|
43
|
+
def self.ssl_verification_error
|
44
|
+
"SSL verification problem: if connecting to a trusted but non production API endpoint, " +
|
45
|
+
"set 'ssl_verify' to false in the configuration or add '--no_verify' to the CLI command."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/spark_api/models.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'spark_api/models/dirty'
|
1
2
|
require 'spark_api/models/base'
|
2
3
|
require 'spark_api/models/constraint'
|
3
4
|
require 'spark_api/models/finders'
|
4
5
|
require 'spark_api/models/subresource'
|
6
|
+
require 'spark_api/models/concerns'
|
5
7
|
|
6
8
|
require 'spark_api/models/account'
|
7
9
|
require 'spark_api/models/connect_prefs'
|
@@ -26,6 +28,7 @@ require 'spark_api/models/tour_of_home'
|
|
26
28
|
require 'spark_api/models/video'
|
27
29
|
require 'spark_api/models/virtual_tour'
|
28
30
|
require 'spark_api/models/rental_calendar'
|
31
|
+
require 'spark_api/models/subscription'
|
29
32
|
|
30
33
|
module SparkApi
|
31
34
|
module Models
|
@@ -39,7 +39,15 @@ module SparkApi
|
|
39
39
|
def primary_img(typ)
|
40
40
|
if @images.is_a?(Array)
|
41
41
|
matches = @images.select {|i| i.Type == typ}
|
42
|
-
matches.sort
|
42
|
+
matches.sort do |a,b|
|
43
|
+
if a.Name.nil? && !b.Name.nil?
|
44
|
+
1
|
45
|
+
elsif b.Name.nil? && !a.Name.nil?
|
46
|
+
-1
|
47
|
+
else
|
48
|
+
a.Name.to_s <=> b.Name.to_s
|
49
|
+
end
|
50
|
+
end.first
|
43
51
|
else
|
44
52
|
nil
|
45
53
|
end
|
@@ -5,10 +5,10 @@ module SparkApi
|
|
5
5
|
# active model type niceties.
|
6
6
|
class Base
|
7
7
|
extend Paginate
|
8
|
+
include Dirty
|
8
9
|
|
9
10
|
attr_accessor :attributes, :errors
|
10
|
-
|
11
|
-
|
11
|
+
|
12
12
|
# Name of the resource as related to the path name
|
13
13
|
def self.element_name
|
14
14
|
# TODO I'd love to pull in active model at this point to provide default naming
|
@@ -18,7 +18,7 @@ module SparkApi
|
|
18
18
|
def self.element_name=(name)
|
19
19
|
@element_name = name
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
# Resource path prefix, prepended to the url
|
23
23
|
def self.prefix
|
24
24
|
@prefix ||= "/"
|
@@ -29,7 +29,7 @@ module SparkApi
|
|
29
29
|
def self.path
|
30
30
|
"#{prefix}#{element_name}"
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def self.connection
|
34
34
|
SparkApi.client
|
35
35
|
end
|
@@ -40,7 +40,6 @@ module SparkApi
|
|
40
40
|
def initialize(attributes={})
|
41
41
|
@attributes = {}
|
42
42
|
@errors = []
|
43
|
-
@changed = []
|
44
43
|
load(attributes)
|
45
44
|
end
|
46
45
|
|
@@ -49,7 +48,7 @@ module SparkApi
|
|
49
48
|
@attributes[key.to_s] = val
|
50
49
|
end
|
51
50
|
end
|
52
|
-
|
51
|
+
|
53
52
|
def self.get(options={})
|
54
53
|
collect(connection.get(path, options))
|
55
54
|
end
|
@@ -61,28 +60,28 @@ module SparkApi
|
|
61
60
|
def self.count(options={})
|
62
61
|
connection.get(path, options.merge({:_pagination=>"count"}))
|
63
62
|
end
|
64
|
-
|
63
|
+
|
65
64
|
def method_missing(method_symbol, *arguments)
|
66
65
|
method_name = method_symbol.to_s
|
67
66
|
|
68
|
-
if method_name =~ /(
|
67
|
+
if method_name =~ /(=|\?|_will_change!)$/
|
69
68
|
case $1
|
70
69
|
when "="
|
71
70
|
write_attribute($`, arguments.first)
|
72
71
|
# TODO figure out a nice way to present setters for the standard fields
|
73
72
|
when "?"
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
raise NoMethodError unless attributes.include?($`)
|
74
|
+
attributes[$`] ? true : false
|
75
|
+
when "_will_change!"
|
76
|
+
raise NoMethodError unless attributes.include?($`)
|
77
|
+
attribute_will_change!($`)
|
79
78
|
end
|
80
79
|
else
|
81
80
|
return attributes[method_name] if attributes.include?(method_name)
|
82
81
|
super # GTFO
|
83
82
|
end
|
84
83
|
end
|
85
|
-
|
84
|
+
|
86
85
|
def respond_to?(method_symbol, include_private=false)
|
87
86
|
if super
|
88
87
|
return true
|
@@ -93,26 +92,32 @@ module SparkApi
|
|
93
92
|
true
|
94
93
|
elsif method_name =~ /(\?)$/
|
95
94
|
attributes.include?($`)
|
95
|
+
elsif method_name =~ /(\w*)_will_change!$/
|
96
|
+
attributes.include?($1)
|
96
97
|
else
|
97
98
|
attributes.include?(method_name)
|
98
99
|
end
|
99
100
|
|
100
101
|
end
|
101
102
|
end
|
102
|
-
|
103
|
+
|
103
104
|
def parse_id(uri)
|
104
105
|
uri[/\/.*\/(.+)$/, 1]
|
105
106
|
end
|
106
|
-
|
107
|
+
|
108
|
+
def persisted?
|
109
|
+
!(@attributes['Id'].nil? && @attributes['ResourceUri'].nil?)
|
110
|
+
end
|
111
|
+
|
107
112
|
protected
|
108
|
-
|
113
|
+
|
109
114
|
def write_attribute(attribute, value)
|
110
115
|
unless attributes[attribute] == value
|
116
|
+
attribute_will_change!(attribute)
|
111
117
|
attributes[attribute] = value
|
112
|
-
@changed << attribute unless @changed.include?(attribute)
|
113
118
|
end
|
114
119
|
end
|
115
|
-
|
120
|
+
|
116
121
|
end
|
117
122
|
end
|
118
123
|
end
|