omnigroupcontacts 0.3.10 → 0.3.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +39 -0
  5. data/README.md +132 -0
  6. data/Rakefile +7 -0
  7. data/lib/omnigroupcontacts.rb +19 -0
  8. data/lib/omnigroupcontacts/authorization/oauth1.rb +122 -0
  9. data/lib/omnigroupcontacts/authorization/oauth2.rb +87 -0
  10. data/lib/omnigroupcontacts/builder.rb +30 -0
  11. data/lib/omnigroupcontacts/http_utils.rb +101 -0
  12. data/lib/omnigroupcontacts/importer.rb +5 -0
  13. data/lib/omnigroupcontacts/importer/gmailgroup.rb +238 -0
  14. data/lib/omnigroupcontacts/integration_test.rb +36 -0
  15. data/lib/omnigroupcontacts/middleware/base_oauth.rb +120 -0
  16. data/lib/omnigroupcontacts/middleware/oauth1.rb +70 -0
  17. data/lib/omnigroupcontacts/middleware/oauth2.rb +80 -0
  18. data/lib/omnigroupcontacts/parse_utils.rb +56 -0
  19. data/omnigroupcontacts-0.3.10.gem +0 -0
  20. data/omnigroupcontacts-0.3.8.gem +0 -0
  21. data/omnigroupcontacts-0.3.9.gem +0 -0
  22. data/omnigroupcontacts.gemspec +25 -0
  23. data/spec/omnicontacts/authorization/oauth1_spec.rb +82 -0
  24. data/spec/omnicontacts/authorization/oauth2_spec.rb +92 -0
  25. data/spec/omnicontacts/http_utils_spec.rb +79 -0
  26. data/spec/omnicontacts/importer/facebook_spec.rb +120 -0
  27. data/spec/omnicontacts/importer/gmail_spec.rb +194 -0
  28. data/spec/omnicontacts/importer/hotmail_spec.rb +106 -0
  29. data/spec/omnicontacts/importer/linkedin_spec.rb +67 -0
  30. data/spec/omnicontacts/importer/yahoo_spec.rb +124 -0
  31. data/spec/omnicontacts/integration_test_spec.rb +51 -0
  32. data/spec/omnicontacts/middleware/base_oauth_spec.rb +53 -0
  33. data/spec/omnicontacts/middleware/oauth1_spec.rb +78 -0
  34. data/spec/omnicontacts/middleware/oauth2_spec.rb +67 -0
  35. data/spec/omnicontacts/parse_utils_spec.rb +53 -0
  36. data/spec/spec_helper.rb +12 -0
  37. metadata +37 -2
@@ -0,0 +1,124 @@
1
+ require "spec_helper"
2
+ require "omnigroupcontacts/importer/yahoo"
3
+
4
+ describe OmniGroupContacts::Importer::Yahoo do
5
+
6
+ describe "fetch_contacts_from_token_and_verifier" do
7
+ let(:self_response) {
8
+ '{"profile":{
9
+ "guid":"PCLASP523T3E2R5TFMHDW9KWQQ",
10
+ "birthdate": "06/21",
11
+ "emails":[{"handle":"chrisjohnson@gmail.com", "id":10, "primary":true, "type":"HOME"}, {"handle":"xyz@xyz.com", "id":11, "type":"HOME"}],
12
+ "familyName": "Johnson",
13
+ "gender":"M",
14
+ "givenName":"Chris",
15
+ "image":{"imageUrl":"https://avatars.zenfs.com/users/23T3E2R5TFMHDW-AFE-I7lUpIsGQ==.large.png"}
16
+ }
17
+ }'
18
+ }
19
+
20
+ let(:contacts_as_json) {
21
+ '{
22
+ "contacts": {
23
+ "start":1,
24
+ "count":1,
25
+ "contact":[
26
+ {
27
+ "id":10,
28
+ "fields":[
29
+ {"id":819, "type":"email", "value":"johnny@yahoo.com"},
30
+ {"id":806,"type":"name","value":{"givenName":"John","middleName":"","familyName":"Smith"},"editedBy":"OWNER","categories":[]},
31
+ {"id":33555343,"type":"guid","value":"7ET6MYV2UQ6VR6CBSNMCLFJIVI"},
32
+ {"id":946,"type":"birthday","value":{"day":"22","month":"2","year":"1952"},"editedBy":"OWNER","categories":[]},
33
+ {"id":21, "type":"address", "value":{"street":"1313 Trashview Court\nApt. 13", "city":"Nowheresville", "stateOrProvince":"OK", "postalCode":"66666", "country":"", "countryCode":""}, "editedBy":"OWNER", "flags":["HOME"], "categories":[]}
34
+ ]
35
+ }
36
+ ]
37
+ }
38
+ }' }
39
+
40
+ let(:yahoo) { OmniGroupContacts::Importer::Yahoo.new({}, "consumer_key", "consumer_secret") }
41
+
42
+ before(:each) do
43
+ yahoo.instance_variable_set(:@env, {})
44
+ end
45
+
46
+ it "should request the contacts by specifying all required parameters" do
47
+ yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
48
+
49
+ yahoo.should_receive(:https_get) do |host, path, params|
50
+ params[:format].should eq("json")
51
+ params[:oauth_consumer_key].should eq("consumer_key")
52
+ params[:oauth_nonce].should_not be_nil
53
+ params[:oauth_signature_method].should eq("HMAC-SHA1")
54
+ params[:oauth_timestamp].should_not be_nil
55
+ params[:oauth_token].should eq("access_token")
56
+ params[:oauth_version].should eq("1.0")
57
+ self_response
58
+ end
59
+
60
+ yahoo.should_receive(:https_get) do |host, path, params|
61
+ params[:format].should eq("json")
62
+ params[:oauth_consumer_key].should eq("consumer_key")
63
+ params[:oauth_nonce].should_not be_nil
64
+ params[:oauth_signature_method].should eq("HMAC-SHA1")
65
+ params[:oauth_timestamp].should_not be_nil
66
+ params[:oauth_token].should eq("access_token")
67
+ params[:oauth_version].should eq("1.0")
68
+ contacts_as_json
69
+ end
70
+ yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
71
+ end
72
+
73
+ it "should correctly parse id, name,email,gender, birthday, snailmail address, image source and relation for contact and logged in user" do
74
+ yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
75
+ yahoo.should_receive(:https_get).and_return(self_response)
76
+ yahoo.should_receive(:https_get).and_return(contacts_as_json)
77
+ result = yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
78
+
79
+ result.size.should be(1)
80
+ result.first[:id].should eq('10')
81
+ result.first[:first_name].should eq('John')
82
+ result.first[:last_name].should eq('Smith')
83
+ result.first[:name].should eq("John Smith")
84
+ result.first[:email].should eq("johnny@yahoo.com")
85
+ result.first[:gender].should be_nil
86
+ result.first[:birthday].should eq({:day=>22, :month=>2, :year=>1952})
87
+ result.first[:address_1].should eq('1313 Trashview Court')
88
+ result.first[:address_2].should eq('Apt. 13')
89
+ result.first[:city].should eq('Nowheresville')
90
+ result.first[:region].should eq('OK')
91
+ result.first[:postcode].should eq('66666')
92
+ result.first[:relation].should be_nil
93
+ end
94
+
95
+ it "should return an empty list of contacts" do
96
+ empty_contacts_list = '{"contacts": {"start":0, "count":0}}'
97
+ yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
98
+ yahoo.should_receive(:https_get).and_return(self_response)
99
+ yahoo.should_receive(:https_get).and_return(empty_contacts_list)
100
+ result = yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
101
+
102
+ result.should be_empty
103
+ end
104
+
105
+ it "should correctly parse and set logged in user information" do
106
+ yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
107
+ yahoo.should_receive(:https_get).and_return(self_response)
108
+ yahoo.should_receive(:https_get).and_return(contacts_as_json)
109
+ yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
110
+
111
+ user = yahoo.instance_variable_get(:@env)["omnigroupcontacts.user"]
112
+ user.should_not be_nil
113
+ user[:id].should eq('PCLASP523T3E2R5TFMHDW9KWQQ')
114
+ user[:first_name].should eq('Chris')
115
+ user[:last_name].should eq('Johnson')
116
+ user[:name].should eq('Chris Johnson')
117
+ user[:gender].should eq('male')
118
+ user[:birthday].should eq({:day=>21, :month=>06, :year=>nil})
119
+ user[:email].should eq('chrisjohnson@gmail.com')
120
+ user[:profile_picture].should eq('https://avatars.zenfs.com/users/23T3E2R5TFMHDW-AFE-I7lUpIsGQ==.large.png')
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+ require "omnigroupcontacts/integration_test"
3
+
4
+ describe IntegrationTest do
5
+
6
+ context "mock_initial_request" do
7
+ it "should redirect to the provider's redirect_path" do
8
+ provider = mock
9
+ redirect_path = "/redirect_path"
10
+ provider.stub(:redirect_path => redirect_path)
11
+ IntegrationTest.instance.mock_authorization_from_user(provider)[1]["location"].should eq(redirect_path)
12
+ end
13
+ end
14
+
15
+ context "mock_callback" do
16
+
17
+ before(:each) {
18
+ @env = {}
19
+ @provider = self.mock
20
+ @provider.stub(:class_name => "test")
21
+ IntegrationTest.instance.clear_mocks
22
+ }
23
+
24
+ it "should return an empty contacts list" do
25
+ IntegrationTest.instance.mock_fetch_contacts(@provider).should be_empty
26
+ end
27
+
28
+ it "should return a configured list of contacts " do
29
+ contacts = [:name => 'John Doe', :email => 'john@doe.com']
30
+ IntegrationTest.instance.mock('test', contacts)
31
+ result = IntegrationTest.instance.mock_fetch_contacts(@provider)
32
+ result.size.should be(1)
33
+ result.first[:email].should eq(contacts.first[:email])
34
+ result.first[:name].should eq(contacts.first[:name])
35
+ end
36
+
37
+ it "should return a single element list of contacts " do
38
+ contact = {:name => 'John Doe', :email => 'john@doe.com'}
39
+ IntegrationTest.instance.mock('test', contact)
40
+ result = IntegrationTest.instance.mock_fetch_contacts(@provider)
41
+ result.size.should be(1)
42
+ result.first[:email].should eq(contact[:email])
43
+ result.first[:name].should eq(contact[:name])
44
+ end
45
+
46
+ it "should throw an exception" do
47
+ IntegrationTest.instance.mock('test', :some_error)
48
+ expect {IntegrationTest.instance.mock_fetch_contacts(@provider)}.to raise_error
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+ require "omnigroupcontacts"
3
+ require "omnigroupcontacts/middleware/base_oauth"
4
+
5
+ describe OmniGroupContacts::Middleware::BaseOAuth do
6
+
7
+ before(:all) do
8
+ class TestProvider < OmniGroupContacts::Middleware::BaseOAuth
9
+ def initialize app, consumer_key, consumer_secret, options = {}
10
+ super app, options
11
+ end
12
+
13
+ def redirect_path
14
+ "#{ MOUNT_PATH }testprovider/callback"
15
+ end
16
+ end
17
+ omnigroupcontacts.integration_test.enabled = true
18
+ end
19
+
20
+ let(:app) {
21
+ Rack::Builder.new do |b|
22
+ b.use TestProvider, "consumer_id", "consumer_secret"
23
+ b.run lambda { |env| [200, {"Content-Type" => "text/html"}, ["Hello World"]] }
24
+ end.to_app
25
+ }
26
+
27
+ it "should return a preconfigured list of contacts" do
28
+ omnigroupcontacts.integration_test.mock(:testprovider, :email => "user@example.com")
29
+ get "#{ MOUNT_PATH }testprovider"
30
+ get "#{ MOUNT_PATH }testprovider/callback"
31
+ last_request.env["omnigroupcontacts.contacts"].first[:email].should eq("user@example.com")
32
+ end
33
+
34
+ it "should redurect to failure url" do
35
+ omnigroupcontacts.integration_test.mock(:testprovider, "some_error" )
36
+ get "#{ MOUNT_PATH }testprovider"
37
+ get "#{MOUNT_PATH }testprovider/callback"
38
+ last_response.should be_redirect
39
+ last_response.headers["location"].should eq("#{ MOUNT_PATH }failure?error_message=internal_error&importer=testprovider")
40
+ end
41
+
42
+ it "should pass through state query params to the failure url" do
43
+ omnigroupcontacts.integration_test.mock(:testprovider, "some_error" )
44
+ get "#{MOUNT_PATH }testprovider/callback?state=/parent/resource/id"
45
+ last_response.headers["location"].should eq("#{ MOUNT_PATH }failure?error_message=internal_error&importer=testprovider&state=/parent/resource/id")
46
+ end
47
+
48
+ after(:all) do
49
+ omnigroupcontacts.integration_test.enabled = false
50
+ omnigroupcontacts.integration_test.clear_mocks
51
+ end
52
+
53
+ end
@@ -0,0 +1,78 @@
1
+ require "spec_helper"
2
+ require "omnigroupcontacts/middleware/oauth1"
3
+
4
+ describe OmniGroupContacts::Middleware::OAuth1 do
5
+
6
+ before(:all) do
7
+ class OAuth1Middleware < OmniGroupContacts::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
+
28
+ def session
29
+ OAuth1Middleware.mock_session
30
+ end
31
+ end
32
+ end
33
+
34
+ let(:app) {
35
+ Rack::Builder.new do |b|
36
+ b.use OAuth1Middleware, "consumer_id", "consumer_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 save the authorization token and redirect to the authorization url" do
43
+ OAuth1Middleware.mock_auth_token_resp.should_receive(:body).and_return(["auth_token", "auth_token_secret"])
44
+ get "#{ MOUNT_PATH }oauth1middleware"
45
+ last_response.should be_redirect
46
+ last_response.headers['location'].should eq("http://www.example.com")
47
+ end
48
+
49
+ it "should pass through state query params visiting the listening path" do
50
+ OAuth1Middleware.mock_auth_token_resp.should_receive(:body).and_return(["auth_token", "auth_token_secret"])
51
+ get "#{ MOUNT_PATH }oauth1middleware?state=/parent/resource/id"
52
+ last_response.headers['location'].should eq("http://www.example.com?state=/parent/resource/id")
53
+ end
54
+
55
+ it "should redirect to failure url if fetching the request token does not succeed" do
56
+ OAuth1Middleware.mock_auth_token_resp.should_receive(:body).and_raise("Request failed")
57
+ get "contacts/oauth1middleware"
58
+ last_response.should be_redirect
59
+ last_response.headers["location"].should eq("#{ MOUNT_PATH }failure?error_message=internal_error&importer=oauth1middleware")
60
+ end
61
+ end
62
+
63
+ context "visiting the callback url after authorization" do
64
+ it "should return the list of contacts" do
65
+ OAuth1Middleware.mock_session.should_receive(:[]).and_return("oauth_token_secret")
66
+ get "#{ MOUNT_PATH }oauth1middleware/callback?oauth_token=token&oauth_verifier=verifier"
67
+ last_response.should be_ok
68
+ last_request.env["omnigroupcontacts.contacts"].size.should be(1)
69
+ end
70
+
71
+ it "should redirect to failure url if oauth_token_secret is not found in the session" do
72
+ OAuth1Middleware.mock_session.should_receive(:[]).and_return(nil)
73
+ get "#{ MOUNT_PATH }oauth1middleware/callback?oauth_token=token&oauth_verifier=verifier"
74
+ last_response.should be_redirect
75
+ last_response.headers["location"].should eq("#{ MOUNT_PATH }failure?error_message=not_authorized&importer=oauth1middleware")
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+ require "omnigroupcontacts/middleware/oauth2"
3
+
4
+ describe OmniGroupContacts::Middleware::OAuth2 do
5
+
6
+ before(:all) do
7
+ class OAuth2Middleware < OmniGroupContacts::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 "#{ MOUNT_PATH }oauth2middleware"
44
+ last_response.should be_redirect
45
+ last_response.headers['location'].should eq("http://www.example.com")
46
+ end
47
+
48
+ it "should pass through state query params visiting the listening path" do
49
+ get "#{ MOUNT_PATH }oauth2middleware?state=/parent/resource/id"
50
+ last_response.headers['location'].should eq("http://www.example.com?state=/parent/resource/id")
51
+ end
52
+ end
53
+
54
+ context "visiting the callback url after authorization" do
55
+ it "should fetch the contacts" do
56
+ get '/redirect_path?code=ABC'
57
+ last_response.should be_ok
58
+ last_request.env["omnigroupcontacts.contacts"].size.should be(1)
59
+ end
60
+
61
+ it "should redirect to failure page because user did not allow access to contacts list" do
62
+ get '/redirect_path?error=not_authorized'
63
+ last_response.should be_redirect
64
+ last_response.headers["location"].should eq("#{ MOUNT_PATH }failure?error_message=not_authorized&importer=oauth2middleware")
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+ require "omnigroupcontacts/parse_utils"
3
+
4
+ include OmniGroupContacts::ParseUtils
5
+
6
+ describe OmniGroupContacts::ParseUtils do
7
+ describe "normalize_name" do
8
+ it "should remove trailing spaces" do
9
+ result = normalize_name("John ")
10
+ result.should eq("John")
11
+ end
12
+
13
+ it "should preserve capitalization" do
14
+ result = normalize_name("John McDonald")
15
+ result.should eq("John McDonald")
16
+ end
17
+ end
18
+
19
+ describe "full_name" do
20
+ it "should preserve capitalization" do
21
+ result = full_name("John", "McDonald")
22
+ result.should eq("John McDonald")
23
+ end
24
+
25
+ it "returns only first name if no last name present" do
26
+ result = full_name("John", nil)
27
+ result.should eq("John")
28
+ end
29
+
30
+ it "returns only last name if no first name present" do
31
+ result = full_name(nil, "McDonald")
32
+ result.should eq("McDonald")
33
+ end
34
+ end
35
+
36
+ describe "birthday_format" do
37
+ it "returns nil if (!year && !month) || (!year && !day)" do
38
+ result = birthday_format(nil, Date.today, nil)
39
+ result.should eq(nil)
40
+
41
+ result = birthday_format(Date.today.month, nil, nil)
42
+ result.should eq(nil)
43
+ end
44
+ end
45
+
46
+ describe "email_to_name" do
47
+ it "create a probable name from email" do
48
+ username_or_email = "foo.bar@test.com"
49
+ result = email_to_name(username_or_email)
50
+ result.should eq ['foo','bar',"foo bar"]
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,12 @@
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
11
+
12
+ MOUNT_PATH = "/contacts/"