omnicontacts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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: []