omnicontacts 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +10 -2
- data/Rakefile +2 -1
- data/lib/omnicontacts.rb +9 -4
- data/lib/omnicontacts/authorization/oauth2.rb +7 -7
- data/lib/omnicontacts/http_utils.rb +2 -2
- data/lib/omnicontacts/integration_test.rb +36 -0
- data/lib/omnicontacts/middleware/base_oauth.rb +15 -7
- data/lib/omnicontacts/middleware/oauth1.rb +1 -1
- data/lib/omnicontacts/middleware/oauth2.rb +1 -1
- data/spec/omnicontacts/integration_test_spec.rb +51 -0
- data/spec/omnicontacts/middleware/base_oauth_spec.rb +46 -0
- metadata +5 -2
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -36,8 +36,16 @@ On the other hand it makes things much easier to leave the default value for `:r
|
|
36
36
|
|
37
37
|
## Integrating with your Application
|
38
38
|
|
39
|
-
To use
|
40
|
-
|
39
|
+
To use the Gem you first need to redirect your users to `/contacts/:importer`, where `:importer` can be google, yahoo or hotmail.
|
40
|
+
No changes to `config/routes.rb` are needed for this step since OmniContacts will be listening on that path and redirect the user to the email provider's website in order to authorize your app to access his contact list.
|
41
|
+
Once that is done the user will be redirected back to your application, to the path specified in `:redirect_path` (or `:callback_path` for yahoo).
|
42
|
+
If nothing is specified the default value is `/contacts/:importer/callback` (e.g. `/contacts/yahoo/callback`). This makes things simpler and you can just add the following line to `config/routes.rb`:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
match "/contacts/:importer/callback" => "your_controller#callback"
|
46
|
+
```
|
47
|
+
|
48
|
+
The list of contacts can be accessed via the `omnicontacts.contacts` key in the environment hash. It is a simple array of hashes. Each hash has two keys: `:email` and `:name`, containing the email and the name of the contact respectively.
|
41
49
|
|
42
50
|
```ruby
|
43
51
|
def contacts_callback
|
data/Rakefile
CHANGED
data/lib/omnicontacts.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
module OmniContacts
|
2
|
-
|
3
|
-
VERSION = "0.
|
2
|
+
|
3
|
+
VERSION = "0.2.0"
|
4
4
|
|
5
5
|
autoload :Builder, "omnicontacts/builder"
|
6
6
|
autoload :Importer, "omnicontacts/importer"
|
7
|
+
autoload :IntegrationTest, "omnicontacts/integration_test"
|
7
8
|
|
8
9
|
class AuthorizationError < RuntimeError
|
9
10
|
end
|
10
|
-
|
11
|
-
|
11
|
+
|
12
|
+
def self.integration_test
|
13
|
+
IntegrationTest.instance
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -27,13 +27,13 @@ module OmniContacts
|
|
27
27
|
|
28
28
|
def authorize_url_params
|
29
29
|
to_query_string({
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
:client_id => client_id,
|
31
|
+
:scope => encode(scope),
|
32
|
+
:response_type => "code",
|
33
|
+
:access_type => "offline",
|
34
|
+
:approval_prompt => "force",
|
35
|
+
:redirect_uri => encode(redirect_uri)
|
36
|
+
})
|
37
37
|
end
|
38
38
|
|
39
39
|
public
|
@@ -36,7 +36,7 @@ module OmniContacts
|
|
36
36
|
def host_url_from_rack_env env
|
37
37
|
port = ((env["SERVER_PORT"] == 80) && "") || ":#{env['SERVER_PORT']}"
|
38
38
|
host = (env["HTTP_HOST"]) || (env["SERVER_NAME"] + port)
|
39
|
-
scheme(env)
|
39
|
+
"#{scheme(env)}://#{host}"
|
40
40
|
end
|
41
41
|
|
42
42
|
def scheme env
|
@@ -45,7 +45,7 @@ module OmniContacts
|
|
45
45
|
elsif env['HTTP_X_FORWARDED_SSL'] == 'on'
|
46
46
|
'https'
|
47
47
|
elsif env['HTTP_X_FORWARDED_PROTO']
|
48
|
-
env['HTTP_X_FORWARDED_PROTO'].split(',')
|
48
|
+
env['HTTP_X_FORWARDED_PROTO'].split(',').first
|
49
49
|
else
|
50
50
|
env["rack.url_scheme"]
|
51
51
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class IntegrationTest
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
attr_accessor :enabled
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
enabled = false
|
10
|
+
clear_mocks
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear_mocks
|
14
|
+
@mock = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def mock provider, mock
|
18
|
+
@mock[provider.to_sym] = mock
|
19
|
+
end
|
20
|
+
|
21
|
+
def mock_authorization_from_user provider
|
22
|
+
[302, {"location" => provider.redirect_path}, []]
|
23
|
+
end
|
24
|
+
|
25
|
+
def mock_fetch_contacts provider
|
26
|
+
result = @mock[provider.class_name.to_sym] || []
|
27
|
+
if result.is_a? Array
|
28
|
+
result
|
29
|
+
elsif result.is_a? Hash
|
30
|
+
[result]
|
31
|
+
else
|
32
|
+
raise result.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -17,16 +17,12 @@ module OmniContacts
|
|
17
17
|
@ssl_ca_file = options[:ssl_ca_file]
|
18
18
|
end
|
19
19
|
|
20
|
-
private
|
21
|
-
|
22
20
|
def class_name
|
23
21
|
self.class.name.split('::').last.downcase
|
24
22
|
end
|
25
23
|
|
26
|
-
public
|
27
|
-
|
28
24
|
# Rack callback. It handles three cases:
|
29
|
-
# * user visit middleware
|
25
|
+
# * user visit middleware entry point.
|
30
26
|
# In this case request_authorization_from_user is called
|
31
27
|
# * user is redirected back to the application
|
32
28
|
# from the authorization site. In this case the list
|
@@ -47,16 +43,28 @@ module OmniContacts
|
|
47
43
|
end
|
48
44
|
|
49
45
|
private
|
46
|
+
|
47
|
+
def test_mode?
|
48
|
+
IntegrationTest.instance.enabled
|
49
|
+
end
|
50
50
|
|
51
51
|
def handle_initial_request
|
52
52
|
execute_and_rescue_exceptions do
|
53
|
-
|
53
|
+
if test_mode?
|
54
|
+
IntegrationTest.instance.mock_authorization_from_user(self)
|
55
|
+
else
|
56
|
+
request_authorization_from_user
|
57
|
+
end
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
57
61
|
def handle_callback
|
58
62
|
execute_and_rescue_exceptions do
|
59
|
-
@env["omnicontacts.contacts"] =
|
63
|
+
@env["omnicontacts.contacts"] = if test_mode?
|
64
|
+
IntegrationTest.instance.mock_fetch_contacts(self)
|
65
|
+
else
|
66
|
+
fetch_contacts
|
67
|
+
end
|
60
68
|
@app.call(@env)
|
61
69
|
end
|
62
70
|
end
|
@@ -18,7 +18,7 @@ module OmniContacts
|
|
18
18
|
super app, options
|
19
19
|
@consumer_key = consumer_key
|
20
20
|
@consumer_secret = consumer_secret
|
21
|
-
@callback_path = options[:callback_path]
|
21
|
+
@callback_path = options[:callback_path] || "/contacts/#{class_name}/callback"
|
22
22
|
@token_prop_name = "#{base_prop_name}.oauth_token"
|
23
23
|
end
|
24
24
|
|
@@ -19,7 +19,7 @@ module OmniContacts
|
|
19
19
|
super app, options
|
20
20
|
@client_id = client_id
|
21
21
|
@client_secret = client_secret
|
22
|
-
@redirect_path = options[:redirect_path]
|
22
|
+
@redirect_path = options[:redirect_path] || "/contacts/#{class_name}/callback"
|
23
23
|
@ssl_ca_file = options[:ssl_ca_file]
|
24
24
|
end
|
25
25
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "omnicontacts/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)}.should raise_error
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "omnicontacts/middleware/base_oauth"
|
3
|
+
|
4
|
+
describe OmniContacts::Middleware::BaseOAuth do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
class TestProvider < OmniContacts::Middleware::BaseOAuth
|
8
|
+
def initialize app, consumer_key, consumer_secret, options = {}
|
9
|
+
super app, options
|
10
|
+
end
|
11
|
+
|
12
|
+
def redirect_path
|
13
|
+
"/contacts/testprovider/callback"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
OmniContacts.integration_test.enabled = true
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:app) {
|
20
|
+
Rack::Builder.new do |b|
|
21
|
+
b.use TestProvider, "consumer_id", "consumer_secret"
|
22
|
+
b.run lambda { |env| [200, {"Content-Type" => "text/html"}, ["Hello World"]] }
|
23
|
+
end.to_app
|
24
|
+
}
|
25
|
+
|
26
|
+
it "should return a preconfigured list of contacts" do
|
27
|
+
OmniContacts.integration_test.mock(:testprovider, :email => "user@example.com")
|
28
|
+
get "/contacts/testprovider"
|
29
|
+
get "/contacts/testprovider/callback"
|
30
|
+
last_request.env["omnicontacts.contacts"].first[:email].should eq("user@example.com")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should redurect to failure url" do
|
34
|
+
OmniContacts.integration_test.mock(:testprovider, "some_error" )
|
35
|
+
get "/contacts/testprovider"
|
36
|
+
get "/contacts/testprovider/callback"
|
37
|
+
last_response.should be_redirect
|
38
|
+
last_response.headers["location"].should eq("/contacts/failure?error_message=internal_error")
|
39
|
+
end
|
40
|
+
|
41
|
+
after(:all) do
|
42
|
+
OmniContacts.integration_test.enabled = false
|
43
|
+
OmniContacts.integration_test.clear_mocks
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omnicontacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05
|
12
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- lib/omnicontacts/importer/gmail.rb
|
130
130
|
- lib/omnicontacts/importer/hotmail.rb
|
131
131
|
- lib/omnicontacts/importer/yahoo.rb
|
132
|
+
- lib/omnicontacts/integration_test.rb
|
132
133
|
- lib/omnicontacts/middleware/base_oauth.rb
|
133
134
|
- lib/omnicontacts/middleware/oauth1.rb
|
134
135
|
- lib/omnicontacts/middleware/oauth2.rb
|
@@ -139,6 +140,8 @@ files:
|
|
139
140
|
- spec/omnicontacts/importer/gmail_spec.rb
|
140
141
|
- spec/omnicontacts/importer/hotmail_spec.rb
|
141
142
|
- spec/omnicontacts/importer/yahoo_spec.rb
|
143
|
+
- spec/omnicontacts/integration_test_spec.rb
|
144
|
+
- spec/omnicontacts/middleware/base_oauth_spec.rb
|
142
145
|
- spec/omnicontacts/middleware/oauth1_spec.rb
|
143
146
|
- spec/omnicontacts/middleware/oauth2_spec.rb
|
144
147
|
- spec/spec_helper.rb
|