salsa_labs 0.0.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.
- 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
|
+
[](http://badge.fury.io/rb/salsa_labs)
|
5
|
+
[](https://travis-ci.org/fivetooldev/salsa_labs)
|
6
|
+
[](https://gemnasium.com/fivetooldev/salsa_labs)
|
7
|
+
[](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
|