spark_api 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/History.txt +14 -0
  2. data/README.md +42 -233
  3. data/VERSION +1 -1
  4. data/lib/spark_api.rb +1 -0
  5. data/lib/spark_api/authentication/oauth2.rb +39 -9
  6. data/lib/spark_api/authentication/oauth2_impl/cli_provider.rb +96 -0
  7. data/lib/spark_api/authentication/oauth2_impl/faraday_middleware.rb +28 -0
  8. data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +7 -2
  9. data/lib/spark_api/authentication/oauth2_impl/single_session_provider.rb +27 -0
  10. data/lib/spark_api/cli.rb +29 -10
  11. data/lib/spark_api/cli/api_auth.rb +1 -0
  12. data/lib/spark_api/cli/oauth2.rb +23 -8
  13. data/lib/spark_api/cli/setup.rb +31 -0
  14. data/lib/spark_api/configuration.rb +10 -2
  15. data/lib/spark_api/configuration/yaml.rb +6 -1
  16. data/lib/spark_api/connection.rb +1 -1
  17. data/lib/spark_api/errors.rb +48 -0
  18. data/lib/spark_api/models.rb +3 -0
  19. data/lib/spark_api/models/account.rb +9 -1
  20. data/lib/spark_api/models/base.rb +24 -19
  21. data/lib/spark_api/models/concerns.rb +7 -0
  22. data/lib/spark_api/models/concerns/destroyable.rb +32 -0
  23. data/lib/spark_api/models/concerns/savable.rb +66 -0
  24. data/lib/spark_api/models/contact.rb +6 -25
  25. data/lib/spark_api/models/dirty.rb +57 -0
  26. data/lib/spark_api/models/finders.rb +0 -4
  27. data/lib/spark_api/models/saved_search.rb +10 -0
  28. data/lib/spark_api/models/subresource.rb +5 -1
  29. data/lib/spark_api/models/subscription.rb +52 -0
  30. data/lib/spark_api/request.rb +17 -4
  31. data/lib/spark_api/response.rb +0 -37
  32. data/script/combined_flow_example.rb +3 -3
  33. data/script/oauth2_example.rb +3 -3
  34. data/spec/fixtures/base.json +3 -1
  35. data/spec/fixtures/contacts/new.json +2 -3
  36. data/spec/fixtures/contacts/new_empty.json +2 -3
  37. data/spec/fixtures/contacts/new_notify.json +1 -1
  38. data/spec/fixtures/{listings/saved_search.json → saved_searches/get.json} +1 -1
  39. data/spec/fixtures/saved_searches/new.json +8 -0
  40. data/spec/fixtures/saved_searches/post.json +12 -0
  41. data/spec/fixtures/saved_searches/update.json +6 -0
  42. data/spec/fixtures/subscriptions/get.json +19 -0
  43. data/spec/fixtures/subscriptions/new.json +13 -0
  44. data/spec/fixtures/subscriptions/post.json +10 -0
  45. data/spec/fixtures/subscriptions/put.json +12 -0
  46. data/spec/fixtures/subscriptions/subscribe.json +5 -0
  47. data/spec/fixtures/subscriptions/update.json +6 -0
  48. data/spec/mock_helper.rb +14 -6
  49. data/spec/oauth2_helper.rb +2 -0
  50. data/spec/spec_helper.rb +4 -7
  51. data/spec/unit/spark_api/authentication/api_auth_spec.rb +0 -1
  52. data/spec/unit/spark_api/authentication/oauth2_impl/faraday_middleware_spec.rb +32 -0
  53. data/spec/unit/spark_api/authentication/oauth2_impl/single_session_provider_spec.rb +9 -0
  54. data/spec/unit/spark_api/authentication/oauth2_spec.rb +29 -3
  55. data/spec/unit/spark_api/authentication_spec.rb +4 -10
  56. data/spec/unit/spark_api/configuration/yaml_spec.rb +4 -3
  57. data/spec/unit/spark_api/configuration_spec.rb +22 -8
  58. data/spec/unit/spark_api/models/account_spec.rb +5 -0
  59. data/spec/unit/spark_api/models/base_spec.rb +27 -0
  60. data/spec/unit/spark_api/models/concerns/destroyable_spec.rb +28 -0
  61. data/spec/unit/spark_api/models/concerns/savable_spec.rb +61 -0
  62. data/spec/unit/spark_api/models/contact_spec.rb +5 -5
  63. data/spec/unit/spark_api/models/dirty_spec.rb +46 -0
  64. data/spec/unit/spark_api/models/finders_spec.rb +0 -7
  65. data/spec/unit/spark_api/models/saved_search_spec.rb +34 -3
  66. data/spec/unit/spark_api/models/shared_listing_spec.rb +1 -1
  67. data/spec/unit/spark_api/models/subscription_spec.rb +106 -0
  68. data/spec/unit/spark_api/multi_client_spec.rb +14 -4
  69. data/spec/unit/spark_api/paginate_spec.rb +0 -1
  70. data/spec/unit/spark_api/request_spec.rb +10 -0
  71. data/spec/unit/spark_api_spec.rb +0 -3
  72. metadata +127 -45
  73. data/lib/spark_api/authentication/oauth2_impl/password_provider.rb +0 -24
@@ -15,8 +15,8 @@ SparkApi.configure do |config|
15
15
  config.api_secret = "YOUR_CLIENT_SECRET"
16
16
  config.callback = "YOUR_REDIRECT_URI"
17
17
  config.version = "v1"
18
- config.endpoint = "https://developers.sparkapi.com"
19
- config.auth_endpoint = "https://developers.sparkplatform.com/oauth2"
18
+ config.endpoint = "https://sparkapi.com"
19
+ config.auth_endpoint = "https://sparkplatform.com/oauth2"
20
20
  end
21
21
 
22
22
  client = SparkApi.client
@@ -25,7 +25,7 @@ client = SparkApi.client
25
25
  # Step 1:
26
26
  # To get your code to post to /v1/oauth2/grant, send the end user to this URI, replacing the all-capped strings with
27
27
  # the CGI-escaped credentials for your key:
28
- # https://developers.sparkplatform.com/oauth2?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI
28
+ # https://sparkplatform.com/oauth2?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI
29
29
  # When the user has finished, they will land at:
30
30
  # YOUR_REDIRECT_URI?code=CODE.
31
31
  puts "Go here and log in to get your code: #{client.authenticator.authorization_url}"
@@ -2,12 +2,14 @@
2
2
  "Success": true,
3
3
  "Results": [{
4
4
  "Id": 1,
5
+ "ResourceUri": "some/place/123",
5
6
  "Name": "My Example",
6
7
  "Test": true
7
8
  },
8
9
  {
9
10
  "Id": 2,
11
+ "ResourceUri": "some/place/123",
10
12
  "Name": "My Example2",
11
13
  "Test": false
12
14
  }]}
13
- }
15
+ }
@@ -5,7 +5,6 @@
5
5
  "DisplayName": "Contact Four",
6
6
  "PrimaryEmail": "contact4@fbsdata.com"
7
7
  }
8
- ],
9
- "Notify": false
8
+ ]
10
9
  }
11
- }
10
+ }
@@ -2,7 +2,6 @@
2
2
  "D": {
3
3
  "Contacts": [
4
4
  { }
5
- ],
6
- "Notify": false
5
+ ]
7
6
  }
8
- }
7
+ }
@@ -8,4 +8,4 @@
8
8
  ],
9
9
  "Notify": true
10
10
  }
11
- }
11
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "D": {
3
+ "SavedSearches": [
4
+ { "Name": "A new search name here" }
5
+ ]
6
+ }
7
+ }
8
+
@@ -0,0 +1,12 @@
1
+ {
2
+ "D": {
3
+ "Success": true,
4
+ "Results": [
5
+ {
6
+ "ResourceUri": "/v1/savedsearches/20100815220615294367000000",
7
+ "Id": "20100815220615294367000000",
8
+ "Name": "A new search name here"
9
+ }
10
+ ]
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "D": {
3
+ "Name": "A new search name here"
4
+ }
5
+ }
6
+
@@ -0,0 +1,19 @@
1
+ {
2
+ "D": {
3
+ "Success": true,
4
+ "Results": [
5
+ {
6
+ "Id":"20101230223226074204000000",
7
+ "ResourceUri":"/v1/contacts/20101230223226074204000000",
8
+ "Name":"First subscription",
9
+ "RecipientIds": ["20101230223226074307000000"]
10
+ },
11
+ {
12
+ "Id":"20101230223226074205000000",
13
+ "ResourceUri":"/v1/contacts/20101230223226074205000000",
14
+ "Name":"Second subscription",
15
+ "RecipientIds": []
16
+ }
17
+ ]
18
+ }
19
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "D": {
3
+ "Subscriptions": [
4
+ {
5
+ "Name":"A new subscription name",
6
+ "SearchId":"20101230223226074204000000",
7
+ "RecipientIds": ["20101230223226074204000000"],
8
+ "Subject": "my subject",
9
+ "Message": "my message"
10
+ }
11
+ ]
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "D": {
3
+ "Success": true,
4
+ "Results": [
5
+ {
6
+ "ResourceUri":"/v1/subscriptions/20101230223226074204000000"
7
+ }
8
+ ]
9
+ }
10
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "D": {
3
+ "Success": true,
4
+ "Results": [
5
+ {
6
+ "Id":"20101230223226074204000000",
7
+ "ResourceUri":"/v1/contacts/20101230223226074204000000",
8
+ "Name":"A new subscription name"
9
+ }
10
+ ]
11
+ }
12
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "D":{
3
+ "Success":true
4
+ }
5
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "D": {
3
+ "Name":"A new subscription name"
4
+ }
5
+ }
6
+
@@ -32,15 +32,19 @@ def stub_api_delete(service_path, stub_fixture="success.json", opts={})
32
32
  log_stub(s)
33
33
  end
34
34
  def stub_api_post(service_path, body, stub_fixture="success.json", opts={})
35
- body_hash = MultiJson.load(fixture(body).read)
36
- body_str = MultiJson.dump(body_hash)
35
+ if body.is_a?(Hash)
36
+ body = { :D => body } unless body.empty?
37
+ elsif !body.nil?
38
+ body = MultiJson.load(fixture(body).read)
39
+ end
40
+ body_str = body.nil? ? body : MultiJson.dump(body)
37
41
  params = {:ApiUser => "foobar", :AuthToken => "c401736bf3d3f754f07c04e460e09573"}.merge(opts)
38
42
  sig = $test_client.authenticator.sign_token("/#{SparkApi.version}#{service_path}", params, body_str)
39
43
  s=stub_request(:post, "#{SparkApi.endpoint}/#{SparkApi.version}#{service_path}").
40
44
  with(:query => {
41
45
  :ApiSig => sig
42
46
  }.merge(params),
43
- :body => body_str
47
+ :body => body
44
48
  )
45
49
  if(block_given?)
46
50
  yield s
@@ -50,15 +54,19 @@ def stub_api_post(service_path, body, stub_fixture="success.json", opts={})
50
54
  log_stub(s)
51
55
  end
52
56
  def stub_api_put(service_path, body, stub_fixture="success.json", opts={})
53
- body_hash = MultiJson.load(fixture(body).read)
54
- body_str = MultiJson.dump(body_hash)
57
+ if body.is_a? Hash
58
+ body = { :D => body }
59
+ elsif !body.nil?
60
+ body = MultiJson.load(fixture(body).read)
61
+ end
62
+ body_str = body.nil? ? body : MultiJson.dump(body)
55
63
  params = {:ApiUser => "foobar", :AuthToken => "c401736bf3d3f754f07c04e460e09573"}.merge(opts)
56
64
  sig = $test_client.authenticator.sign_token("/#{SparkApi.version}#{service_path}", params, body_str)
57
65
  s=stub_request(:put, "#{SparkApi.endpoint}/#{SparkApi.version}#{service_path}").
58
66
  with(:query => {
59
67
  :ApiSig => sig
60
68
  }.merge(params),
61
- :body => body_str
69
+ :body => body
62
70
  )
63
71
  if(block_given?)
64
72
  yield s
@@ -7,6 +7,7 @@ class TestOAuth2Provider < SparkApi::Authentication::BaseOAuth2Provider
7
7
  @redirect_uri = "https://exampleapp.fbsdata.com/oauth-callback"
8
8
  @client_id="example-id"
9
9
  @client_secret="example-password"
10
+ @sparkbar_uri = "https://test.sparkplatform.com/appbar/authorize"
10
11
  @session_cache = {}
11
12
  end
12
13
 
@@ -56,6 +57,7 @@ class TestCLIOAuth2Provider < SparkApi::Authentication::BaseOAuth2Provider
56
57
  nil
57
58
  end
58
59
  def session_timeout; 60; end
60
+
59
61
  end
60
62
 
61
63
 
@@ -31,15 +31,12 @@ end
31
31
 
32
32
  SparkApi.logger.info("Setup gem for rspec testing")
33
33
 
34
+ include SparkApi::Models
35
+
34
36
  def reset_config
35
37
  SparkApi.reset
36
- SparkApi.configure do |config|
37
- config.api_user = "foobar"
38
- end
38
+ SparkApi.configure { |c| c.api_user = "foobar" }
39
39
  end
40
- reset_config
41
-
42
- include SparkApi::Models
43
40
 
44
41
  RSpec.configure do |config|
45
42
  config.treat_symbols_as_metadata_keys_with_true_values = true
@@ -47,5 +44,5 @@ RSpec.configure do |config|
47
44
  config.alias_example_to :on_put_it, :method => 'PUT'
48
45
  config.alias_example_to :on_post_it, :method => 'POST'
49
46
  config.alias_example_to :on_delete_it, :method => 'DELETE'
47
+ config.before(:all) { reset_config }
50
48
  end
51
-
@@ -140,7 +140,6 @@ describe SparkApi::Authentication::ApiAuth do
140
140
 
141
141
  context "when the server says the session is expired (even if we disagree)" do
142
142
  it "should reset the session and reauthenticate" do
143
- reset_config
144
143
  count = 0
145
144
  # Make sure the auth request goes out twice.
146
145
  stub_request(:post, "https://api.sparkapi.com/#{SparkApi.version}/session").
@@ -0,0 +1,32 @@
1
+ require './spec/spec_helper'
2
+ require './spec/oauth2_helper'
3
+
4
+ describe SparkApi::Authentication::OAuth2Impl::SparkbarFaradayMiddleware do
5
+ subject { SparkApi::Authentication::OAuth2Impl::SparkbarFaradayMiddleware.new("test") }
6
+ # Make sure the client boostraps the right plugin based on configuration.
7
+ it "should parse token on successful response" do
8
+ env = {
9
+ :body => '{"token":"sp4rkb4rt0k3n"}',
10
+ :status => 201
11
+ }
12
+ subject.on_complete env
13
+ env[:body]["token"].should eq("sp4rkb4rt0k3n")
14
+ end
15
+
16
+ it "should raise error on unsuccessful response" do
17
+ env = {
18
+ :body => '{"token":"sp4rkb4rt0k3n"}',
19
+ :status => 500
20
+ }
21
+ expect {subject.on_complete env }.to raise_error(SparkApi::ClientError)
22
+ end
23
+
24
+ it "should raise error on invalid json" do
25
+ env = {
26
+ :body => '{"BORKBORKBORK"}',
27
+ :status => 200
28
+ }
29
+ expect {subject.on_complete env }.to raise_error(MultiJson::DecodeError)
30
+ end
31
+
32
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe SparkApi::Authentication::SingleSessionProvider do
4
+ subject { SparkApi::Authentication::SingleSessionProvider.new({ :access_token => "the_token" }) }
5
+ it "should initialize a new session with access_token" do
6
+ subject.load_session.should respond_to(:access_token)
7
+ subject.load_session.access_token.should eq("the_token")
8
+ end
9
+ end
@@ -2,8 +2,12 @@ require './spec/spec_helper'
2
2
  require './spec/oauth2_helper'
3
3
 
4
4
  describe SparkApi::Authentication::OAuth2 do
5
+ before(:all) { SparkApi.reset } # dump api user stuff from other tests
5
6
  let(:provider) { TestOAuth2Provider.new() }
6
- let(:client) { SparkApi::Client.new({:authentication_mode => SparkApi::Authentication::OAuth2,:oauth2_provider => provider}) }
7
+ let(:client) { SparkApi::Client.new({
8
+ :authentication_mode => SparkApi::Authentication::OAuth2,
9
+ :oauth2_provider => provider,
10
+ :sparkbar_uri => "https://test.sparkplatform.com/appbar/authorize"}) }
7
11
  subject {client.authenticator }
8
12
  # Make sure the client boostraps the right plugin based on configuration.
9
13
  describe "plugin" do
@@ -50,7 +54,6 @@ describe SparkApi::Authentication::OAuth2 do
50
54
  end
51
55
  end
52
56
 
53
-
54
57
  describe "logout" do
55
58
  let(:session) { mock_oauth_session }
56
59
  it "should logout when there is an active session" do
@@ -96,6 +99,24 @@ describe SparkApi::Authentication::OAuth2 do
96
99
  subject.request(:post, "/#{SparkApi.version}/contacts", contact, args).status.should eq(201)
97
100
  end
98
101
  end
102
+
103
+ describe "sparkbar_token" do
104
+ let(:session) { mock_oauth_session }
105
+ it "should fetch a sparkbar token" do
106
+ c = stub_request(:post, "https://test.sparkplatform.com/appbar/authorize").
107
+ with(:body => "access_token=#{session.access_token}").
108
+ to_return(:body => '{"token":"sp4rkb4rt0k3n"}')
109
+ subject.session = session
110
+ subject.sparkbar_token.should eq("sp4rkb4rt0k3n")
111
+ end
112
+ it "should raise an error on missing sparkbar token" do
113
+ c = stub_request(:post, "https://test.sparkplatform.com/appbar/authorize").
114
+ with(:body => "access_token=#{session.access_token}").
115
+ to_return(:body => '{"foo":"bar"}')
116
+ subject.session = session
117
+ expect {subject.sparkbar_token }.to raise_error(SparkApi::ClientError)
118
+ end
119
+ end
99
120
 
100
121
  context "with an expired session" do
101
122
  context "and a valid refresh token" do
@@ -246,7 +267,7 @@ describe "password authentication" do
246
267
  end
247
268
  describe SparkApi::Authentication::OAuth2Impl do
248
269
  it "should load a provider" do
249
- example = "SparkApi::Authentication::OAuth2Impl::PasswordProvider"
270
+ example = "SparkApi::Authentication::OAuth2Impl::CLIProvider"
250
271
  SparkApi::Authentication::OAuth2Impl.load_provider(example,{}).class.to_s.should eq(example)
251
272
  prefix = "::#{example}"
252
273
  SparkApi::Authentication::OAuth2Impl.load_provider(prefix,{}).class.to_s.should eq(example)
@@ -282,4 +303,9 @@ describe SparkApi::Authentication::OAuthSession do
282
303
  session.start_time.should eq(DateTime.parse(args[:start_time]))
283
304
  JSON.parse(session.to_json).should eq(JSON.parse(args.to_json))
284
305
  end
306
+
307
+ it "should not expire if expires_in is nil" do
308
+ session = SparkApi::Authentication::OAuthSession.new
309
+ session.expired?.should eq(false)
310
+ end
285
311
  end
@@ -1,19 +1,12 @@
1
1
  require './spec/spec_helper'
2
2
 
3
3
  describe SparkApi::Authentication do
4
- before(:all) do
5
- SparkApi.reset
6
- end
7
-
8
- after(:all) do
9
- reset_config
10
- end
11
-
12
4
  it "should give me a session object" do
13
5
  stub_auth_request
14
6
  stub_request(:get, "#{SparkApi.endpoint}/#{SparkApi.version}/session/c401736bf3d3f754f07c04e460e09573").
15
7
  with(:query => {
16
- :ApiSig => "5596eff4550d74ec6802ac2d637ae5ae",
8
+ :ApiSig => "d4cea51b4a6b9eb930e4320866aae7d0",
9
+ :ApiUser => "foobar",
17
10
  :AuthToken => "c401736bf3d3f754f07c04e460e09573"
18
11
  }).
19
12
  to_return(:body => fixture("session.json"))
@@ -26,7 +19,8 @@ describe SparkApi::Authentication do
26
19
  stub_auth_request
27
20
  stub_request(:delete, "#{SparkApi.endpoint}/#{SparkApi.version}/session/c401736bf3d3f754f07c04e460e09573").
28
21
  with(:query => {
29
- :ApiSig => "5596eff4550d74ec6802ac2d637ae5ae",
22
+ :ApiSig => "d4cea51b4a6b9eb930e4320866aae7d0",
23
+ :ApiUser => "foobar",
30
24
  :AuthToken => "c401736bf3d3f754f07c04e460e09573"
31
25
  }).
32
26
  to_return(:body => fixture("success.json"))
@@ -8,11 +8,12 @@ describe SparkApi::Configuration::YamlConfig, "Yaml Config" do
8
8
  subject.api_env.should eq("development")
9
9
  subject.load_file(api_file)
10
10
  subject.oauth2?.should eq(false)
11
+ subject.ssl_verify?.should eq(false)
11
12
  subject.api_key.should eq("demo_key")
12
13
  subject.api_secret.should eq("t3sts3cr3t")
13
14
  subject.endpoint.should eq("https://developers.sparkapi.com")
14
15
  subject.name.should eq("test_key")
15
- subject.client_keys.keys.should =~ [:api_key, :api_secret, :endpoint]
16
+ subject.client_keys.keys.should =~ [:api_key, :api_secret, :endpoint, :ssl_verify]
16
17
  subject.oauth2_keys.keys.should eq([])
17
18
  end
18
19
  it "should load a configured api key for production" do
@@ -47,7 +48,7 @@ describe SparkApi::Configuration::YamlConfig, "Yaml Config" do
47
48
  subject.oauth2_provider.should eq("SparkApi::TestOAuth2Provider")
48
49
  subject.name.should eq("test_oauth")
49
50
  subject.client_keys.keys.should =~ [:endpoint, :oauth2_provider]
50
- subject.oauth2_keys.keys.should =~ [:authorization_uri, :client_id, :access_uri, :client_secret, :redirect_uri]
51
+ subject.oauth2_keys.keys.should =~ [:authorization_uri, :client_id, :access_uri, :client_secret, :redirect_uri, :sparkbar_uri]
51
52
  end
52
53
  it "should load a configured api key for production" do
53
54
  subject.stub(:env){ {"SPARK_API_ENV" => "production"} }
@@ -66,7 +67,7 @@ describe SparkApi::Configuration::YamlConfig, "Yaml Config" do
66
67
 
67
68
  it "should list available keys" do
68
69
  SparkApi::Configuration::YamlConfig.stub(:config_path) { "spec/config/spark_api" }
69
- subject.class.config_keys.should =~ ["test_key", "test_oauth"]
70
+ subject.class.config_keys.should =~ ["test_key", "test_oauth", "test_single_session_oauth"]
70
71
  end
71
72
  end
72
73
  end