icontact-api 0.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +7 -0
- data/History.txt +1 -5
- data/{README.txt → README.rdoc} +3 -1
- data/Rakefile +13 -25
- data/VERSION +1 -0
- data/lib/icontact-api.rb +1 -1
- data/lib/icontact/api.rb +11 -9
- data/spec/api_spec.rb +52 -28
- metadata +61 -58
- data.tar.gz.sig +0 -0
- data/Manifest.txt +0 -13
- metadata.gz.sig +0 -0
data/Gemfile
ADDED
data/History.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
@@ -39,11 +39,13 @@ class BetaApi < Icontact::Api
|
|
39
39
|
API_USERNAME='username'
|
40
40
|
API_PASSWORD='password'
|
41
41
|
API_KEY = 'YOUR_API_KEY'
|
42
|
+
API_SECRET = 'YOUR_API_SECRET'
|
42
43
|
DOMAIN = "http://app.beta.icontact.com/icp"
|
43
44
|
|
44
45
|
def initialize(username = BetaApi::API_USERNAME, password = BetaApi::API_PASSWORD)
|
45
46
|
super(username, password)
|
46
|
-
self.
|
47
|
+
self.key = API_KEY
|
48
|
+
self.secret = API_SECRET
|
47
49
|
self.domain = DOMAIN
|
48
50
|
end
|
49
51
|
end
|
data/Rakefile
CHANGED
@@ -1,29 +1,17 @@
|
|
1
|
-
%w[rubygems rake rake/clean
|
1
|
+
%w[rubygems rake rake/clean].each { |f| require f }
|
2
2
|
require File.dirname(__FILE__) + '/lib/icontact-api'
|
3
|
-
require 'hoe'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
]
|
18
|
-
|
19
|
-
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
20
|
-
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
21
|
-
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
22
|
-
p.rsync_args = '-av --delete --ignore-errors'
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "icontact-api"
|
8
|
+
gem.summary = %Q{A thin wrapper around the iContact API}
|
9
|
+
gem.authors = ["Kevin Olbrich"]
|
10
|
+
gem.email = ["kevin.olbrich+icontact-api@gmail.com"]
|
11
|
+
gem.homepage = "http://github.com/olbrich/IContact-API"
|
12
|
+
end
|
13
|
+
Jeweler::GemcutterTasks.new
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
16
|
end
|
24
17
|
|
25
|
-
require 'newgem/tasks' # load /tasks/*.rake
|
26
|
-
Dir['tasks/**/*.rake'].each { |t| load t }
|
27
|
-
|
28
|
-
# TODO - want other tests/tasks run by default? Add them to the list
|
29
|
-
# task :default => [:spec, :features]
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/lib/icontact-api.rb
CHANGED
data/lib/icontact/api.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'net/http'
|
3
2
|
require 'net/https'
|
4
3
|
require 'json'
|
5
4
|
|
6
5
|
class Icontact
|
7
6
|
class Api
|
8
|
-
VERSION = "0.
|
9
|
-
API_VERSION = "2.
|
10
|
-
|
7
|
+
VERSION = "0.3"
|
8
|
+
API_VERSION = "2.2"
|
9
|
+
URL = 'https://app.icontact.com/icp'
|
11
10
|
API_KEY = "API_KEY"
|
12
11
|
attr_accessor :username
|
13
12
|
attr_accessor :password
|
14
13
|
attr_accessor :app_id
|
15
|
-
attr_accessor :
|
14
|
+
attr_accessor :url
|
15
|
+
attr_accessor :api_version
|
16
16
|
|
17
|
-
def initialize(username, password)
|
17
|
+
def initialize(username=nil, password=nil)
|
18
18
|
self.username = username
|
19
19
|
self.password = password
|
20
|
-
self.
|
20
|
+
self.url = URL
|
21
21
|
self.app_id = API_KEY
|
22
|
+
self.api_version = API_VERSION
|
22
23
|
end
|
23
24
|
|
24
25
|
# Package up any options into a query string and format it properly for the server
|
@@ -54,7 +55,7 @@ class Icontact
|
|
54
55
|
# data exchange. Also accepts text/xml for either, but then you have to deal with XML encoding and decoding
|
55
56
|
# manually
|
56
57
|
def apply_headers(req)
|
57
|
-
req.add_field('API-Version',
|
58
|
+
req.add_field('API-Version', self.api_version)
|
58
59
|
req.add_field('accept','application/json')
|
59
60
|
req.add_field('Content-Type','application/json')
|
60
61
|
req.add_field('API-Appid', self.app_id)
|
@@ -82,7 +83,7 @@ class Icontact
|
|
82
83
|
# options passed as optional parameter show up as an array
|
83
84
|
options = options.first if options.kind_of? Array
|
84
85
|
query_options = self.class.package_query_params(options)
|
85
|
-
full_url = URI.parse("#{self.
|
86
|
+
full_url = URI.parse("#{self.url}#{url}#{query_options}")
|
86
87
|
|
87
88
|
# create an object of the class required to process this method
|
88
89
|
klass = Object.module_eval("::Net::HTTP::#{kind.to_s.capitalize}", __FILE__, __LINE__)
|
@@ -93,6 +94,7 @@ class Icontact
|
|
93
94
|
|
94
95
|
http = Net::HTTP.new(full_url.host, full_url.port)
|
95
96
|
http.use_ssl = true
|
97
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
96
98
|
response = http.start do |web|
|
97
99
|
web.request(request)
|
98
100
|
end
|
data/spec/api_spec.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
3
|
describe Icontact::Api do
|
4
|
+
before(:each) do
|
5
|
+
@mock_time = mock('Time', :getgm => 999999)
|
6
|
+
Time.stub!(:now).and_return(@mock_time)
|
7
|
+
Kernel.stub!(:rand).and_return(111)
|
8
|
+
end
|
9
|
+
|
4
10
|
describe "api" do
|
5
11
|
before(:each) do
|
6
12
|
@api = Icontact::Api.new('mock_username', 'mock_password')
|
7
13
|
@response = mock('response',:code=>200, :body=>"body")
|
8
|
-
|
9
|
-
|
10
|
-
Net::HTTP.stub!(:new).and_return(@mock_http_session)
|
14
|
+
@mock_http_request = mock('http', :request=>@response)
|
15
|
+
Net::HTTP.stub!(:start).and_yield(@mock_http_request)
|
11
16
|
end
|
12
17
|
|
13
|
-
describe "an
|
18
|
+
describe "an http request", :shared=>true do
|
14
19
|
it "should apply headers to the request" do
|
15
20
|
@mock_request = mock("Request", :body= => true)
|
16
21
|
@api.should_receive(:apply_headers).and_return(@mock_request)
|
@@ -22,13 +27,8 @@ describe Icontact::Api do
|
|
22
27
|
do_request(:limit=>10)
|
23
28
|
end
|
24
29
|
|
25
|
-
it "should use ssl" do
|
26
|
-
@mock_http_session.should_receive(:use_ssl=).with(true)
|
27
|
-
do_request
|
28
|
-
end
|
29
|
-
|
30
30
|
it "should send the request" do
|
31
|
-
|
31
|
+
Net::HTTP.should_receive(:start)
|
32
32
|
do_request
|
33
33
|
end
|
34
34
|
|
@@ -38,8 +38,8 @@ describe Icontact::Api do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
describe "an
|
42
|
-
it_should_behave_like "an
|
41
|
+
describe "an http request with a body", :shared=>true do
|
42
|
+
it_should_behave_like "an http request"
|
43
43
|
|
44
44
|
it "should package the data into the body" do
|
45
45
|
@api.class.should_receive(:body_encoder)
|
@@ -53,7 +53,7 @@ describe Icontact::Api do
|
|
53
53
|
@api.get("/a", options)
|
54
54
|
end
|
55
55
|
|
56
|
-
it_should_behave_like "an
|
56
|
+
it_should_behave_like "an http request"
|
57
57
|
end
|
58
58
|
|
59
59
|
describe ".post" do
|
@@ -61,7 +61,7 @@ describe Icontact::Api do
|
|
61
61
|
@api.post("/a", {}, options)
|
62
62
|
end
|
63
63
|
|
64
|
-
it_should_behave_like "an
|
64
|
+
it_should_behave_like "an http request with a body"
|
65
65
|
end
|
66
66
|
|
67
67
|
describe ".put" do
|
@@ -69,7 +69,7 @@ describe Icontact::Api do
|
|
69
69
|
@api.put("/a", {}, options)
|
70
70
|
end
|
71
71
|
|
72
|
-
it_should_behave_like "an
|
72
|
+
it_should_behave_like "an http request with a body"
|
73
73
|
end
|
74
74
|
|
75
75
|
describe '.delete' do
|
@@ -77,10 +77,25 @@ describe Icontact::Api do
|
|
77
77
|
@api.delete("/a", options)
|
78
78
|
end
|
79
79
|
|
80
|
-
it_should_behave_like "an
|
80
|
+
it_should_behave_like "an http request"
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
describe ".request_signature" do
|
85
|
+
before(:each) do
|
86
|
+
@api = Icontact::Api.new('username','password')
|
87
|
+
Kernel.stub!(:rand).and_return(111)
|
88
|
+
@mock_time = mock('Time', :getgm => 999999)
|
89
|
+
Time.stub!(:now).and_return(@mock_time)
|
90
|
+
Digest::SHA1.stub!(:hexdigest).and_return('api_signature')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should generate an API Signature" do
|
94
|
+
Digest::SHA1.should_receive(:hexdigest).with('API_SECRETpasswordtimestamp/urlrandomGET').and_return('api_signature')
|
95
|
+
@api.request_signature('get','timestamp''/url', 'random', '').should == "api_signature"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
84
99
|
describe ".apply_headers" do
|
85
100
|
before(:each) do
|
86
101
|
@request = mock('Request', :add_field=>true)
|
@@ -88,16 +103,16 @@ describe Icontact::Api do
|
|
88
103
|
end
|
89
104
|
|
90
105
|
def do_apply_headers
|
91
|
-
@api.apply_headers(@request)
|
106
|
+
@api.apply_headers(:get, @request, 'http://fakeurl.com')
|
92
107
|
end
|
93
108
|
|
94
|
-
it "should add an
|
95
|
-
@request.should_receive(:add_field).with('
|
109
|
+
it "should add an API_VERSION header to indicate we are using the 2.0 version of the API" do
|
110
|
+
@request.should_receive(:add_field).with('API_VERSION', @api.class::API_VERSION)
|
96
111
|
do_apply_headers
|
97
112
|
end
|
98
113
|
|
99
114
|
it "should add an ACCEPT header indicating we want a JSON object back" do
|
100
|
-
@request.should_receive(:add_field).with('
|
115
|
+
@request.should_receive(:add_field).with('ACCEPT', 'application/json')
|
101
116
|
do_apply_headers
|
102
117
|
end
|
103
118
|
|
@@ -106,22 +121,31 @@ describe Icontact::Api do
|
|
106
121
|
do_apply_headers
|
107
122
|
end
|
108
123
|
|
109
|
-
it "should add an
|
110
|
-
@request.should_receive(:add_field).with('
|
124
|
+
it "should add an API_KEY header to verify that our application is authrorized to use the API" do
|
125
|
+
@request.should_receive(:add_field).with('API_KEY', @api.class::API_KEY)
|
111
126
|
do_apply_headers
|
112
127
|
end
|
113
128
|
|
114
|
-
it "should add an
|
115
|
-
@request.should_receive(:add_field).with('
|
129
|
+
it "should add an API_USERNAME header to verify that our user is authorized to use the API" do
|
130
|
+
@request.should_receive(:add_field).with('API_USERNAME', 'username')
|
116
131
|
do_apply_headers
|
117
132
|
end
|
118
|
-
|
119
|
-
it "should add an
|
120
|
-
@request.should_receive(:add_field).with('
|
133
|
+
|
134
|
+
it "should add an API_TIMESTAMP header to prevent old requests from being replayed" do
|
135
|
+
@request.should_receive(:add_field).with('API_TIMESTAMP', 999999)
|
136
|
+
do_apply_headers
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should add an API_NUMBER header" do
|
140
|
+
@request.should_receive(:add_field).with('API_NUMBER', 111)
|
121
141
|
do_apply_headers
|
122
142
|
end
|
123
|
-
|
124
143
|
|
144
|
+
it "should add an API_SIGNATURE header to ensure this api request is valid" do
|
145
|
+
@api.should_receive(:request_signature).and_return('api_signature')
|
146
|
+
@request.should_receive(:add_field).with('API_SIGNATURE', 'api_signature')
|
147
|
+
do_apply_headers
|
148
|
+
end
|
125
149
|
end
|
126
150
|
|
127
151
|
describe "class methods" do
|
metadata
CHANGED
@@ -1,84 +1,81 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: icontact-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Kevin Olbrich
|
8
14
|
autorequire:
|
9
15
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
- |
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIIDPDCCAiSgAwIBAgIBADANBgkqhkiG9w0BAQUFADBEMRYwFAYDVQQDDA1rZXZp
|
14
|
-
bi5vbGJyaWNoMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
|
15
|
-
FgNjb20wHhcNMDkwMzA3MTUwMzQ5WhcNMTAwMzA3MTUwMzQ5WjBEMRYwFAYDVQQD
|
16
|
-
DA1rZXZpbi5vbGJyaWNoMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJ
|
17
|
-
k/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvza3W
|
18
|
-
J5Dloirbhpge6teyZNfvOzuo478vtqnU/c6S8o2EerBkmWm88J+ipItO3U2HDPgP
|
19
|
-
a7THrx41/QEj1oG15mO6wtBLf0Z+AOJFAmf+Th8x3b46b3Voo1+suON67fCqCz+U
|
20
|
-
L5V2I5NBNywCte5Nzjh7knLkHr+rUCCKAIPK6vq+sASMIgmlhzZUuQfdRZMhRVZP
|
21
|
-
clMwf9sIp7LUTq2b/LCdP2dlGFydb1cyvaHjho+X/pk5uWKcr1OkrZtYFdxyeGU4
|
22
|
-
ZTtqEd5vaNTacYf0vGBfPfiolIfbmOa8Pgfyj8zkjBug/iukM/YGmwL1KAk8Qs+/
|
23
|
-
gInxSkyPxa7zkYTzAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0G
|
24
|
-
A1UdDgQWBBS+y2GRZjETz6d3jHKosqOZ6Ll+zjANBgkqhkiG9w0BAQUFAAOCAQEA
|
25
|
-
f3hCt6NBuESjAN4fkpbcfi3/Nj06aNl6CAfryfKaOaIfLcypT5nqP1qtqqGih5ne
|
26
|
-
QCe7jmtZHOGFC/SSlCS8obHSkCGn2cfUl/InfpF/YQnZV0Kp8esihuVmEjO0SgEU
|
27
|
-
yf46wW9Nh4byKctkgKMlWnIqwAyk4G1dD/le6MGJutb4pv5hT9qm1vaTFkAcy1Qu
|
28
|
-
1VMZa+MH6xnINGdFyV8T7AYL5BaQTbp2WYsfbOvy3ZfxbpP5O3wc3wter/Cyp8pu
|
29
|
-
Wvn0/+13roT+v5T5yFIpu6NbSpuqvRaKZvS+n2ZgwS10rUPFydzn+335umE4vsfH
|
30
|
-
4Umf0rf1f8h+GJia5xXYww==
|
31
|
-
-----END CERTIFICATE-----
|
16
|
+
cert_chain: []
|
32
17
|
|
33
|
-
date:
|
18
|
+
date: 2011-04-27 00:00:00 -04:00
|
34
19
|
default_executable:
|
35
20
|
dependencies:
|
36
21
|
- !ruby/object:Gem::Dependency
|
37
|
-
name: json
|
38
22
|
type: :runtime
|
39
|
-
|
40
|
-
|
23
|
+
prerelease: false
|
24
|
+
name: json
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
41
27
|
requirements:
|
42
28
|
- - ">="
|
43
29
|
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
requirement: *id001
|
46
35
|
- !ruby/object:Gem::Dependency
|
47
|
-
name: newgem
|
48
36
|
type: :development
|
49
|
-
|
50
|
-
|
37
|
+
prerelease: false
|
38
|
+
name: bundler
|
39
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
51
41
|
requirements:
|
52
|
-
- -
|
42
|
+
- - ~>
|
53
43
|
- !ruby/object:Gem::Version
|
54
|
-
|
55
|
-
|
44
|
+
hash: 15
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
version: "1.0"
|
49
|
+
requirement: *id002
|
56
50
|
- !ruby/object:Gem::Dependency
|
57
|
-
name: hoe
|
58
51
|
type: :development
|
59
|
-
|
60
|
-
|
52
|
+
prerelease: false
|
53
|
+
name: jeweler
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
61
56
|
requirements:
|
62
57
|
- - ">="
|
63
58
|
- !ruby/object:Gem::Version
|
64
|
-
|
65
|
-
|
66
|
-
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
requirement: *id003
|
64
|
+
description:
|
67
65
|
email:
|
68
|
-
- kevin.olbrich@gmail.com
|
66
|
+
- kevin.olbrich+icontact-api@gmail.com
|
69
67
|
executables: []
|
70
68
|
|
71
69
|
extensions: []
|
72
70
|
|
73
71
|
extra_rdoc_files:
|
74
|
-
-
|
75
|
-
- Manifest.txt
|
76
|
-
- README.txt
|
72
|
+
- README.rdoc
|
77
73
|
files:
|
74
|
+
- Gemfile
|
78
75
|
- History.txt
|
79
|
-
-
|
80
|
-
- README.txt
|
76
|
+
- README.rdoc
|
81
77
|
- Rakefile
|
78
|
+
- VERSION
|
82
79
|
- lib/icontact-api.rb
|
83
80
|
- lib/icontact/api.rb
|
84
81
|
- script/console
|
@@ -89,33 +86,39 @@ files:
|
|
89
86
|
- spec/spec_helper.rb
|
90
87
|
- tasks/rspec.rake
|
91
88
|
has_rdoc: true
|
92
|
-
homepage:
|
89
|
+
homepage: http://github.com/olbrich/IContact-API
|
93
90
|
licenses: []
|
94
91
|
|
95
92
|
post_install_message:
|
96
|
-
rdoc_options:
|
97
|
-
|
98
|
-
- README.txt
|
93
|
+
rdoc_options: []
|
94
|
+
|
99
95
|
require_paths:
|
100
96
|
- lib
|
101
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
102
99
|
requirements:
|
103
100
|
- - ">="
|
104
101
|
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
105
|
version: "0"
|
106
|
-
version:
|
107
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
108
|
requirements:
|
109
109
|
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
112
|
+
segments:
|
113
|
+
- 0
|
111
114
|
version: "0"
|
112
|
-
version:
|
113
115
|
requirements: []
|
114
116
|
|
115
|
-
rubyforge_project:
|
116
|
-
rubygems_version: 1.3.
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.3.7
|
117
119
|
signing_key:
|
118
120
|
specification_version: 3
|
119
|
-
summary:
|
120
|
-
test_files:
|
121
|
-
|
121
|
+
summary: A thin wrapper around the iContact API
|
122
|
+
test_files:
|
123
|
+
- spec/api_spec.rb
|
124
|
+
- spec/spec_helper.rb
|
data.tar.gz.sig
DELETED
Binary file
|
data/Manifest.txt
DELETED
metadata.gz.sig
DELETED
Binary file
|