omnicontacts 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- omnicontacts (0.3.0)
4
+ omnicontacts (0.3.1)
5
5
  json
6
6
  rack
7
7
 
data/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # OmniContacts
2
2
 
3
- Inspired by the popular OmniAuth, OmniContacts is a library that enables users of an application to import contacts from their email accounts.
4
- The current version allows to import contacts from the three most popular web email providers: Gmail, Yahoo and Hotmail.
5
- OmniContacts is a Rack middleware, therefore you can use it with Rails, Sinatra and with any other Rack-based framework.
3
+ Inspired by the popular OmniAuth, OmniContacts is a library that enables users of an application to import contacts
4
+ from their email or Facebook accounts. The email providers currently supported are Gmail, Yahoo and Hotmail.
5
+ OmniContacts is a Rack middleware, therefore you can use it with Rails, Sinatra and any other Rack-based framework.
6
6
 
7
- OmniContacts uses the OAuth protocol to communicate with the contacts provider. Yahoo still uses OAuth 1.0, while both Gmail and Hotmail support OAuth 2.0.
8
- In order to use OmniContacts, it is therefore necessary to first register your application with the providers you want to use and to obtain client_id and client_secret.
7
+ OmniContacts uses the OAuth protocol to communicate with the contacts provider. Yahoo still uses OAuth 1.0, while
8
+ Facebook, Gmail and Hotmail support OAuth 2.0.
9
+ In order to use OmniContacts, it is therefore necessary to first register your application with the provider and to obtain client_id and client_secret.
9
10
 
10
11
  ## Usage
11
12
 
@@ -25,18 +26,19 @@ Rails.application.middleware.use OmniContacts::Builder do
25
26
  importer :gmail, "client_id", "client_secret", {:redirect_path => "/oauth2callback", :ssl_ca_file => "/etc/ssl/certs/curl-ca-bundle.crt"}
26
27
  importer :yahoo, "consumer_id", "consumer_secret", {:callback_path => '/callback'}
27
28
  importer :hotmail, "client_id", "client_secret"
29
+ importer :facebook, "client_id", "client_secret"
28
30
  end
29
31
 
30
32
  ```
31
33
 
32
- Every importer expects `client_id` and `client_secret` as mandatory, while `:redirect_path` and `:ssl_ca_file` are optional.
33
- Since Yahoo implements the version 1.0 of the OAuth protocol, naming is slightly different. Instead of `:redirect_path` you should use `:callback_path` as key in the hash providing the optional parameters.
34
+ Every importer expects `client_id` and `client_secret` as mandatory, while `:redirect_path` and `:ssl_ca_file` are optional.
35
+ Since Yahoo implements the version 1.0 of the OAuth protocol, naming is slightly different. Instead of `:redirect_path` you should use `:callback_path` as key in the hash providing the optional parameters.
34
36
  While `:ssl_ca_file` is optional, it is highly recommended to set it on production environments for obvious security reasons.
35
37
  On the other hand it makes things much easier to leave the default value for `:redirect_path` and `:callback path`, the reason of which will be clear after reading the following section.
36
38
 
37
39
  ## Integrating with your Application
38
40
 
39
- To use the Gem you first need to redirect your users to `/contacts/:importer`, where `:importer` can be gmail, yahoo or hotmail.
41
+ To use the Gem you first need to redirect your users to `/contacts/:importer`, where `:importer` can be facebook, gmail, yahoo or hotmail.
40
42
  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
43
  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
44
  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`:
@@ -45,8 +47,75 @@ If nothing is specified the default value is `/contacts/:importer/callback` (e.g
45
47
  match "/contacts/:importer/callback" => "your_controller#callback"
46
48
  ```
47
49
 
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.
49
-
50
+ The list of contacts can be accessed via the `omnicontacts.contacts` key in the environment hash and it consists of a simple array of hashes.
51
+ The following table shows which fields are supported by which provider:
52
+
53
+ <table>
54
+ <tr>
55
+ <th>Provider</th>
56
+ <th>:email</th>
57
+ <th>:id</th>
58
+ <th>:profile_image</th>
59
+ <th>:name</th>
60
+ <th>:first_name</th>
61
+ <th>:last_name</th>
62
+ <th>:birthday</th>
63
+ <th>:gender</th>
64
+ <th>:relation</th>
65
+ </tr>
66
+ <tr>
67
+ <td>Gmail</td>
68
+ <td>X</td>
69
+ <td>X</td>
70
+ <td></td>
71
+ <td>X</td>
72
+ <td>X</td>
73
+ <td>X</td>
74
+ <td>X</td>
75
+ <td>X</td>
76
+ <td>X</td>
77
+ </tr>
78
+ <tr>
79
+ <td>Facebook</td>
80
+ <td>X</td>
81
+ <td>X</td>
82
+ <td>X</td>
83
+ <td>X</td>
84
+ <td>X</td>
85
+ <td>X</td>
86
+ <td>X</td>
87
+ <td>X</td>
88
+ <td>X</td>
89
+ </tr>
90
+ <tr>
91
+ <td>Yahoo</td>
92
+ <td>X</td>
93
+ <td>X</td>
94
+ <td></td>
95
+ <td>X</td>
96
+ <td>X</td>
97
+ <td>X</td>
98
+ <td>X</td>
99
+ <td></td>
100
+ <td></td>
101
+ </tr>
102
+ <tr>
103
+ <td>Hotmail</td>
104
+ <td>X</td>
105
+ <td>X</td>
106
+ <td>X</td>
107
+ <td>X</td>
108
+ <td>X</td>
109
+ <td>X</td>
110
+ <td>X</td>
111
+ <td>X</td>
112
+ <td></td>
113
+ </tr>
114
+ </table>
115
+
116
+ Obviously it may happen that some fields are blank even if supported by the provider in the case that the contact did not provide any information about them.
117
+
118
+ The following snippet shows how to simply print name and email of each contact:
50
119
  ```ruby
51
120
  def contacts_callback
52
121
  @contacts = request.env['omnicontacts.contacts']
@@ -73,8 +142,9 @@ importer :gmail, "xxx", "yyy", :max_results => 1000
73
142
 
74
143
  Yahoo requires you to configure the Permissions your application requires. Make sure to go the Yahoo website and to select Read permission for Contacts.
75
144
 
76
- Hotmail does not accept requests from localhost. This can be quite annoying during development, but unfortunately this is the way it is.
77
- Hotmail presents another "peculiar" feature. Their API returns a Contact object, which does not contain an e-mail field! However, if the contact has either name, family name or both set to null, than there is a field called name which does contain the e-mail address. To summarize, a Hotmail contact will only be returned if the name field contains a valid e-mail address, otherwise it will be skipped. Another consequence is that OmniContacts can provide contacts with only the `:email` key set.
145
+ Hotmail presents a "peculiar" feature. Their API returns a Contact object which does not contain an e-mail field!
146
+ However, if the contact has either name, family name or both set to null, than there is a field called name which does contain the e-mail address.
147
+ This means that it may happen that an Hotmail contact does not contain the email field.
78
148
 
79
149
  ## Integration Testing
80
150
 
@@ -103,9 +173,40 @@ Follows a full example of an integration test:
103
173
  page.should have_content("user@example.com")
104
174
  ```
105
175
 
176
+ ## Working on localhost
177
+
178
+ Since Hotmail and Facebook do not allow the usage of `localhost` as redirect path for the authorization step, a workaround is to use the `localtunnel` gem.
179
+ This gem is really useful when you need someone, the contacts provider in this case, to access your locally running application using a unique url.
180
+
181
+ Install the Gem using RubyGems:
182
+ ```bash
183
+ sudo gem install localtunnel
184
+ ```
185
+
186
+ Start `localtunnel` passing your public SSH key and the port where your application is running:
187
+ ```bash
188
+ localtunnel -k ~/.ssh/id_rsa.pub 3000
189
+ ```
190
+
191
+ Check the output to see something like
192
+ ```bash
193
+ Port 3000 is now publicly accessible from http://8bv2.localtunnel.com ...
194
+ ```
195
+
196
+ The printed Url is the one you can now use to access your application.
197
+
198
+ ## Example application
199
+
200
+ Thanks to @sonianand11, you can find a full example of a Rails application using OmniContacts at: https://github.com/sonianand11/omnicontacts_example
201
+
202
+ ## Thanks
203
+
204
+ As already mentioned above, a special thanks goes to @sonianand11 for implementing an example app.
205
+ Thanks also to @asmatameem for its huge contribution. He indeed added support for Facebook and for many fields which were missing before.
206
+
106
207
  ## License
107
208
 
108
- Copyright (c) 2012 Diego81
209
+ Copyright (c) 2012-2013 Diego81
109
210
 
110
211
  Permission is hereby granted, free of charge, to any person obtaining a
111
212
  copy of this software and associated documentation files (the "Software"),
@@ -70,7 +70,7 @@ module OmniContacts
70
70
 
71
71
  def create_contact_element contact_info
72
72
  # creating nil fields to keep the fields consistent across other networks
73
- contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :image_source => nil, :relation => nil}
73
+ contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :profile_picture=> nil, :relation => nil}
74
74
  contact[:id] = contact_info['id']
75
75
  contact[:first_name] = normalize_name(contact_info['first_name'])
76
76
  contact[:last_name] = normalize_name(contact_info['last_name'])
@@ -79,7 +79,7 @@ module OmniContacts
79
79
  contact[:gender] = contact_info['gender']
80
80
  birthday = contact_info['birthday'].split('/') if contact_info['birthday']
81
81
  contact[:birthday] = birthday_format(birthday[0],birthday[1],birthday[2]) if birthday
82
- contact[:image_source] = contact_info['picture']['data']['url'] if contact_info['picture']
82
+ contact[:profile_picture] = contact_info['picture']['data']['url'] if contact_info['picture']
83
83
  contact[:relation] = contact_info['relationship']
84
84
  contact
85
85
  end
@@ -37,7 +37,7 @@ module OmniContacts
37
37
  contacts = []
38
38
  response['feed']['entry'].each do |entry|
39
39
  # creating nil fields to keep the fields consistent across other networks
40
- contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :image_source => nil, :relation => nil}
40
+ contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :profile_picture=> nil, :relation => nil}
41
41
  contact[:id] = entry['id']['$t'] if entry['id']
42
42
  if entry['gd$name']
43
43
  contact[:first_name] = normalize_name(entry['gd$name']['gd$givenName']['$t']) if entry['gd$name']['gd$givenName']
@@ -29,14 +29,18 @@ module OmniContacts
29
29
  contacts = []
30
30
  response['data'].each do |entry|
31
31
  # creating nil fields to keep the fields consistent across other networks
32
- contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :image_source => nil, :relation => nil}
32
+ contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :profile_picture=> nil, :relation => nil}
33
33
  contact[:id] = entry['user_id']
34
- contact[:first_name] = normalize_name(entry['first_name'])
35
- contact[:last_name] = normalize_name(entry['last_name'])
36
- contact[:name] = normalize_name(entry['name'])
34
+ if valid_email? entry["name"]
35
+ contact[:email] = entry["name"]
36
+ else
37
+ contact[:first_name] = normalize_name(entry['first_name'])
38
+ contact[:last_name] = normalize_name(entry['last_name'])
39
+ contact[:name] = normalize_name(entry['name'])
40
+ end
37
41
  contact[:birthday] = birthday_format(entry['birth_month'], entry['birth_day'], entry['birth_year'])
38
42
  contact[:gender] = entry['gender']
39
- contact[:image_source] = 'https://apis.live.net/v5.0/' + entry['user_id'] + '/picture' if entry['user_id']
43
+ contact[:profile_picture] = 'https://apis.live.net/v5.0/' + entry['user_id'] + '/picture' if entry['user_id']
40
44
  contacts << contact if contact[:name] || contact[:first_name]
41
45
  end
42
46
  contacts
@@ -47,7 +47,7 @@ module OmniContacts
47
47
  return contacts unless response['contacts']['contact']
48
48
  response['contacts']['contact'].each do |entry|
49
49
  # creating nil fields to keep the fields consistent across other networks
50
- contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :image_source => nil, :relation => nil}
50
+ contact = {:id => nil, :first_name => nil, :last_name => nil, :name => nil, :email => nil, :gender => nil, :birthday => nil, :profile_picture=> nil, :relation => nil}
51
51
  yahoo_id = nil
52
52
  contact[:id] = entry['id'].to_s
53
53
  entry['fields'].each do |field|
data/lib/omnicontacts.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module OmniContacts
2
2
 
3
- VERSION = "0.3.1"
3
+ VERSION = "0.3.2"
4
4
 
5
5
  autoload :Builder, "omnicontacts/builder"
6
6
  autoload :Importer, "omnicontacts/importer"
@@ -39,7 +39,7 @@ describe OmniContacts::Importer::Facebook do
39
39
  facebook.fetch_contacts_using_access_token token, token_type
40
40
  end
41
41
 
42
- it "should correctly parse id, name,email,gender, birthday, image source and relation" do
42
+ it "should correctly parse id, name,email,gender, birthday, profile picture and relation" do
43
43
  3.times { facebook.should_receive(:https_get).and_return(contacts_as_json) }
44
44
  result = facebook.fetch_contacts_using_access_token token, token_type
45
45
  result.size.should be(1)
@@ -50,7 +50,7 @@ describe OmniContacts::Importer::Facebook do
50
50
  result.first[:email].should be_nil
51
51
  result.first[:gender].should eq('male')
52
52
  result.first[:birthday].should eq({:day=>21, :month=>06, :year=>nil})
53
- result.first[:image_source].should eq('http://profile.ak.fbcdn.net/hprofile-ak-snc6/186364_608061886_2089044200_q.jpg')
53
+ result.first[:profile_picture].should eq('http://profile.ak.fbcdn.net/hprofile-ak-snc6/186364_608061886_2089044200_q.jpg')
54
54
  result.first[:relation].should eq('cousin')
55
55
  end
56
56
  end
@@ -37,7 +37,7 @@ describe OmniContacts::Importer::Hotmail do
37
37
  hotmail.fetch_contacts_using_access_token token, token_type
38
38
  end
39
39
 
40
- it "should correctly parse id, name,email,gender, birthday, image source and relation" do
40
+ it "should correctly parse id, name,email,gender, birthday, profile picture and relation" do
41
41
  hotmail.should_receive(:https_get).and_return(contacts_as_json)
42
42
  result = hotmail.fetch_contacts_using_access_token token, token_type
43
43
  result.size.should be(1)
@@ -48,7 +48,7 @@ describe OmniContacts::Importer::Hotmail do
48
48
  result.first[:email].should be_nil
49
49
  result.first[:gender].should be_nil
50
50
  result.first[:birthday].should eq({:day=>5, :month=>6, :year=>1952})
51
- result.first[:image_source].should eq('https://apis.live.net/v5.0/123456/picture')
51
+ result.first[:profile_picture].should eq('https://apis.live.net/v5.0/123456/picture')
52
52
  result.first[:relation].should be_nil
53
53
  end
54
54
  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.3.1
4
+ version: 0.3.2
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: 2013-05-10 00:00:00.000000000 Z
12
+ date: 2013-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack