salsa_labs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +58 -0
- data/LICENSE +22 -0
- data/README.md +84 -0
- data/Rakefile +1 -0
- data/lib/salsa_labs/API_Client.rb +85 -0
- data/lib/salsa_labs/action.rb +35 -0
- data/lib/salsa_labs/actions_fetcher.rb +61 -0
- data/lib/salsa_labs/salsa_object.rb +19 -0
- data/lib/salsa_labs/version.rb +3 -0
- data/salsa_labs.gemspec +30 -0
- data/salsa_labs.rb +18 -0
- data/spec/fixtures/getObjects.sjs_action.xml +50 -0
- data/spec/salsa_labs/action_spec.rb +67 -0
- data/spec/salsa_labs/actions_fetcher_spec.rb +32 -0
- data/spec/salsa_labs/api_client_spec.rb +79 -0
- data/spec/salsa_labs/salsa_object_spec.rb +26 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/vcr_cassettes/successful_authentication.yml +45 -0
- data/spec/vcr_cassettes/unsuccessful_authentication.yml +45 -0
- metadata +200 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 789c61d06d857f8f1de240ce34828659bc89f63f
|
4
|
+
data.tar.gz: 51a6cf8d8845b2105ca3afaaa5dcab4bf37b8856
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f4b97d640ef36363b0a47054e2b0e05beab55f345300d59ac92983521531312f00154a117fcc4942cc1e38518319e57fa98826c3ddd8a756cf8734290dbcc30
|
7
|
+
data.tar.gz: ea1f1ea916fef505b78ee05d846109e7df28a76ce62e9a10685566dec3b2df4276402f295c2bf98191524027a4dc1ab4ec2d688abac9d0584200bf649cddcf77
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
salsa_labs (0.0.1)
|
5
|
+
faraday
|
6
|
+
httparty
|
7
|
+
nokogiri
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
addressable (2.3.5)
|
13
|
+
crack (0.4.1)
|
14
|
+
safe_yaml (~> 0.9.0)
|
15
|
+
diff-lcs (1.2.5)
|
16
|
+
docile (1.1.1)
|
17
|
+
fakeweb (1.3.0)
|
18
|
+
faraday (0.8.8)
|
19
|
+
multipart-post (~> 1.2.0)
|
20
|
+
httparty (0.12.0)
|
21
|
+
json (~> 1.8)
|
22
|
+
multi_xml (>= 0.5.2)
|
23
|
+
json (1.8.1)
|
24
|
+
mini_portile (0.5.2)
|
25
|
+
multi_json (1.8.2)
|
26
|
+
multi_xml (0.5.5)
|
27
|
+
multipart-post (1.2.0)
|
28
|
+
nokogiri (1.6.1)
|
29
|
+
mini_portile (~> 0.5.0)
|
30
|
+
rspec (2.14.1)
|
31
|
+
rspec-core (~> 2.14.0)
|
32
|
+
rspec-expectations (~> 2.14.0)
|
33
|
+
rspec-mocks (~> 2.14.0)
|
34
|
+
rspec-core (2.14.7)
|
35
|
+
rspec-expectations (2.14.4)
|
36
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
37
|
+
rspec-mocks (2.14.4)
|
38
|
+
safe_yaml (0.9.7)
|
39
|
+
simplecov (0.8.2)
|
40
|
+
docile (~> 1.1.0)
|
41
|
+
multi_json
|
42
|
+
simplecov-html (~> 0.8.0)
|
43
|
+
simplecov-html (0.8.0)
|
44
|
+
vcr (2.8.0)
|
45
|
+
webmock (1.16.1)
|
46
|
+
addressable (>= 2.2.7)
|
47
|
+
crack (>= 0.3.2)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
fakeweb
|
54
|
+
rspec
|
55
|
+
salsa_labs!
|
56
|
+
simplecov
|
57
|
+
vcr
|
58
|
+
webmock
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Velocity
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# SalsaLabs bindings for Ruby
|
2
|
+
|
3
|
+
[![Gem
|
4
|
+
Version](https://badge.fury.io/rb/salsa_labs.png)](http://badge.fury.io/rb/salsa_labs)
|
5
|
+
[![Build Status](https://travis-ci.org/fivetooldev/salsa_labs.png?branch=master)](https://travis-ci.org/fivetooldev/salsa_labs)
|
6
|
+
[![Dependency Status](https://gemnasium.com/fivetooldev/salsa_labs.png)](https://gemnasium.com/fivetooldev/salsa_labs)
|
7
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/fivetooldev/salsa_labs)
|
8
|
+
|
9
|
+
``salsa_labs`` can fetch data from the [Salsa Labs](http://salsalabs.com) API.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'salsa_labs'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install salsa_labs
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
By default, you can store your API credentials as the environment variables ``SALSA_LABS_API_EMAIL`` and ``SALSA_LABS_API_PASSWORD`` to avoid the need to re-enter your password multiple times. Otherwise you will need to pass your credentials into the ``SalsaLabs::ApiClient`` or appropriate fetching method as you call it.
|
28
|
+
|
29
|
+
``SalsaLabs::ApiClient`` is a general-purpose object for performing GET requests from the Salsa API.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# Create a client
|
33
|
+
client = SalsaLabs::ApiClient.new({email: 'barry@example.com', password: 'myPassword'})
|
34
|
+
|
35
|
+
# Perform arbitrary requests from Salsa API. If not already authenticated, client will do so automatically.
|
36
|
+
client.fetch('getObjects.sjs', {object: 'Supporter'})
|
37
|
+
# => Returns XML output of all supporters returned by API.
|
38
|
+
|
39
|
+
# Pass filter criteria to #fetch to retrieve a more focused result set.
|
40
|
+
# Filtering can be necessary if your result set exceeds allowed API limits.
|
41
|
+
# This query pulls all supporters with an address in Washington, D.C.
|
42
|
+
client.fetch('getObjects.sjs', {object: 'Supporter', State: 'DC'})
|
43
|
+
```
|
44
|
+
|
45
|
+
You can get a list of API calls and information about Salsa database objects here:
|
46
|
+
[https://help.salsalabs.com/entries/23537918-Getting-data-from-Salsa](https://help.salsalabs.com/entries/23537918-Getting-data-from-Salsa)
|
47
|
+
|
48
|
+
Currently specific functionality exists to work with Action campaigns, but more objects will be added later.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
# Fetch all actions from Salsa. First argument is filter criteria, second argument is credentials if you are not storing them as environment variables.
|
52
|
+
actions = SalsaLabs::Action.fetch({}, {})
|
53
|
+
# => Array of SalsaLabs::Action objects.
|
54
|
+
|
55
|
+
# Examine the Action.
|
56
|
+
actions.first.attributes
|
57
|
+
# => {'title' => 'My Action Title', 'organization_key' => '90210', action_key => '1234'}
|
58
|
+
```
|
59
|
+
|
60
|
+
``SalsaLabs::Action#attributes`` returns a hash corresponding to all the attributes returned by the API, so it should accommodate custom fields and/or new fields added later by SalsaLabs. All attribute names are downcased.
|
61
|
+
|
62
|
+
## Dependencies
|
63
|
+
|
64
|
+
Ruby 1.9 is required.
|
65
|
+
|
66
|
+
## Credits
|
67
|
+
|
68
|
+
The ``salsa_labs`` gem was created and is maintained by [Allison Sheren](http://github.com/asheren) and [Geoff Harcourt](http://github.com/geoffharcourt).
|
69
|
+
|
70
|
+
Development is generously sponsored by [Velocity](http://wearevelocity.com), in support of their work with progressive organizations.
|
71
|
+
|
72
|
+
## Contributing
|
73
|
+
|
74
|
+
1. Fork it
|
75
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
76
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
77
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
78
|
+
5. Create new Pull Request
|
79
|
+
|
80
|
+
## License
|
81
|
+
|
82
|
+
The ``salsa_labs`` gem is Copyright 2013-2014 Velocity. It is free software, and
|
83
|
+
may be redistributed under the terms of the MIT license, specified in the
|
84
|
+
LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module SalsaLabs
|
2
|
+
##
|
3
|
+
# Used to request information from Salsa Labs. Handles cookie-based
|
4
|
+
# authentication, and raises an exception when the API returns an error.
|
5
|
+
##
|
6
|
+
class ApiClient
|
7
|
+
|
8
|
+
attr_reader :authentication_cookie
|
9
|
+
|
10
|
+
def initialize(credentials = {})
|
11
|
+
@email = credentials[:email] || ENV['SALSA_LABS_API_EMAIL']
|
12
|
+
@password = credentials[:password] || ENV['SALSA_LABS_API_PASSWORD']
|
13
|
+
|
14
|
+
@authenticated = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def authenticate
|
18
|
+
return true if authenticated?
|
19
|
+
|
20
|
+
response = authenticate!
|
21
|
+
|
22
|
+
@authentication_cookie = response.env[:response_headers]["set-cookie"]
|
23
|
+
@authenticated = Nokogiri::XML(response.body).css('error').empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def authenticated?
|
27
|
+
@authenticated
|
28
|
+
end
|
29
|
+
|
30
|
+
def fetch(endpoint, params)
|
31
|
+
authenticate unless authenticated?
|
32
|
+
|
33
|
+
perform_get_request(endpoint, params).body
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :authenticated,
|
39
|
+
:email,
|
40
|
+
:password
|
41
|
+
|
42
|
+
def authenticate!
|
43
|
+
perform_get_request(
|
44
|
+
'/api/authenticate.sjs',
|
45
|
+
authentication_parameters
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def authentication_parameters
|
50
|
+
{email: email, password: password}
|
51
|
+
end
|
52
|
+
|
53
|
+
def connection
|
54
|
+
@connection ||= Faraday.
|
55
|
+
new(url: 'https://hq-salsa.wiredforchange.com') do |faraday|
|
56
|
+
|
57
|
+
faraday.use Faraday::Request::UrlEncoded
|
58
|
+
faraday.adapter Faraday.default_adapter
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def perform_get_request(endpoint, params)
|
63
|
+
response = connection.get do |request|
|
64
|
+
request.headers['cookie'] = authentication_cookie.to_s
|
65
|
+
request.url(endpoint, params)
|
66
|
+
end
|
67
|
+
|
68
|
+
raise_if_error!(response)
|
69
|
+
|
70
|
+
response
|
71
|
+
end
|
72
|
+
|
73
|
+
def raise_if_error!(response)
|
74
|
+
# Raise SalsaLabs::Error if response.body contains error (need to do this
|
75
|
+
# because API always gives 200 but then gives an error in the XML).
|
76
|
+
errors = Nokogiri::XML(response.body).css('error')
|
77
|
+
|
78
|
+
if errors.any?
|
79
|
+
raise SalsaLabs::Error.new(response),
|
80
|
+
"There is an error: #{errors.first.text}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SalsaLabs
|
2
|
+
##
|
3
|
+
# Action represents a single instance of an advocacy campaign ("Action") in
|
4
|
+
# the Salsa Labs / DemocracyInAction CRM.
|
5
|
+
##
|
6
|
+
class Action < SalsaObject
|
7
|
+
|
8
|
+
attr_reader :attributes
|
9
|
+
|
10
|
+
def initialize(attributes)
|
11
|
+
@attributes = attributes
|
12
|
+
end
|
13
|
+
|
14
|
+
def action_key
|
15
|
+
(attributes['action_key'] || 0).to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
def description
|
19
|
+
attributes['description']
|
20
|
+
end
|
21
|
+
|
22
|
+
def reference_name
|
23
|
+
attributes['reference_name']
|
24
|
+
end
|
25
|
+
|
26
|
+
def title
|
27
|
+
attributes['title']
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.fetch(credentials = {})
|
31
|
+
ActionsFetcher.new(credentials).fetch
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module SalsaLabs
|
2
|
+
##
|
3
|
+
# Service object to pull back a collection of actions from the Salsa Labs API.
|
4
|
+
##
|
5
|
+
class ActionsFetcher
|
6
|
+
|
7
|
+
def initialize(filter_parameters = {}, credentials = {})
|
8
|
+
@filter_parameters = filter_parameters
|
9
|
+
@client = SalsaLabs::ApiClient.new(credentials)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch
|
13
|
+
item_nodes.map do |node|
|
14
|
+
SalsaLabs::Action.new(SalsaLabsApiObjectNode.new(node).attributes)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :client, :filter_parameters
|
21
|
+
|
22
|
+
def api_call
|
23
|
+
client.fetch('/api/getObjects.sjs', api_parameters)
|
24
|
+
end
|
25
|
+
|
26
|
+
def api_parameters
|
27
|
+
filter_parameters.merge(object: 'Action')
|
28
|
+
end
|
29
|
+
|
30
|
+
def item_nodes
|
31
|
+
Nokogiri::XML(api_call).css('item')
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Object used to translate API's XML node into a hash of attributes for
|
36
|
+
# SalsaLabs::Action creation.
|
37
|
+
##
|
38
|
+
class SalsaLabsApiObjectNode
|
39
|
+
|
40
|
+
def initialize(xml_element)
|
41
|
+
@node = xml_element
|
42
|
+
end
|
43
|
+
|
44
|
+
def attributes
|
45
|
+
children.inject({}) do |memo, attribute|
|
46
|
+
memo[attribute.name.downcase] = attribute.text
|
47
|
+
attribute
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :node
|
54
|
+
|
55
|
+
def children
|
56
|
+
node.children
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SalsaLabs
|
2
|
+
##
|
3
|
+
# Base class used for subclasses that can be represented by Salsa Labs
|
4
|
+
# concepts that can be returned by getObject or getObjects.
|
5
|
+
##
|
6
|
+
class SalsaObject
|
7
|
+
|
8
|
+
attr_reader :attributes
|
9
|
+
|
10
|
+
def initialize(params)
|
11
|
+
@attributes = params
|
12
|
+
end
|
13
|
+
|
14
|
+
def organization_key
|
15
|
+
(attributes['organization_key'] || 0).to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/salsa_labs.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'salsa_labs/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "salsa_labs"
|
8
|
+
gem.version = SalsaLabs::VERSION
|
9
|
+
gem.authors = ['Geoff Harcourt', 'Allison Sheren']
|
10
|
+
gem.email = ['asheren@gmail.com']
|
11
|
+
gem.description = %q{A Ruby binding for the Salsa Labs (http://salsalabs.com) API.}
|
12
|
+
gem.summary = %q{Salsa Labs' API contains information about supporters, donations, and actions. This gem faciliates pulling that information into a Ruby application.}
|
13
|
+
gem.homepage = "http://github.com/geoffharcourt/ruby-salsa_labs"
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.test_files = gem.files.grep(%r{^(spec)/})
|
16
|
+
gem.require_paths = ['lib']
|
17
|
+
gem.licenses = ['LICENSE']
|
18
|
+
|
19
|
+
gem.add_runtime_dependency 'dotenv'
|
20
|
+
gem.add_runtime_dependency 'faraday'
|
21
|
+
gem.add_runtime_dependency 'httparty'
|
22
|
+
gem.add_runtime_dependency 'nokogiri'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'fakeweb'
|
25
|
+
gem.add_development_dependency 'rspec'
|
26
|
+
gem.add_development_dependency 'simplecov'
|
27
|
+
gem.add_development_dependency 'vcr'
|
28
|
+
gem.add_development_dependency 'webmock'
|
29
|
+
|
30
|
+
end
|
data/salsa_labs.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
require 'salsa_labs/version'
|
5
|
+
require 'salsa_labs/api_client'
|
6
|
+
require 'salsa_labs/salsa_object'
|
7
|
+
require 'salsa_labs/action'
|
8
|
+
require 'salsa_labs/actions_fetcher'
|
9
|
+
|
10
|
+
module SalsaLabs
|
11
|
+
|
12
|
+
##
|
13
|
+
# Exception class for API-related errors.
|
14
|
+
##
|
15
|
+
class Error < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<data organization_KEY="6120">
|
3
|
+
<Action>
|
4
|
+
<item>
|
5
|
+
<action_KEY>6656</action_KEY>
|
6
|
+
<organization_KEY>6120</organization_KEY>
|
7
|
+
<chapter_KEY/>
|
8
|
+
<Last_Modified>Tue Dec 17 2013 11:08:58 GMT-0500 (EST)</Last_Modified>
|
9
|
+
<Date_Created>Wed Sep 26 2012 14:30:02 GMT-0400 (EDT)</Date_Created>
|
10
|
+
<Reference_Name>My TItle</Reference_Name>
|
11
|
+
<Title>My Action Title</Title>
|
12
|
+
<Description><p>&#160;</p></Description>
|
13
|
+
<Allow_Comments_BOOLVALUE>false</Allow_Comments_BOOLVALUE>
|
14
|
+
<Allow_Comments>false</Allow_Comments>
|
15
|
+
<Comment_Question/>
|
16
|
+
<Max_Number_Of_Emails/>
|
17
|
+
<Max_Number_Of_Faxes/>
|
18
|
+
<Signatures/>
|
19
|
+
<Signature_Goal/>
|
20
|
+
<Deadline/>
|
21
|
+
<Signature_Minimum_for_Display/>
|
22
|
+
<Allow_Anonymous_BOOLVALUE>false</Allow_Anonymous_BOOLVALUE>
|
23
|
+
<Allow_Anonymous>false</Allow_Anonymous>
|
24
|
+
<Footer><p>&#160;</p></Footer>
|
25
|
+
<Request>First_Name,Last_Name,Street,Street_2,City,State,Zip,Email</Request>
|
26
|
+
<Required>First_Name,Last_Name,Street,City,State,Zip,Email</Required>
|
27
|
+
<Thank_You_Text/>
|
28
|
+
<redirect_path/>
|
29
|
+
<alternate_action_path/>
|
30
|
+
<email_trigger_KEYS/>
|
31
|
+
<add_to_groups_KEYS/>
|
32
|
+
<optionally_add_to_groups_KEYS/>
|
33
|
+
<Restriction_Type/>
|
34
|
+
<Restricted_Regions/>
|
35
|
+
<Restricted_Districts/>
|
36
|
+
<Restricted_Text/>
|
37
|
+
<No_Target_Text/>
|
38
|
+
<template_KEY/>
|
39
|
+
<Style>Targeted</Style>
|
40
|
+
<style_path/>
|
41
|
+
<Status/>
|
42
|
+
<linkRequest/>
|
43
|
+
<linkRequired/>
|
44
|
+
<key>6656</key>
|
45
|
+
<object>action</object>
|
46
|
+
</item>
|
47
|
+
<count>1</count>
|
48
|
+
</Action>
|
49
|
+
</data>
|
50
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SalsaLabs::Action do
|
4
|
+
|
5
|
+
let(:attributes) do
|
6
|
+
{
|
7
|
+
'action_key' => '1234',
|
8
|
+
'description' => 'Lengthy Description',
|
9
|
+
'organization_key' => '90210',
|
10
|
+
'reference_name' => 'A Good Reference',
|
11
|
+
'title' => 'A Distinguished Title'
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:action) { SalsaLabs::Action.new(attributes) }
|
16
|
+
|
17
|
+
describe "#action_key" do
|
18
|
+
it "returns the action_key attribute as an integer" do
|
19
|
+
expect(action.action_key).to eq(1234)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#attributes" do
|
24
|
+
it "returns the attributes hash passed in to initialize" do
|
25
|
+
expect(action.attributes).to eq(attributes)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#description" do
|
30
|
+
it "returns the description attribute" do
|
31
|
+
expect(action.description).to eq('Lengthy Description')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#organization_key" do
|
36
|
+
it "returns the organization_key attribute as an integer" do
|
37
|
+
expect(action.organization_key).to eq(90210)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#reference_name" do
|
42
|
+
it "returns the reference_name attribute" do
|
43
|
+
expect(action.reference_name).to eq('A Good Reference')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#title" do
|
48
|
+
it "returns the title as an attribute" do
|
49
|
+
expect(action.title).to eq('A Distinguished Title')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ".fetch" do
|
54
|
+
let(:actions_fetcher) { double('ActionsFetcher', fetch: []) }
|
55
|
+
|
56
|
+
before(:each) do
|
57
|
+
SalsaLabs::ActionsFetcher.stub(new: actions_fetcher)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "calls .fetch on an SalsaLabs::ActionsFetcher object" do
|
61
|
+
SalsaLabs::Action.fetch
|
62
|
+
|
63
|
+
expect(actions_fetcher).to have_received(:fetch)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SalsaLabs::ActionsFetcher do
|
4
|
+
|
5
|
+
let(:client) do
|
6
|
+
double(
|
7
|
+
'API client',
|
8
|
+
fetch: File.read('spec/fixtures/getObjects.sjs_action.xml')
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#fetch" do
|
13
|
+
before(:each) do
|
14
|
+
allow(SalsaLabs::ApiClient).to receive(:new) { client }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "calls the getObjects API endpoint" do
|
18
|
+
SalsaLabs::ActionsFetcher.new.fetch
|
19
|
+
|
20
|
+
expect(client).to have_received(:fetch).
|
21
|
+
with('/api/getObjects.sjs', {object: 'Action'})
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns an array of SalsaLabs::Action objects" do
|
25
|
+
results = SalsaLabs::ActionsFetcher.new.fetch
|
26
|
+
|
27
|
+
expect(results).to be_a(Array)
|
28
|
+
expect(results.first).to be_a(SalsaLabs::Action)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'vcr'
|
3
|
+
|
4
|
+
describe SalsaLabs::ApiClient do
|
5
|
+
|
6
|
+
let(:api_client) do
|
7
|
+
SalsaLabs::ApiClient.new({
|
8
|
+
email: 'allison@example.com', password: 'password'
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#authenticate" do
|
13
|
+
it "stores the cookie from Salsa Labs" do
|
14
|
+
VCR.use_cassette 'successful_authentication',
|
15
|
+
match_requests_on: [:path] do
|
16
|
+
|
17
|
+
api_client.authenticate
|
18
|
+
|
19
|
+
expect(api_client.authentication_cookie).to eq(
|
20
|
+
'JSESSIONID=67EBA60BFE7BCF73E2BA0B8E6F9592D0-n2; Path=/; Secure; '\
|
21
|
+
'HttpOnly, hqtab_2=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT, '\
|
22
|
+
'READONLY_Short_Name=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT, '\
|
23
|
+
'SRV=vweb213; path=/'
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with proper credentials" do
|
29
|
+
it "sets authenticated to be true" do
|
30
|
+
VCR.use_cassette 'successful_authentication',
|
31
|
+
match_requests_on: [:path] do
|
32
|
+
|
33
|
+
api_client.authenticate
|
34
|
+
|
35
|
+
expect(api_client.authenticated?).to be_true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with improper credentials" do
|
42
|
+
it "raises an exception" do
|
43
|
+
VCR.use_cassette 'unsuccessful_authentication',
|
44
|
+
match_requests_on: [:path] do
|
45
|
+
|
46
|
+
expect{
|
47
|
+
api_client.authenticate
|
48
|
+
}.to raise_error(SalsaLabs::Error)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#authenticated?" do
|
55
|
+
it "returns the value of the instance variable @authenticated" do
|
56
|
+
api_client.instance_variable_set(:@authenticated, 123)
|
57
|
+
|
58
|
+
expect(api_client.authenticated?).to eq(123)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#fetch" do
|
63
|
+
it "returns the body of the response from Salsa Labs for that API call" do
|
64
|
+
VCR.use_cassette 'get_objects/action',
|
65
|
+
match_requests_on: [:path] do
|
66
|
+
|
67
|
+
data = api_client.fetch('/api/getObjects.sjs', object: 'Action')
|
68
|
+
|
69
|
+
expect(data.gsub(/\n|\s{2,}/, "")).
|
70
|
+
to eq(salsa_get_objects_for_action_xml_response)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def salsa_get_objects_for_action_xml_response
|
76
|
+
File.read('spec/fixtures/getObjects.sjs_action.xml').gsub(/\n|\s{2,}/, '')
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SalsaLabs::SalsaObject do
|
4
|
+
|
5
|
+
let(:attributes) do
|
6
|
+
{
|
7
|
+
"description" => "A depiction of a description",
|
8
|
+
"organization_key" => "456"
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:salsa_object) { SalsaLabs::SalsaObject.new(attributes) }
|
13
|
+
|
14
|
+
describe "#attributes" do
|
15
|
+
it "returns the hash used to constuct the object" do
|
16
|
+
expect(salsa_object.attributes).to eq(attributes)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#organization_key" do
|
21
|
+
it "returns the organization_key attribute as an integer" do
|
22
|
+
expect(salsa_object.organization_key).to eq(456)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
require 'salsa_labs'
|
5
|
+
|
6
|
+
require 'rspec/autorun'
|
7
|
+
require 'vcr'
|
8
|
+
require 'webmock'
|
9
|
+
|
10
|
+
WebMock.disable_net_connect!
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
14
|
+
end
|
15
|
+
|
16
|
+
VCR.configure do |c|
|
17
|
+
c.cassette_library_dir = 'spec/vcr_cassettes'
|
18
|
+
c.hook_into :faraday
|
19
|
+
c.hook_into :webmock
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://hq-salsa.wiredforchange.com/api/authenticate.sjs?email=allison@example.com&password=password
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.8.8
|
12
|
+
cookie:
|
13
|
+
- ''
|
14
|
+
response:
|
15
|
+
status:
|
16
|
+
code: 200
|
17
|
+
message:
|
18
|
+
headers:
|
19
|
+
server:
|
20
|
+
- nginx/1.0.0
|
21
|
+
date:
|
22
|
+
- Sat, 28 Dec 2013 02:55:27 GMT
|
23
|
+
content-type:
|
24
|
+
- text/xml;charset=UTF-8
|
25
|
+
transfer-encoding:
|
26
|
+
- chunked
|
27
|
+
connection:
|
28
|
+
- keep-alive
|
29
|
+
keep-alive:
|
30
|
+
- timeout=20
|
31
|
+
set-cookie:
|
32
|
+
- JSESSIONID=67EBA60BFE7BCF73E2BA0B8E6F9592D0-n2; Path=/; Secure; HttpOnly,
|
33
|
+
hqtab_2=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT, READONLY_Short_Name="";
|
34
|
+
Expires=Thu, 01-Jan-1970 00:00:10 GMT, SRV=vweb213; path=/
|
35
|
+
requesturi:
|
36
|
+
- "/api/authenticate.sjs?email=allison@example.com&password=password"
|
37
|
+
cache-control:
|
38
|
+
- private
|
39
|
+
body:
|
40
|
+
encoding: UTF-8
|
41
|
+
string: "<?xml version=\"1.0\"?>\n\t\t\t<data organization_KEY=\"6120\">\n\t\t\t<message>Successful
|
42
|
+
Login</message>\n\t\t\t</data>"
|
43
|
+
http_version:
|
44
|
+
recorded_at: Sat, 28 Dec 2013 02:55:27 GMT
|
45
|
+
recorded_with: VCR 2.8.0
|
@@ -0,0 +1,45 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://hq-salsa.wiredforchange.com/api/authenticate.sjs?email=allison%40example.com&password=password
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.8.8
|
12
|
+
cookie:
|
13
|
+
- ''
|
14
|
+
response:
|
15
|
+
status:
|
16
|
+
code: 200
|
17
|
+
message:
|
18
|
+
headers:
|
19
|
+
server:
|
20
|
+
- nginx/1.0.0
|
21
|
+
date:
|
22
|
+
- Sat, 28 Dec 2013 02:56:00 GMT
|
23
|
+
content-type:
|
24
|
+
- text/xml;charset=UTF-8
|
25
|
+
transfer-encoding:
|
26
|
+
- chunked
|
27
|
+
connection:
|
28
|
+
- keep-alive
|
29
|
+
keep-alive:
|
30
|
+
- timeout=20
|
31
|
+
set-cookie:
|
32
|
+
- JSESSIONID=646F52AB13B1FCD5AA7B94A935B6E479-n3; Path=/; Secure; HttpOnly,
|
33
|
+
hqtab_2=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT, READONLY_Short_Name="";
|
34
|
+
Expires=Thu, 01-Jan-1970 00:00:10 GMT, SRV=vweb208; path=/
|
35
|
+
requesturi:
|
36
|
+
- "/api/authenticate.sjs?email=allison%40example.com&password=password"
|
37
|
+
cache-control:
|
38
|
+
- private
|
39
|
+
body:
|
40
|
+
encoding: UTF-8
|
41
|
+
string: "<?xml version=\"1.0\"?>\n\t\t\t<data>\n\t\t\t<error>Invalid login,
|
42
|
+
please try again.</error>\n\t\t\t</data>"
|
43
|
+
http_version:
|
44
|
+
recorded_at: Sat, 28 Dec 2013 02:56:00 GMT
|
45
|
+
recorded_with: VCR 2.8.0
|
metadata
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: salsa_labs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Geoff Harcourt
|
8
|
+
- Allison Sheren
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: dotenv
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: faraday
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: httparty
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: nokogiri
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: fakeweb
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rspec
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: simplecov
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: vcr
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: webmock
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
description: A Ruby binding for the Salsa Labs (http://salsalabs.com) API.
|
141
|
+
email:
|
142
|
+
- asheren@gmail.com
|
143
|
+
executables: []
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- Gemfile
|
148
|
+
- Gemfile.lock
|
149
|
+
- LICENSE
|
150
|
+
- README.md
|
151
|
+
- Rakefile
|
152
|
+
- lib/salsa_labs/API_Client.rb
|
153
|
+
- lib/salsa_labs/action.rb
|
154
|
+
- lib/salsa_labs/actions_fetcher.rb
|
155
|
+
- lib/salsa_labs/salsa_object.rb
|
156
|
+
- lib/salsa_labs/version.rb
|
157
|
+
- salsa_labs.gemspec
|
158
|
+
- salsa_labs.rb
|
159
|
+
- spec/fixtures/getObjects.sjs_action.xml
|
160
|
+
- spec/salsa_labs/action_spec.rb
|
161
|
+
- spec/salsa_labs/actions_fetcher_spec.rb
|
162
|
+
- spec/salsa_labs/api_client_spec.rb
|
163
|
+
- spec/salsa_labs/salsa_object_spec.rb
|
164
|
+
- spec/spec_helper.rb
|
165
|
+
- spec/vcr_cassettes/successful_authentication.yml
|
166
|
+
- spec/vcr_cassettes/unsuccessful_authentication.yml
|
167
|
+
homepage: http://github.com/geoffharcourt/ruby-salsa_labs
|
168
|
+
licenses:
|
169
|
+
- LICENSE
|
170
|
+
metadata: {}
|
171
|
+
post_install_message:
|
172
|
+
rdoc_options: []
|
173
|
+
require_paths:
|
174
|
+
- lib
|
175
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
requirements: []
|
186
|
+
rubyforge_project:
|
187
|
+
rubygems_version: 2.2.0
|
188
|
+
signing_key:
|
189
|
+
specification_version: 4
|
190
|
+
summary: Salsa Labs' API contains information about supporters, donations, and actions.
|
191
|
+
This gem faciliates pulling that information into a Ruby application.
|
192
|
+
test_files:
|
193
|
+
- spec/fixtures/getObjects.sjs_action.xml
|
194
|
+
- spec/salsa_labs/action_spec.rb
|
195
|
+
- spec/salsa_labs/actions_fetcher_spec.rb
|
196
|
+
- spec/salsa_labs/api_client_spec.rb
|
197
|
+
- spec/salsa_labs/salsa_object_spec.rb
|
198
|
+
- spec/spec_helper.rb
|
199
|
+
- spec/vcr_cassettes/successful_authentication.yml
|
200
|
+
- spec/vcr_cassettes/unsuccessful_authentication.yml
|