action_kit_api 0.1.11 → 0.2.1

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.
@@ -0,0 +1,9 @@
1
+ Feature: Establish a Connection
2
+ In order to use the ActionKitAPI
3
+ As a developer
4
+ I want to establish a connection
5
+
6
+ Scenario: Connection with valid credentials should success
7
+ When authenticating with valid credentials
8
+ Then I can get the remote API version
9
+
@@ -0,0 +1,13 @@
1
+ When /^authenticating with valid credentials$/ do
2
+ # These globals are set in the file features/support/credentials.rb you'll need
3
+ # to already have a valid API user with ActionKit to use these tests
4
+ ActionKitApi.connect(ACTIONKIT_USERNAME, ACTIONKIT_PASSWORD, ACTIONKIT_HOSTNAME)
5
+ end
6
+
7
+ Then /^I can get the remote API version$/ do
8
+ ActionKitApi.connection.version.should =~ /ActionKit \d\.\d\.\d+/
9
+ end
10
+
11
+ Given /^I have an active connection$/ do
12
+ ActionKitApi.connect(ACTIONKIT_USERNAME, ACTIONKIT_PASSWORD, ACTIONKIT_HOSTNAME)
13
+ end
@@ -1,25 +1,57 @@
1
- When /^I create a user with the email "([^"]*)", first name "([^"]*)", last name "([^"]*)", and zipcode "([^"]*)"$/ do |email, first_name, last_name, zip|
2
- attrs = {
3
- :email => email,
4
- :first_name => first_name,
5
- :last_name => last_name,
6
- :zip => :zip
7
- }
8
-
9
- @user = ActionKitApi::User.new(attrs)
1
+ Given /^I have found an existing user$/ do
2
+ @user = ActionKitApi::User.find_by_email('arealaddress@ipromise.com')
3
+ end
4
+
5
+ When /^I create a user with valid attributes$/ do
6
+ @user = ActionKitApi::User.new({
7
+ "email" => "arealaddress@ipromise.com",
8
+ "first_name" => "Real",
9
+ "last_name" => "Name",
10
+ "zip" => "00001"
11
+ })
12
+ end
13
+
14
+ When /^I save the user$/ do
10
15
  @user.save
11
16
  end
12
17
 
13
- When /^I search for user email "([^"]*)"$/ do |email|
14
- @user = ActionKitApi::User.find_by_email(email)
18
+ When /^I create a user missing an email address$/ do
19
+ @user = ActionKitApi::User.new({
20
+ "first_name" => "Real",
21
+ "last_name" => "Name",
22
+ "zip" => "00001"
23
+ })
24
+ end
25
+
26
+ When /^I change their zip code$/ do
27
+ @new_zip = @user.zip.reverse
28
+ @user.zip = @new_zip
29
+ end
30
+
31
+ When /^I search for a user that doesn't exist$/ do
32
+ @user = ActionKitApi::User.find_by_email('thisisnteven@arealtld.lorp')
15
33
  end
16
34
 
17
- When /^I search for user ID "([^"]*)"$/ do |id|
18
- @user = ActionKitApi::User.find_by_id(id)
35
+ When /^I search a user that has already been created$/ do
36
+ @user = ActionKitApi::User.find_by_email('arealaddress@ipromise.com')
19
37
  end
20
38
 
21
- Then /^I should have a valid user$/ do
39
+ Then /^I should receive a valid user$/ do
22
40
  @user.should be_valid
23
41
  end
24
42
 
43
+ Then /^I should get an error when I save$/ do
44
+ lambda{ @user.save }.should raise_error
45
+ end
46
+
47
+ Then /^the user should have an ActionKit ID$/ do
48
+ @user.akid.should_not be_nil
49
+ end
25
50
 
51
+ Then /^I should receive nil$/ do
52
+ @user.should be_nil
53
+ end
54
+
55
+ Then /^the user should have the new zip code$/ do
56
+ @user.zip.should eql(@new_zip)
57
+ end
@@ -0,0 +1,15 @@
1
+ Feature: Create a new user through the API
2
+ In order to track a person's actions
3
+ As a developer
4
+ I want to create a user for them
5
+
6
+ Scenario: Create a valid user
7
+ Given I have an active connection
8
+ When I create a user with valid attributes
9
+ And I save the user
10
+ Then the user should have an ActionKit ID
11
+
12
+ Scenario: Create an invalid user
13
+ Given I have an active connection
14
+ When I create a user missing an email address
15
+ Then I should get an error when I save
@@ -0,0 +1,14 @@
1
+ Feature: Find a user by email address
2
+ In order to act on people we already know about
3
+ As a developer
4
+ I should be able to find a user using their email address
5
+
6
+ Scenario: Find an existing user
7
+ Given I have an active connection
8
+ When I search a user that has already been created
9
+ Then I should receive a valid user
10
+
11
+ Scenario: Find a non-existant user
12
+ Given I have an active connection
13
+ When I search for a user that doesn't exist
14
+ Then I should receive nil
@@ -0,0 +1,11 @@
1
+ Feature: Update a user's information in ActionKit
2
+ In order to keep user's information up to date
3
+ As a developer
4
+ I should be able to make persistant changes to a user's instance
5
+
6
+ Scenario: Update a user's zip code
7
+ Given I have an active connection
8
+ And I have found an existing user
9
+ When I change their zip code
10
+ And I save the user
11
+ Then the user should have the new zip code
@@ -16,6 +16,8 @@ require "action_kit_api/page_types/unsubscribe"
16
16
  require "action_kit_api/page_types/import"
17
17
 
18
18
  module ActionKitApi
19
+ @@connection = nil
20
+
19
21
  # Takes a page object and a user object and a hash of any additional
20
22
  # attributes and records the action. Will return a Action object with
21
23
  # status information and unique identifiers
@@ -32,8 +34,18 @@ module ActionKitApi
32
34
  "akid" => user.akid,
33
35
  })
34
36
 
35
- response = ActionKitApi::Connection.call('act', act_attrs)
37
+ @@connection.call('act', act_attrs)
36
38
 
37
39
  ActionKitApi::Action.new(response)
38
40
  end
41
+
42
+ # Takes username, password, and hostname. This is simply a wrapper to
43
+ # ActionKitAPi::Connection.connect to make the gem a bit easier to use
44
+ def self.connect(username, password, hostname)
45
+ @@connection = ActionKitApi::Connection.new(username, password, hostname)
46
+ end
47
+
48
+ def self.connection
49
+ @@connection
50
+ end
39
51
  end
@@ -1,11 +1,11 @@
1
1
  require 'xmlrpc/client'
2
2
 
3
- module XMLRPC
4
- # This file adds the connection information for the ActionKit API
5
- # which is used throughout the rest of the Gem (a connection being
6
- # required for ... well every operation ... this is a remote API
7
- # gem :)
3
+ # This file adds the connection information for the ActionKit API
4
+ # which is used throughout the rest of the Gem (a connection being
5
+ # required for ... well every operation ... this is a remote API
6
+ # gem :)
8
7
 
8
+ module XMLRPC
9
9
  # This seems silly and dangerous right? Overwriting something in the ruby
10
10
  # standard libraries? Well ActionKit is doing XMLRPC wrong. This is almost
11
11
  # identical to the Ruby standard library version however it drops the type
@@ -36,22 +36,18 @@ module XMLRPC
36
36
  remove_const(:USER_AGENT)
37
37
  USER_AGENT = "DFA Ruby action_kit_api/#{ActionKitApi::VERSION} ( http://code.democracyforamerica.com/ )"
38
38
  end
39
- end
40
39
 
41
- module ActionKitApi
42
- class NoConnection < Exception
43
- # Nothing special, will be raised in the event something
44
- # trys to use a connection and one doesn't exist
40
+ # This was need to prevent empty responses from the remote
41
+ # server from triggering an exception on calls
42
+ module Config
43
+ remove_const(:ENABLE_NIL_PARSER)
44
+ ENABLE_NIL_PARSER = true
45
45
  end
46
+ end
46
47
 
48
+ module ActionKitApi
47
49
  class Connection
48
- # This was need to prevent empty responses from the remote
49
- # server from triggering an exception on calls
50
- XMLRPC::Config::ENABLE_NIL_PARSER = true
51
-
52
- @@connection = nil
53
-
54
- def self.connect(user, password, host)
50
+ def initialize(user, password, host)
55
51
  # Build the arguments for the XMLRPC::Client object
56
52
  conn_args = {
57
53
  :user => user,
@@ -61,29 +57,28 @@ module ActionKitApi
61
57
  :path => "/api"
62
58
  }
63
59
 
64
- @@connection = XMLRPC::Client.new_from_hash(conn_args)
60
+ @connection = XMLRPC::Client.new_from_hash(conn_args)
65
61
 
66
62
  # Unfortunately XMLRPC::Client does not expose it's SSL settings so
67
63
  # we need to dive into it's instance methods to set SSL verification
68
64
  # and add a CA to authenticate against
69
- @@connection.instance_variable_get("@http").verify_mode = OpenSSL::SSL::VERIFY_PEER
70
- @@connection.instance_variable_get("@http").ca_file = File.join(File.dirname(__FILE__), "actionkit_ca_chain.pem")
65
+ @connection.instance_variable_get("@http").verify_mode = OpenSSL::SSL::VERIFY_PEER
66
+ @connection.instance_variable_get("@http").ca_file = File.join(File.dirname(__FILE__), "actionkit_ca_chain.pem")
71
67
 
72
68
  return nil
73
69
  end
74
70
 
75
- def self.call(command, args)
76
- raise NoConnection if @@connection.nil?
77
-
71
+ def call(command, args)
78
72
  # XMLRPC::Client doesn't flush it's IO buffer which occasionally
79
73
  # causes a second command on the same connection to fail with an
80
74
  # EOFError. Using the _async version of this causes XMLRPC::Client
81
75
  # to use a new connection each time eliminating this issue
82
- @@connection.call_async(command, args)
76
+ @connection.call_async(command, args)
83
77
  end
84
78
 
85
- def self.version
86
- self.call("version")
79
+ def version
80
+ self.call("version", {})
87
81
  end
82
+
88
83
  end
89
84
  end
@@ -18,9 +18,12 @@ module ActionKitApi
18
18
 
19
19
  # TODO: Add blacklisting to the model to prevent read-only attributes from syncing
20
20
  # this is a temporary fix.
21
- hash = self.to_hash
22
- hash.delete("subscription_status")
23
- response = ActionKitApi::Connection.call("#{class_name}.save_or_create", hash)
21
+ attrs_hash = self.to_hash
22
+ attrs_hash.delete_if do |k, v|
23
+ k == :subscription_status
24
+ end
25
+
26
+ response = ActionKitApi.connection.call("#{class_name}.save_or_create", attrs_hash)
24
27
 
25
28
  # Update ourselves to include the data that the server populated
26
29
  self.update(response)
@@ -62,7 +65,7 @@ module ActionKitApi
62
65
 
63
66
  # XMLRPC::Client doesn't like empty values
64
67
  user_hash.delete_if do |k, v|
65
- v.to_s.empty?
68
+ v.to_s.empty? || v.nil?
66
69
  end
67
70
 
68
71
  user_hash
@@ -25,7 +25,7 @@ module ActionKitApi
25
25
  search = self.parse_attributes(attrs, args)
26
26
 
27
27
  begin
28
- response = ActionKitApi::Connection.call("#{class_name}.get", search)
28
+ response = ActionKitApi.connection.call("#{class_name}.get", search)
29
29
  rescue XMLRPC::FaultException => exception
30
30
  if exception.faultCode == "DoesNotExist"
31
31
  return nil
@@ -56,7 +56,7 @@ module ActionKitApi
56
56
  search["limit"] = 1000
57
57
  #search["offset"] = 0
58
58
 
59
- response = ActionKitApi::Connection.call("#{class_name}.get", search)
59
+ response = ActionKitApi.connection.call("#{class_name}.get", search)
60
60
 
61
61
  response_objects = []
62
62
  response.each do |obj|
@@ -67,7 +67,7 @@ module ActionKitApi
67
67
  end
68
68
 
69
69
  #def class_name.count(search)
70
- # ActionKitApi::Connection.call("#{class_name}.count", search)
70
+ # ActionKitApi.connection.call("#{class_name}.count", search)
71
71
  #end
72
72
 
73
73
  # Helper method for method_missing and the find_* virtual methods that
@@ -1,3 +1,3 @@
1
1
  module ActionKitApi
2
- VERSION = "0.1.11"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActionKitApi::Connection do
4
+
5
+ it "should raise an error when there is no connection" do
6
+ lambda { ActionKitApi.connection.version }.should raise_error
7
+ end
8
+
9
+ it "should use asynchronous calls on the remote API" do
10
+ pending
11
+ end
12
+
13
+ end
data/spec/spec_helper.rb CHANGED
@@ -3,8 +3,19 @@ require 'action_kit_api'
3
3
  require 'features/support/credentials'
4
4
 
5
5
  RSpec.configure do |config|
6
- config.filter_run_excluding :certificates => true, :remote => true
7
-
8
6
  config.color_enabled = true
9
7
  config.formatter = 'documentation'
10
8
  end
9
+
10
+ # This was taken from Rails master commit 1eecd94, it's so useful for testing and
11
+ # I was so sad to find it was not a part of the Ruby native Hash implementation
12
+ class Hash
13
+ def except(*keys)
14
+ dup.except!(*keys)
15
+ end
16
+
17
+ def except!(*keys)
18
+ keys.each { |key| delete(key) }
19
+ self
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ module AKAUserSpecHelper
4
+ def validUserAttributes
5
+ {
6
+ :email => "tuser@example.org",
7
+ :first_name => "Test",
8
+ :last_name => "User",
9
+ :zip => "00001"
10
+ }
11
+ end
12
+ end
13
+
14
+ describe ActionKitApi::User do
15
+ include AKAUserSpecHelper
16
+
17
+ before(:each) do
18
+ @user = ActionKitApi::User.new
19
+ end
20
+
21
+ it "should verify that an email is required" do
22
+ @user.update(validUserAttributes.except(:email))
23
+ @user.should_not be_valid
24
+ end
25
+
26
+ it "should verify that a zip is required" do
27
+ @user.update(validUserAttributes.except(:zip))
28
+ @user.should_not be_valid
29
+ end
30
+
31
+ it "should verify that first_name is required" do
32
+ @user.update(validUserAttributes.except(:first_name))
33
+ @user.should_not be_valid
34
+ end
35
+
36
+ it "should verify that last_name is required" do
37
+ @user.update(validUserAttributes.except(:last_name))
38
+ @user.should_not be_valid
39
+ end
40
+
41
+ it "should not allow arbitrary attributes to be added" do
42
+ @user.update({"fake_attr" => "with some data"})
43
+ user_hash = @user.to_hash
44
+
45
+ user_hash.should_not include("fake_attr")
46
+ end
47
+
48
+ it "should return it's attributes as a hash" do
49
+ @user.update(validUserAttributes)
50
+ user_hash = @user.to_hash
51
+
52
+ user_hash.should eql(validUserAttributes)
53
+ end
54
+
55
+ it "should not try to save subscription_status" do
56
+ pending
57
+ end
58
+
59
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 2
7
8
  - 1
8
- - 11
9
- version: 0.1.11
9
+ version: 0.2.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Sam Stelfox
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-02-27 00:00:00 -05:00
17
+ date: 2012-03-05 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -58,13 +58,13 @@ files:
58
58
  - README.md
59
59
  - Rakefile
60
60
  - action_kit_api.gemspec
61
- - features/create_a_user.feature
62
- - features/find_a_page.feature
63
- - features/find_a_user.feature
64
- - features/step_definitions/general_api_steps.rb
65
- - features/step_definitions/page_steps.rb
61
+ - features/connections/establish_a_connection.feature
62
+ - features/step_definitions/connection_steps.rb
66
63
  - features/step_definitions/user_steps.rb
67
64
  - features/support/env.rb
65
+ - features/users/create_a_user.feature
66
+ - features/users/find_a_user.feature
67
+ - features/users/update_a_user.feature
68
68
  - lib/action_kit_api.rb
69
69
  - lib/action_kit_api/action.rb
70
70
  - lib/action_kit_api/actionkit_ca_chain.pem
@@ -78,9 +78,10 @@ files:
78
78
  - lib/action_kit_api/searchable.rb
79
79
  - lib/action_kit_api/user.rb
80
80
  - lib/action_kit_api/version.rb
81
- - spec/connections/action_kit_api_connection_spec.rb
81
+ - spec/connection/connection_spec.rb
82
82
  - spec/remote_certificates_spec.rb
83
83
  - spec/spec_helper.rb
84
+ - spec/user/user_model_spec.rb
84
85
  has_rdoc: true
85
86
  homepage: http://code.democracyforamerica.com/
86
87
  licenses:
@@ -112,13 +113,14 @@ signing_key:
112
113
  specification_version: 3
113
114
  summary: Wrapper for the ActionKit API
114
115
  test_files:
115
- - features/create_a_user.feature
116
- - features/find_a_page.feature
117
- - features/find_a_user.feature
118
- - features/step_definitions/general_api_steps.rb
119
- - features/step_definitions/page_steps.rb
116
+ - features/connections/establish_a_connection.feature
117
+ - features/step_definitions/connection_steps.rb
120
118
  - features/step_definitions/user_steps.rb
121
119
  - features/support/env.rb
122
- - spec/connections/action_kit_api_connection_spec.rb
120
+ - features/users/create_a_user.feature
121
+ - features/users/find_a_user.feature
122
+ - features/users/update_a_user.feature
123
+ - spec/connection/connection_spec.rb
123
124
  - spec/remote_certificates_spec.rb
124
125
  - spec/spec_helper.rb
126
+ - spec/user/user_model_spec.rb
@@ -1,11 +0,0 @@
1
- Feature: Create a user
2
- In order to add a user to a mailing lists
3
- As a developer
4
- I should be able to create a user through the API
5
-
6
- Scenario: Create a user
7
- Given I have instantiated the API
8
- When I create a user with the email "tuser@example.org", first name "Test", last name "User", and zipcode "12345"
9
- And I search for user email "tuser@example.org"
10
- Then I should have a valid user
11
-
@@ -1,14 +0,0 @@
1
- Feature: Find a page
2
- In order to act on page
3
- As a developer
4
- I should be able to find a page
5
-
6
- Scenario: Find a page by name
7
- Given I have instantiated the API
8
- When I search for page name "jstreetdonation"
9
- Then I should have a valid page
10
-
11
- Scenario: Find a page by id
12
- Given I have instantiated the API
13
- When I search for page ID "1"
14
- Then I should have a valid page
@@ -1,15 +0,0 @@
1
- Feature: Find a user
2
- In order to update a user
3
- As a developer
4
- I should be able to find a user
5
-
6
- Scenario: Find a user by email
7
- Given I have instantiated the API
8
- When I search for user email "tuser@example.org"
9
- Then I should have a valid user
10
-
11
- Scenario: Find a user by ID
12
- Given I have instantiated the API
13
- When I search for user ID "39221"
14
- Then I should have a valid user
15
-
@@ -1,6 +0,0 @@
1
- Given /^I have instantiated the API$/ do
2
- # Uses information provided in credential file to setup the API's connection
3
- ActionKitApi::Connection.connect(ACTIONKIT_USERNAME,
4
- ACTIONKIT_PASSWORD, ACTIONKIT_HOSTNAME)
5
- end
6
-
@@ -1,11 +0,0 @@
1
- When /^I search for page name "([^"]*)"$/ do |name|
2
- @page = ActionKitApi::Page.find_by_name(name)
3
- end
4
-
5
- When /^I search for page ID "([^"]*)"$/ do |id|
6
- @page = ActionKitApi::Page.find_by_id(id)
7
- end
8
-
9
- Then /^I should have a valid page$/ do
10
- @page.should be_valid
11
- end
@@ -1,24 +0,0 @@
1
- require "spec_helper.rb"
2
-
3
- describe "ActionKitApi Connection" do
4
- it "should be able to create a new connection" do
5
- ActionKitApi::Connection.connect('testuser', 'testpass',
6
- 'host.example.local')
7
- end
8
-
9
- describe "Tests That Need a Connection", :remote => true do
10
- before(:all) do
11
- ActionKitApi::Connection.connect(ACTIONKIT_USERNAME,
12
- ACTIONKIT_PASSWORD, ACTIONKIT_HOSTNAME)
13
- end
14
-
15
- it "should be able to ask ActionKit for the version of it's API" do
16
- ActionKitApi::Connection.version.should =~ /ActionKit \d\.\d\.\d+/
17
- end
18
-
19
- it "should be able to make arbitrary calls to the remote API" do
20
- ActionKitApi::Connection.call("version").should =~ /ActionKit \d\.\d\.\d+/
21
- end
22
- end
23
- end
24
-