omnicontacts 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/authorization/oauth2"
3
+
4
+ describe OmniContacts::Authorization::OAuth2 do
5
+
6
+ before(:all) do
7
+ OAuth2TestClass= Struct.new(:auth_host, :authorize_path, :client_id, :client_secret, :scope, :redirect_uri,:auth_token_path)
8
+ class OAuth2TestClass
9
+ include OmniContacts::Authorization::OAuth2
10
+ end
11
+ end
12
+
13
+ let(:test_target) do
14
+ OAuth2TestClass.new("auth_host", "authorize_path", "client_id", "client_secret", "scope", "redirect_uri", "auth_token_path")
15
+ end
16
+
17
+ describe "authorization_url" do
18
+
19
+ subject {test_target.authorization_url}
20
+
21
+ it {should include("https://#{test_target.auth_host}#{test_target.authorize_path}")}
22
+ it {should include("client_id=#{test_target.client_id}")}
23
+ it {should include("scope=#{test_target.scope}")}
24
+ it {should include("redirect_uri=#{test_target.redirect_uri}")}
25
+ it {should include("access_type=offline")}
26
+ it {should include("response_type=code")}
27
+ end
28
+
29
+ let(:access_token_response) {%[{"access_token": "access_token", "token_type":"token_type", "refresh_token":"refresh_token"}] }
30
+
31
+ describe "fetch_access_token" do
32
+
33
+ it "should provide all mandatory parameters in a https post request" do
34
+ code = "code"
35
+ test_target.should_receive(:https_post) do |host, path, params|
36
+ host.should eq(test_target.auth_host)
37
+ path.should eq(test_target.auth_token_path)
38
+ params[:code].should eq(code)
39
+ params[:client_id].should eq(test_target.client_id)
40
+ params[:client_secret].should eq(test_target.client_secret)
41
+ params[:redirect_uri].should eq(test_target.redirect_uri)
42
+ params[:grant_type].should eq("authorization_code")
43
+ access_token_response
44
+ end
45
+ test_target.fetch_access_token code
46
+ end
47
+
48
+ it "should successfully parse the token from the JSON response" do
49
+ test_target.should_receive(:https_post).and_return(access_token_response)
50
+ (access_token, token_type, refresh_token) = test_target.fetch_access_token "code"
51
+ access_token.should eq("access_token")
52
+ token_type.should eq("token_type")
53
+ refresh_token.should eq("refresh_token")
54
+ end
55
+
56
+ it "should raise if the http request fails" do
57
+ test_target.should_receive(:https_post).and_raise("Invalid code")
58
+ expect{test_target.fetch_access_token("code")}.should raise_error
59
+ end
60
+
61
+ it "should raise an error if the JSON response contains an error field" do
62
+ test_target.should_receive(:https_post).and_return(%[{"error": "error_message"}])
63
+ expect{test_target.fetch_access_token("code")}.should raise_error
64
+ end
65
+ end
66
+
67
+ describe "refresh_access_token" do
68
+ it "should provide all mandatory fields in a https post request" do
69
+ refresh_token = "refresh_token"
70
+ test_target.should_receive(:https_post) do |host, path, params|
71
+ host.should eq(test_target.auth_host)
72
+ path.should eq(test_target.auth_token_path)
73
+ params[:client_id].should eq(test_target.client_id)
74
+ params[:client_secret].should eq(test_target.client_secret)
75
+ params[:refresh_token].should eq(refresh_token)
76
+ params[:grant_type].should eq("refresh_token")
77
+ access_token_response
78
+ end
79
+ test_target.refresh_access_token refresh_token
80
+ end
81
+
82
+ it "should successfully parse the token from the JSON response" do
83
+ test_target.should_receive(:https_post).and_return(access_token_response)
84
+ (access_token, token_type, refresh_token) = test_target.refresh_access_token "refresh_token"
85
+ access_token.should eq("access_token")
86
+ token_type.should eq("token_type")
87
+ refresh_token.should eq("refresh_token")
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/http_utils"
3
+
4
+ describe OmniContacts::HTTPUtils do
5
+
6
+ describe "to_query_string" do
7
+ it "should create a query string from a map" do
8
+ OmniContacts::HTTPUtils.to_query_string(:name => "john", :surname => "doe").should eq("name=john&surname=doe")
9
+ end
10
+ end
11
+
12
+ describe "encode" do
13
+ it "should encode the space" do
14
+ OmniContacts::HTTPUtils.encode("name=\"john\"").should eq("name%3D%22john%22")
15
+ end
16
+ end
17
+
18
+ describe "query_string_to_map" do
19
+ it "should split a query string into a map" do
20
+ query_string = "name=john&surname=doe"
21
+ result = OmniContacts::HTTPUtils.query_string_to_map(query_string)
22
+ result["name"].should eq("john")
23
+ result["surname"].should eq("doe")
24
+ end
25
+ end
26
+
27
+ describe "host_url_from_rack_env" do
28
+ it "should calculate the host url using the HTTP_HOST variable" do
29
+ env = {"rack.url_scheme" => "http", "HTTP_HOST" => "localhost:8080","SERVER_NAME" => "localhost", "SERVER_PORT" => 8080}
30
+ OmniContacts::HTTPUtils.host_url_from_rack_env(env).should eq("http://localhost:8080")
31
+ end
32
+
33
+ it "should calculate the host url using SERVER_NAME and SERVER_PORT variables" do
34
+ env = {"rack.url_scheme" => "http", "SERVER_NAME" => "localhost", "SERVER_PORT" => 8080}
35
+ OmniContacts::HTTPUtils.host_url_from_rack_env(env).should eq("http://localhost:8080")
36
+ end
37
+ end
38
+
39
+ describe "https_post" do
40
+
41
+ before(:each) do
42
+ @connection = double
43
+ Net::HTTP.should_receive(:new).and_return(@connection)
44
+ @connection.should_receive(:use_ssl=).with(true)
45
+ @test_target = Object.new
46
+ @test_target.extend OmniContacts::HTTPUtils
47
+ @response = double
48
+ end
49
+
50
+ it "should execute a request with success" do
51
+ @test_target.should_receive(:ssl_ca_file).and_return(nil)
52
+ @connection.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
53
+ @connection.should_receive(:request_post).and_return(@response)
54
+ @response.should_receive(:code).and_return("200")
55
+ @response.should_receive(:body).and_return("some content")
56
+ @test_target.send(:https_post, "host", "path", {})
57
+ end
58
+
59
+ it "should raise an exception with response code != 200" do
60
+ @test_target.should_receive(:ssl_ca_file).and_return(nil)
61
+ @connection.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
62
+ @connection.should_receive(:request_get).and_return(@response)
63
+ @response.should_receive(:code).and_return("500")
64
+ @response.should_receive(:body).and_return("some error message")
65
+ expect {@test_target.send(:https_get, "host", "path", {})}.should raise_error
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/importer/gmail"
3
+
4
+ describe OmniContacts::Importer::Gmail do
5
+
6
+ let(:gmail) { OmniContacts::Importer::Gmail.new( {}, "client_id", "client_secret") }
7
+
8
+ let(:contacts_as_xml) {
9
+ "<entry xmlns:gd='http://schemas.google.com/g/2005'>
10
+ <gd:name>
11
+ <gd:fullName>Edward Bennet</gd:fullName>
12
+ </gd:name>
13
+ <gd:email rel='http://schemas.google.com/g/2005#work' primary='true' address='bennet@gmail.com'/>
14
+ </entry>"
15
+ }
16
+
17
+ describe "fetch_contacts_using_access_token" do
18
+
19
+ let(:token) { "token"}
20
+ let(:token_type) { "token_type" }
21
+
22
+ it "should request the contacts by specifying version and code in the http headers" do
23
+ gmail.should_receive(:https_get) do |host, path, params, headers|
24
+ headers["GData-Version"].should eq("3.0")
25
+ headers["Authorization"].should eq("#{token_type} #{token}")
26
+ contacts_as_xml
27
+ end
28
+ gmail.fetch_contacts_using_access_token token, token_type
29
+ end
30
+
31
+ it "should correctly parse name and email" do
32
+ gmail.should_receive(:https_get).and_return(contacts_as_xml)
33
+ result = gmail.fetch_contacts_using_access_token token, token_type
34
+ result.size.should be(1)
35
+ result.first[:name].should eq("Edward Bennet")
36
+ result.first[:email].should eq("bennet@gmail.com")
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/importer/hotmail"
3
+
4
+ describe OmniContacts::Importer::Hotmail do
5
+
6
+ let(:hotmail) {OmniContacts::Importer::Hotmail.new({}, "client_id", "client_secret") }
7
+
8
+ let(:contacts_as_json) {
9
+ "{
10
+ \"data\":
11
+ [{
12
+ \"id\": \"contact.b4466224b2ca42798c3d4ea90c75aa56\",
13
+ \"first_name\": null,
14
+ \"last_name\": null,
15
+ \"name\": \"henrik@hotmail.com\",
16
+ \"gender\": null,
17
+ \"is_friend\": false,
18
+ \"is_favorite\": false,
19
+ \"user_id\": null,
20
+ \"birth_day\": 29,
21
+ \"birth_month\": 3
22
+ }]
23
+ }"}
24
+
25
+ describe "fetch_contacts_using_access_token" do
26
+
27
+ let(:token) { "token"}
28
+ let(:token_type) { "token_type" }
29
+
30
+ it "should request the contacts by providing the token in the url" do
31
+ hotmail.should_receive(:https_get) do |host, path, params, headers|
32
+ params[:access_token].should eq(token)
33
+ contacts_as_json
34
+ end
35
+ hotmail.fetch_contacts_using_access_token token, token_type
36
+ end
37
+
38
+ it "should correctly parse the contacts" do
39
+ hotmail.should_receive(:https_get).and_return(contacts_as_json)
40
+ result = hotmail.fetch_contacts_using_access_token token, token_type
41
+ result.size.should be(1)
42
+ result.first[:name].should be_nil
43
+ result.first[:email].should eq("henrik@hotmail.com")
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/importer/yahoo"
3
+
4
+ describe OmniContacts::Importer::Yahoo do
5
+
6
+ describe "fetch_contacts_from_token_and_verifier" do
7
+ let(:contacts_as_json) {
8
+ '{"contacts":
9
+ {"start":1, "count":1,
10
+ "contact":[{"id":10, "fields":[{"id":819, "type":"email", "value":"john@yahoo.com"},
11
+ {"type":"name", "value": { "givenName":"John", "familyName":"Doe"} }] }]
12
+ } }'}
13
+
14
+ let(:yahoo) { OmniContacts::Importer::Yahoo.new( {}, "consumer_key", "consumer_secret" ) }
15
+
16
+ it "should request the contacts by specifying all required parameters" do
17
+ yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
18
+ yahoo.should_receive(:http_get) do |host, path, params|
19
+ params[:format].should eq("json")
20
+ params[:oauth_consumer_key].should eq("consumer_key")
21
+ params[:oauth_nonce].should_not be_nil
22
+ params[:oauth_signature_method].should eq("HMAC-SHA1")
23
+ params[:oauth_timestamp].should_not be_nil
24
+ params[:oauth_token].should eq("access_token")
25
+ params[:oauth_version].should eq("1.0")
26
+ params[:view].should eq("compact")
27
+ contacts_as_json
28
+ end
29
+ yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
30
+ end
31
+
32
+ it "should parse the contacts correctly" do
33
+ yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
34
+ yahoo.should_receive(:http_get).and_return(contacts_as_json)
35
+ result = yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
36
+ result.size.should be(1)
37
+ result.first[:name].should eq("John Doe")
38
+ result.first[:email].should eq("john@yahoo.com")
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/middleware/oauth1"
3
+
4
+ describe OmniContacts::Middleware::OAuth1 do
5
+
6
+ before(:all) do
7
+ class OAuth1Middleware < OmniContacts::Middleware::OAuth1
8
+ def self.mock_auth_token_resp
9
+ @mock_auth_token_resp ||= Object.new
10
+ end
11
+
12
+ def fetch_authorization_token
13
+ OAuth1Middleware.mock_auth_token_resp.body
14
+ end
15
+
16
+ def authorization_url auth_token
17
+ "http://www.example.com"
18
+ end
19
+
20
+ def fetch_contacts_from_token_and_verifier oauth_token, ouath_token_secret, oauth_verifier
21
+ [{:name => "John Doe", :email => "john@example.com"}]
22
+ end
23
+
24
+ def self.mock_session
25
+ @mock_session ||= {}
26
+ end
27
+ def session
28
+ OAuth1Middleware.mock_session
29
+ end
30
+ end
31
+ end
32
+
33
+ let(:app) {
34
+ Rack::Builder.new do |b|
35
+ b.use OAuth1Middleware, "consumer_id", "consumer_secret"
36
+ b.run lambda{ |env| [200, {"Content-Type" => "text/html"}, ["Hello World"]] }
37
+ end.to_app
38
+ }
39
+
40
+ context "visiting the listening path" do
41
+ it "should save the authorization token and redirect to the authorization url" do
42
+ OAuth1Middleware.mock_auth_token_resp.should_receive(:body).and_return(["auth_token", "auth_token_secret"])
43
+ get "/contacts/oauth1middleware"
44
+ last_response.should be_redirect
45
+ last_response.headers['location'].should eq("http://www.example.com")
46
+ end
47
+
48
+ it "should redirect to failure url if fetching the request token does not succeed" do
49
+ OAuth1Middleware.mock_auth_token_resp.should_receive(:body).and_raise("Request failed")
50
+ get "contacts/oauth1middleware"
51
+ last_response.should be_redirect
52
+ last_response.headers["location"].should eq("/contacts/failure?error_message=internal_error")
53
+ end
54
+ end
55
+
56
+ context "visiting the callback url after authorization" do
57
+ it "should return the list of contacts" do
58
+ OAuth1Middleware.mock_session.should_receive(:[]).and_return("oauth_token_secret")
59
+ get "/contacts/oauth1middleware/callback?oauth_token=token&oauth_verifier=verifier"
60
+ last_response.should be_ok
61
+ last_request.env["omnicontacts.contacts"].size.should be(1)
62
+ end
63
+
64
+ it "should redirect to failure url if oauth_token_secret is not found in the session" do
65
+ OAuth1Middleware.mock_session.should_receive(:[]).and_return(nil)
66
+ get "/contacts/oauth1middleware/callback?oauth_token=token&oauth_verifier=verifier"
67
+ last_response.should be_redirect
68
+ last_response.headers["location"].should eq("/contacts/failure?error_message=not_authorized")
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+ require "omnicontacts/middleware/oauth2"
3
+
4
+ describe OmniContacts::Middleware::OAuth2 do
5
+
6
+ before(:all) do
7
+ class OAuth2Middleware < OmniContacts::Middleware::OAuth2
8
+ def authorization_url
9
+ "http://www.example.com"
10
+ end
11
+
12
+ def redirect_path
13
+ "/redirect_path"
14
+ end
15
+
16
+ def self.mock_session
17
+ @mock_session ||= {}
18
+ end
19
+
20
+ def session
21
+ OAuth2Middleware.mock_session
22
+ end
23
+
24
+ def fetch_access_token code
25
+ ["access_token", "token_type", "token_refresh"]
26
+ end
27
+
28
+ def fetch_contacts_using_access_token token, token_type
29
+ [{:name => "John Doe", :email => "john@example.com"}]
30
+ end
31
+ end
32
+ end
33
+
34
+ let(:app) {
35
+ Rack::Builder.new do |b|
36
+ b.use OAuth2Middleware, "client_id", "client_secret"
37
+ b.run lambda{ |env| [200, {"Content-Type" => "text/html"}, ["Hello World"]] }
38
+ end.to_app
39
+ }
40
+
41
+ context "visiting the listening path" do
42
+ it "should redirect to authorization site when visiting the listening path" do
43
+ get "/contacts/oauth2middleware"
44
+ last_response.should be_redirect
45
+ last_response.headers['location'].should eq("http://www.example.com")
46
+ end
47
+ end
48
+
49
+ context "visiting the callback url after authorization" do
50
+ it "should fetch the contacts" do
51
+ get '/redirect_path?code=ABC'
52
+ last_response.should be_ok
53
+ last_request.env["omnicontacts.contacts"].size.should be(1)
54
+ end
55
+
56
+ it "should redirect to failure page because user did not allow access to contacts list" do
57
+ get '/redirect_path?error=not_authorized'
58
+ last_response.should be_redirect
59
+ last_response.headers["location"].should eq("/contacts/failure?error_message=not_authorized")
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,10 @@
1
+ require "simplecov"
2
+ SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
5
+
6
+ require "rspec"
7
+ require "rack/test"
8
+ RSpec.configure do |config|
9
+ config.include Rack::Test::Methods
10
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omnicontacts
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Diego Castorina
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &1458910 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *1458910
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ requirement: &1453940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *1453940
36
+ - !ruby/object:Gem::Dependency
37
+ name: simplecov
38
+ requirement: &1452760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *1452760
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &1451690 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *1451690
58
+ - !ruby/object:Gem::Dependency
59
+ name: rack-test
60
+ requirement: &1450620 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *1450620
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &1449560 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *1449560
80
+ description: A generalized Rack middleware for importing contacts from major email
81
+ providers.
82
+ email:
83
+ - diegocastorina@gmail.com
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - Gemfile
90
+ - Gemfile.lock
91
+ - README.md
92
+ - Rakefile
93
+ - lib/omnicontacts.rb
94
+ - lib/omnicontacts/authorization/oauth1.rb
95
+ - lib/omnicontacts/authorization/oauth2.rb
96
+ - lib/omnicontacts/builder.rb
97
+ - lib/omnicontacts/http_utils.rb
98
+ - lib/omnicontacts/importer.rb
99
+ - lib/omnicontacts/importer/gmail.rb
100
+ - lib/omnicontacts/importer/hotmail.rb
101
+ - lib/omnicontacts/importer/yahoo.rb
102
+ - lib/omnicontacts/middleware/base_oauth.rb
103
+ - lib/omnicontacts/middleware/oauth1.rb
104
+ - lib/omnicontacts/middleware/oauth2.rb
105
+ - omnicontacts.gemspec
106
+ - spec/omnicontacts/authorization/oauth1_spec.rb
107
+ - spec/omnicontacts/authorization/oauth2_spec.rb
108
+ - spec/omnicontacts/http_utils_spec.rb
109
+ - spec/omnicontacts/importer/gmail_spec.rb
110
+ - spec/omnicontacts/importer/hotmail_spec.rb
111
+ - spec/omnicontacts/importer/yahoo_spec.rb
112
+ - spec/omnicontacts/middleware/oauth1_spec.rb
113
+ - spec/omnicontacts/middleware/oauth2_spec.rb
114
+ - spec/spec_helper.rb
115
+ homepage: http://github.com/Diego81/omnicontacts
116
+ licenses: []
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: 1.3.6
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 1.8.17
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: A generalized Rack middleware for importing contacts from major email providers.
139
+ test_files: []