omnicontacts 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +24 -18
- data/README.md +100 -23
- data/lib/omnicontacts.rb +5 -2
- data/lib/omnicontacts/http_utils.rb +1 -1
- data/lib/omnicontacts/importer/facebook.rb +35 -8
- data/lib/omnicontacts/importer/gmail.rb +147 -11
- data/lib/omnicontacts/importer/hotmail.rb +40 -9
- data/lib/omnicontacts/importer/yahoo.rb +107 -14
- data/lib/omnicontacts/middleware/base_oauth.rb +18 -3
- data/lib/omnicontacts/middleware/oauth1.rb +4 -2
- data/lib/omnicontacts/middleware/oauth2.rb +3 -2
- data/lib/omnicontacts/parse_utils.rb +15 -1
- data/omnicontacts.gemspec +2 -2
- data/spec/omnicontacts/authorization/oauth1_spec.rb +2 -2
- data/spec/omnicontacts/http_utils_spec.rb +6 -0
- data/spec/omnicontacts/importer/facebook_spec.rb +68 -6
- data/spec/omnicontacts/importer/gmail_spec.rb +97 -4
- data/spec/omnicontacts/importer/hotmail_spec.rb +53 -3
- data/spec/omnicontacts/importer/yahoo_spec.rb +62 -6
- data/spec/omnicontacts/middleware/base_oauth_spec.rb +12 -6
- data/spec/omnicontacts/middleware/oauth1_spec.rb +11 -5
- data/spec/omnicontacts/middleware/oauth2_spec.rb +7 -2
- data/spec/omnicontacts/parse_utils_spec.rb +53 -0
- data/spec/spec_helper.rb +2 -0
- metadata +52 -33
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 153f2fff78dd7440fe1c653a7458f47db2b8717a
|
4
|
+
data.tar.gz: f115709601214db1e8826893355146514c5c8b82
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 29f390858859e150129a1a01d3fbbe6d523b997ece36e113e6c8635d5c0ecb2cc47f77e2686c07503703a4a0148dd543842cebfa5d285f0923be01e5f5d4454c
|
7
|
+
data.tar.gz: 7850d3c9bd1f6309f0dd1065262c6b16f7aa947ba3f33deb186ba8bff3a9809e5baeb1e588b6cc817c7b159650f3692c44c522df1d062f62a37fffbd6a97b90a
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,32 +1,38 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
omnicontacts (0.3.
|
4
|
+
omnicontacts (0.3.5)
|
5
5
|
json
|
6
6
|
rack
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: http://rubygems.org/
|
10
10
|
specs:
|
11
|
-
diff-lcs (1.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
rack
|
11
|
+
diff-lcs (1.2.5)
|
12
|
+
docile (1.1.5)
|
13
|
+
json (1.8.1)
|
14
|
+
multi_json (1.10.1)
|
15
|
+
rack (1.5.2)
|
16
|
+
rack-test (0.6.2)
|
16
17
|
rack (>= 1.0)
|
17
|
-
rake (
|
18
|
-
rspec (
|
19
|
-
rspec-core (~>
|
20
|
-
rspec-expectations (~>
|
21
|
-
rspec-mocks (~>
|
22
|
-
rspec-core (
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
rake (10.3.2)
|
19
|
+
rspec (3.1.0)
|
20
|
+
rspec-core (~> 3.1.0)
|
21
|
+
rspec-expectations (~> 3.1.0)
|
22
|
+
rspec-mocks (~> 3.1.0)
|
23
|
+
rspec-core (3.1.7)
|
24
|
+
rspec-support (~> 3.1.0)
|
25
|
+
rspec-expectations (3.1.2)
|
26
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
+
rspec-support (~> 3.1.0)
|
28
|
+
rspec-mocks (3.1.3)
|
29
|
+
rspec-support (~> 3.1.0)
|
30
|
+
rspec-support (3.1.2)
|
31
|
+
simplecov (0.9.1)
|
32
|
+
docile (~> 1.1.0)
|
27
33
|
multi_json (~> 1.0)
|
28
|
-
simplecov-html (~> 0.
|
29
|
-
simplecov-html (0.
|
34
|
+
simplecov-html (~> 0.8.0)
|
35
|
+
simplecov-html (0.8.0)
|
30
36
|
|
31
37
|
PLATFORMS
|
32
38
|
ruby
|
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# OmniContacts
|
2
2
|
|
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.
|
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
5
|
OmniContacts is a Rack middleware, therefore you can use it with Rails, Sinatra and any other Rack-based framework.
|
6
6
|
|
7
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.
|
8
|
+
Facebook, Gmail and Hotmail support OAuth 2.0.
|
9
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.
|
10
10
|
|
11
11
|
## Usage
|
@@ -31,14 +31,27 @@ end
|
|
31
31
|
|
32
32
|
```
|
33
33
|
|
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
|
+
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.
|
36
36
|
While `:ssl_ca_file` is optional, it is highly recommended to set it on production environments for obvious security reasons.
|
37
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.
|
38
38
|
|
39
|
+
## Register your application
|
40
|
+
|
41
|
+
* For Gmail : [Google API Console](https://code.google.com/apis/console/)
|
42
|
+
|
43
|
+
* For Yahoo : [Yahoo Developer Network](https://developer.apps.yahoo.com/projects)
|
44
|
+
|
45
|
+
* For Hotmail : [Microsoft Developer Network](https://account.live.com/developers/applications/index)
|
46
|
+
|
47
|
+
* For Facebook : [Facebook Developers](https://developers.facebook.com/apps)
|
48
|
+
|
49
|
+
##### Note:
|
50
|
+
Please go through [MSDN](http://msdn.microsoft.com/en-us/library/cc287659.aspx) if above Hotmail link will not work.
|
51
|
+
|
39
52
|
## Integrating with your Application
|
40
53
|
|
41
|
-
To use the Gem you first need to redirect your users to `/contacts/:importer`, where `:importer` can be facebook, gmail, yahoo or hotmail.
|
54
|
+
To use the Gem you first need to redirect your users to `/contacts/:importer`, where `:importer` can be facebook, gmail, yahoo or hotmail.
|
42
55
|
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.
|
43
56
|
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).
|
44
57
|
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`:
|
@@ -47,7 +60,7 @@ If nothing is specified the default value is `/contacts/:importer/callback` (e.g
|
|
47
60
|
match "/contacts/:importer/callback" => "your_controller#callback"
|
48
61
|
```
|
49
62
|
|
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.
|
63
|
+
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
64
|
The following table shows which fields are supported by which provider:
|
52
65
|
|
53
66
|
<table>
|
@@ -59,6 +72,13 @@ The following table shows which fields are supported by which provider:
|
|
59
72
|
<th>:name</th>
|
60
73
|
<th>:first_name</th>
|
61
74
|
<th>:last_name</th>
|
75
|
+
<th>:address_1</th>
|
76
|
+
<th>:address_2</th>
|
77
|
+
<th>:city</th>
|
78
|
+
<th>:region</th>
|
79
|
+
<th>:postcode</th>
|
80
|
+
<th>:country</th>
|
81
|
+
<th>:phone_number</th>
|
62
82
|
<th>:birthday</th>
|
63
83
|
<th>:gender</th>
|
64
84
|
<th>:relation</th>
|
@@ -74,15 +94,29 @@ The following table shows which fields are supported by which provider:
|
|
74
94
|
<td>X</td>
|
75
95
|
<td>X</td>
|
76
96
|
<td>X</td>
|
97
|
+
<td>X</td>
|
98
|
+
<td>X</td>
|
99
|
+
<td>X</td>
|
100
|
+
<td>X</td>
|
101
|
+
<td>X</td>
|
102
|
+
<td>X</td>
|
103
|
+
<td>X</td>
|
77
104
|
</tr>
|
78
105
|
<tr>
|
79
106
|
<td>Facebook</td>
|
107
|
+
<td></td>
|
80
108
|
<td>X</td>
|
81
109
|
<td>X</td>
|
82
110
|
<td>X</td>
|
83
111
|
<td>X</td>
|
84
112
|
<td>X</td>
|
85
|
-
<td
|
113
|
+
<td></td>
|
114
|
+
<td></td>
|
115
|
+
<td></td>
|
116
|
+
<td></td>
|
117
|
+
<td></td>
|
118
|
+
<td></td>
|
119
|
+
<td></td>
|
86
120
|
<td>X</td>
|
87
121
|
<td>X</td>
|
88
122
|
<td>X</td>
|
@@ -96,6 +130,13 @@ The following table shows which fields are supported by which provider:
|
|
96
130
|
<td>X</td>
|
97
131
|
<td>X</td>
|
98
132
|
<td>X</td>
|
133
|
+
<td>X</td>
|
134
|
+
<td>X</td>
|
135
|
+
<td>X</td>
|
136
|
+
<td>X</td>
|
137
|
+
<td></td>
|
138
|
+
<td></td>
|
139
|
+
<td>X</td>
|
99
140
|
<td></td>
|
100
141
|
<td></td>
|
101
142
|
</tr>
|
@@ -107,6 +148,13 @@ The following table shows which fields are supported by which provider:
|
|
107
148
|
<td>X</td>
|
108
149
|
<td>X</td>
|
109
150
|
<td>X</td>
|
151
|
+
<td></td>
|
152
|
+
<td></td>
|
153
|
+
<td></td>
|
154
|
+
<td></td>
|
155
|
+
<td></td>
|
156
|
+
<td></td>
|
157
|
+
<td></td>
|
110
158
|
<td>X</td>
|
111
159
|
<td>X</td>
|
112
160
|
<td></td>
|
@@ -115,11 +163,14 @@ The following table shows which fields are supported by which provider:
|
|
115
163
|
|
116
164
|
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
165
|
|
118
|
-
The
|
166
|
+
The information for the logged in user can also be accessed via 'omnicontacts.user' key in the environment hash. It consists of a simple hash which includes the same fields as above.
|
167
|
+
|
168
|
+
The following snippet shows how to simply print name and email of each contact, and also the the name of logged in user:
|
119
169
|
```ruby
|
120
170
|
def contacts_callback
|
121
171
|
@contacts = request.env['omnicontacts.contacts']
|
122
|
-
|
172
|
+
@user = request.env['omnicontacts.user']
|
173
|
+
puts "List of contacts of #{@user[:name]} obtained from #{params[:importer]}:"
|
123
174
|
@contacts.each do |contact|
|
124
175
|
puts "Contact found: name => #{contact[:name]}, email => #{contact[:email]}"
|
125
176
|
end
|
@@ -142,8 +193,8 @@ importer :gmail, "xxx", "yyy", :max_results => 1000
|
|
142
193
|
|
143
194
|
Yahoo requires you to configure the Permissions your application requires. Make sure to go the Yahoo website and to select Read permission for Contacts.
|
144
195
|
|
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.
|
196
|
+
Hotmail presents a "peculiar" feature. Their API returns a Contact object which does not contain an e-mail field!
|
197
|
+
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
198
|
This means that it may happen that an Hotmail contact does not contain the email field.
|
148
199
|
|
149
200
|
## Integration Testing
|
@@ -175,25 +226,51 @@ Follows a full example of an integration test:
|
|
175
226
|
|
176
227
|
## Working on localhost
|
177
228
|
|
178
|
-
Since Hotmail and Facebook do not allow the usage of `localhost` as redirect path for the authorization step, a workaround is to use
|
179
|
-
This
|
229
|
+
Since Hotmail and Facebook do not allow the usage of `localhost` as redirect path for the authorization step, a workaround is to use `ngrok`.
|
230
|
+
This is really useful when you need someone, the contacts provider in this case, to access your locally running application using a unique url.
|
231
|
+
|
232
|
+
Install ngrok, download from:
|
180
233
|
|
181
|
-
|
234
|
+
https://ngrok.com/
|
235
|
+
|
236
|
+
https://github.com/inconshreveable/ngrok
|
237
|
+
|
238
|
+
Unzip the file
|
182
239
|
```bash
|
183
|
-
|
240
|
+
unzip /place/this/is/ngrok.zip
|
184
241
|
```
|
242
|
+
Start your application
|
243
|
+
```bash
|
244
|
+
$ rails server
|
185
245
|
|
186
|
-
|
246
|
+
=> Booting WEBrick
|
247
|
+
=> Rails 4.0.4 application starting in development on http://0.0.0.0:3000
|
248
|
+
```
|
249
|
+
|
250
|
+
In a new terminal window, start the tunnel and pass the port where your application is running:
|
187
251
|
```bash
|
188
|
-
|
252
|
+
./ngrok 3000
|
189
253
|
```
|
190
254
|
|
191
|
-
Check the output to see something like
|
255
|
+
Check the output to see something like
|
192
256
|
```bash
|
193
|
-
|
257
|
+
ngrok (Ctrl+C to quit)
|
258
|
+
|
259
|
+
Tunnel Status online
|
260
|
+
Version 1.6/1.5
|
261
|
+
Forwarding http://274101c1e.ngrok.com -> 127.0.0.1:3000
|
262
|
+
Forwarding https://274101c1e.ngrok.com -> 127.0.0.1:3000
|
263
|
+
Web Interface 127.0.0.1:4040
|
264
|
+
# Conn 0
|
265
|
+
Avg Conn Time 0.00ms
|
194
266
|
```
|
195
267
|
|
196
|
-
|
268
|
+
This window will show all network transaction that your locally hosted application is processing.
|
269
|
+
Ngrok will process all of the requests and responses on your localhost. Visit:
|
270
|
+
|
271
|
+
```bash
|
272
|
+
http://123456789.ngrok.com # replace 123456789 with your instance
|
273
|
+
```
|
197
274
|
|
198
275
|
## Example application
|
199
276
|
|
@@ -201,8 +278,8 @@ Thanks to @sonianand11, you can find a full example of a Rails application using
|
|
201
278
|
|
202
279
|
## Thanks
|
203
280
|
|
204
|
-
As already mentioned above, a special thanks goes to @sonianand11 for implementing an example app.
|
205
|
-
Thanks also to @asmatameem for
|
281
|
+
As already mentioned above, a special thanks goes to @sonianand11 for implementing an example app.
|
282
|
+
Thanks also to @asmatameem for her huge contribution. She indeed added support for Facebook and for many fields which were missing before.
|
206
283
|
|
207
284
|
## License
|
208
285
|
|
data/lib/omnicontacts.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module OmniContacts
|
2
2
|
|
3
|
-
VERSION = "0.3.
|
3
|
+
VERSION = "0.3.5"
|
4
|
+
|
5
|
+
MOUNT_PATH = "/contacts/"
|
4
6
|
|
5
7
|
autoload :Builder, "omnicontacts/builder"
|
6
8
|
autoload :Importer, "omnicontacts/importer"
|
@@ -8,7 +10,8 @@ module OmniContacts
|
|
8
10
|
|
9
11
|
class AuthorizationError < RuntimeError
|
10
12
|
end
|
11
|
-
|
13
|
+
|
14
|
+
|
12
15
|
def self.integration_test
|
13
16
|
IntegrationTest.instance
|
14
17
|
end
|
@@ -22,22 +22,30 @@ module OmniContacts
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def fetch_contacts_using_access_token access_token, access_token_secret
|
25
|
-
self_response =
|
26
|
-
|
25
|
+
self_response = fetch_current_user access_token
|
26
|
+
user = current_user self_response
|
27
|
+
set_current_user user
|
28
|
+
spouse_id = extract_spouse_id self_response
|
27
29
|
spouse_response = nil
|
28
30
|
if spouse_id
|
29
31
|
spouse_path = "/#{spouse_id}"
|
30
32
|
spouse_response = https_get(@contacts_host, spouse_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture'})
|
31
33
|
end
|
32
|
-
family_response = https_get(@contacts_host, @family_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture'})
|
34
|
+
family_response = https_get(@contacts_host, @family_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture,relationship'})
|
33
35
|
friends_response = https_get(@contacts_host, @friends_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture'})
|
34
36
|
contacts_from_response(spouse_response, family_response, friends_response)
|
35
37
|
end
|
36
38
|
|
39
|
+
def fetch_current_user access_token
|
40
|
+
self_response = https_get(@contacts_host, @self_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture,relationship_status,significant_other,email'})
|
41
|
+
self_response = JSON.parse(self_response) if self_response
|
42
|
+
self_response
|
43
|
+
end
|
44
|
+
|
37
45
|
private
|
38
46
|
|
39
|
-
def extract_spouse_id
|
40
|
-
|
47
|
+
def extract_spouse_id response
|
48
|
+
return nil if response.nil?
|
41
49
|
id = nil
|
42
50
|
if response['significant_other'] && response['relationship_status'] == 'Married'
|
43
51
|
id = response['significant_other']['id']
|
@@ -79,17 +87,36 @@ module OmniContacts
|
|
79
87
|
contact[:name] = contact_info['name']
|
80
88
|
contact[:email] = contact_info['email']
|
81
89
|
contact[:gender] = contact_info['gender']
|
82
|
-
birthday =
|
83
|
-
contact[:
|
84
|
-
contact[:profile_picture] = contact_info['picture']['data']['url'] if contact_info['picture']
|
90
|
+
contact[:birthday] = birthday(contact_info['birthday'])
|
91
|
+
contact[:profile_picture] = image_url(contact_info['id'])
|
85
92
|
contact[:relation] = contact_info['relationship']
|
86
93
|
contact
|
87
94
|
end
|
88
95
|
|
96
|
+
def image_url fb_id
|
97
|
+
return "https://graph.facebook.com/" + fb_id + "/picture" if fb_id
|
98
|
+
end
|
99
|
+
|
89
100
|
def escape_windows_format value
|
90
101
|
value.gsub(/[\r\s]/, '')
|
91
102
|
end
|
92
103
|
|
104
|
+
def birthday dob
|
105
|
+
return nil if dob.nil?
|
106
|
+
birthday = dob.split('/')
|
107
|
+
return birthday_format(birthday[0],birthday[1],birthday[2])
|
108
|
+
end
|
109
|
+
|
110
|
+
def current_user me
|
111
|
+
return nil if me.nil?
|
112
|
+
user = {:id => me['id'], :email => me['email'],
|
113
|
+
:name => me['name'], :first_name => normalize_name(me['first_name']),
|
114
|
+
:last_name => normalize_name(me['last_name']), :birthday => birthday(me['birthday']),
|
115
|
+
:gender => me['gender'], :profile_picture => image_url(me['id'])
|
116
|
+
}
|
117
|
+
user
|
118
|
+
end
|
119
|
+
|
93
120
|
end
|
94
121
|
end
|
95
122
|
end
|
@@ -13,17 +13,26 @@ module OmniContacts
|
|
13
13
|
@auth_host = "accounts.google.com"
|
14
14
|
@authorize_path = "/o/oauth2/auth"
|
15
15
|
@auth_token_path = "/o/oauth2/token"
|
16
|
-
@scope = "https://www.google.com/m8/feeds"
|
16
|
+
@scope = "https://www.google.com/m8/feeds https://www.googleapis.com/auth/userinfo#email https://www.googleapis.com/auth/userinfo.profile"
|
17
17
|
@contacts_host = "www.google.com"
|
18
18
|
@contacts_path = "/m8/feeds/contacts/default/full"
|
19
19
|
@max_results = (args[3] && args[3][:max_results]) || 100
|
20
|
+
@self_host = "www.googleapis.com"
|
21
|
+
@profile_path = "/oauth2/v1/userinfo"
|
20
22
|
end
|
21
23
|
|
22
24
|
def fetch_contacts_using_access_token access_token, token_type
|
25
|
+
fetch_current_user(access_token, token_type)
|
23
26
|
contacts_response = https_get(@contacts_host, @contacts_path, contacts_req_params, contacts_req_headers(access_token, token_type))
|
24
27
|
contacts_from_response contacts_response
|
25
28
|
end
|
26
29
|
|
30
|
+
def fetch_current_user access_token, token_type
|
31
|
+
self_response = https_get(@self_host, @profile_path, contacts_req_params, contacts_req_headers(access_token, token_type))
|
32
|
+
user = current_user(self_response, access_token, token_type)
|
33
|
+
set_current_user user
|
34
|
+
end
|
35
|
+
|
27
36
|
private
|
28
37
|
|
29
38
|
def contacts_req_params
|
@@ -38,9 +47,25 @@ module OmniContacts
|
|
38
47
|
response = JSON.parse(response_as_json)
|
39
48
|
return [] if response['feed'].nil? || response['feed']['entry'].nil?
|
40
49
|
contacts = []
|
50
|
+
return contacts if response.nil?
|
41
51
|
response['feed']['entry'].each do |entry|
|
42
52
|
# creating nil fields to keep the fields consistent across other networks
|
43
|
-
|
53
|
+
|
54
|
+
contact = { :id => nil,
|
55
|
+
:first_name => nil,
|
56
|
+
:last_name => nil,
|
57
|
+
:name => nil,
|
58
|
+
:emails => nil,
|
59
|
+
:gender => nil,
|
60
|
+
:birthday => nil,
|
61
|
+
:profile_picture=> nil,
|
62
|
+
:relation => nil,
|
63
|
+
:addresses => nil,
|
64
|
+
:phone_numbers => nil,
|
65
|
+
:dates => nil,
|
66
|
+
:company => nil,
|
67
|
+
:position => nil
|
68
|
+
}
|
44
69
|
contact[:id] = entry['id']['$t'] if entry['id']
|
45
70
|
if entry['gd$name']
|
46
71
|
gd_name = entry['gd$name']
|
@@ -50,25 +75,136 @@ module OmniContacts
|
|
50
75
|
contact[:name] = full_name(contact[:first_name],contact[:last_name]) if contact[:name].nil?
|
51
76
|
end
|
52
77
|
|
53
|
-
contact[:
|
78
|
+
contact[:emails] = []
|
79
|
+
entry['gd$email'].each do |email|
|
80
|
+
if email['rel']
|
81
|
+
split_index = email['rel'].index('#')
|
82
|
+
contact[:emails] << {:name => email['rel'][split_index + 1, email['rel'].length - 1], :email => email['address']}
|
83
|
+
elsif email['label']
|
84
|
+
contact[:emails] << {:name => email['label'], :email => email['address']}
|
85
|
+
end
|
86
|
+
end if entry['gd$email']
|
87
|
+
|
88
|
+
# Support older versions of the gem by keeping singular entries around
|
89
|
+
contact[:email] = contact[:emails][0][:email] if contact[:emails][0]
|
54
90
|
contact[:first_name], contact[:last_name], contact[:name] = email_to_name(contact[:name]) if !contact[:name].nil? && contact[:name].include?('@')
|
55
|
-
contact[:first_name], contact[:last_name], contact[:name] = email_to_name(contact[:email]) if contact[:name].nil? && contact[:email]
|
91
|
+
contact[:first_name], contact[:last_name], contact[:name] = email_to_name(contact[:emails][0][:email]) if contact[:name].nil? && contact[:emails][0][:email]
|
56
92
|
#format - year-month-date
|
57
|
-
if entry['gContact$birthday']
|
58
|
-
|
59
|
-
contact[:birthday] = birthday_format(birthday[2], birthday[3], nil) if birthday.size == 4
|
60
|
-
contact[:birthday] = birthday_format(birthday[1], birthday[2], birthday[0]) if birthday.size == 3
|
61
|
-
end
|
93
|
+
contact[:birthday] = birthday(entry['gContact$birthday']['when']) if entry['gContact$birthday']
|
94
|
+
|
62
95
|
# value is either "male" or "female"
|
63
96
|
contact[:gender] = entry['gContact$gender']['value'] if entry['gContact$gender']
|
64
|
-
|
97
|
+
|
98
|
+
if entry['gContact$relation']
|
99
|
+
if entry['gContact$relation'].is_a?(Hash)
|
100
|
+
contact[:relation] = entry['gContact$relation']['rel']
|
101
|
+
elsif entry['gContact$relation'].is_a?(Array)
|
102
|
+
contact[:relation] = entry['gContact$relation'].first['rel']
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
contact[:addresses] = []
|
107
|
+
entry['gd$structuredPostalAddress'].each do |address|
|
108
|
+
if address['rel']
|
109
|
+
split_index = address['rel'].index('#')
|
110
|
+
new_address = {:name => address['rel'][split_index + 1, address['rel'].length - 1]}
|
111
|
+
elsif address['label']
|
112
|
+
new_address = {:name => address['label']}
|
113
|
+
end
|
114
|
+
|
115
|
+
new_address[:address_1] = address['gd$street']['$t'] if address['gd$street']
|
116
|
+
new_address[:address_1] = address['gd$formattedAddress']['$t'] if new_address[:address_1].nil? && address['gd$formattedAddress']
|
117
|
+
if new_address[:address_1].index("\n")
|
118
|
+
parts = new_address[:address_1].split("\n")
|
119
|
+
new_address[:address_1] = parts.first
|
120
|
+
# this may contain city/state/zip if user jammed it all into one string.... :-(
|
121
|
+
new_address[:address_2] = parts[1..-1].join(', ')
|
122
|
+
end
|
123
|
+
new_address[:city] = address['gd$city']['$t'] if address['gd$city']
|
124
|
+
new_address[:region] = address['gd$region']['$t'] if address['gd$region'] # like state or province
|
125
|
+
new_address[:country] = address['gd$country']['code'] if address['gd$country']
|
126
|
+
new_address[:postcode] = address['gd$postcode']['$t'] if address['gd$postcode']
|
127
|
+
contact[:addresses] << new_address
|
128
|
+
end if entry['gd$structuredPostalAddress']
|
129
|
+
|
130
|
+
# Support older versions of the gem by keeping singular entries around
|
131
|
+
if contact[:addresses][0]
|
132
|
+
contact[:address_1] = contact[:addresses][0][:address_1]
|
133
|
+
contact[:address_2] = contact[:addresses][0][:address_2]
|
134
|
+
contact[:city] = contact[:addresses][0][:city]
|
135
|
+
contact[:region] = contact[:addresses][0][:region]
|
136
|
+
contact[:country] = contact[:addresses][0][:country]
|
137
|
+
contact[:postcode] = contact[:addresses][0][:postcode]
|
138
|
+
end
|
139
|
+
|
140
|
+
contact[:phone_numbers] = []
|
141
|
+
entry['gd$phoneNumber'].each do |phone_number|
|
142
|
+
if phone_number['rel']
|
143
|
+
split_index = phone_number['rel'].index('#')
|
144
|
+
contact[:phone_numbers] << {:name => phone_number['rel'][split_index + 1, phone_number['rel'].length - 1], :number => phone_number['$t']}
|
145
|
+
elsif phone_number['label']
|
146
|
+
contact[:phone_numbers] << {:name => phone_number['label'], :number => phone_number['$t']}
|
147
|
+
end
|
148
|
+
end if entry['gd$phoneNumber']
|
149
|
+
|
150
|
+
# Support older versions of the gem by keeping singular entries around
|
151
|
+
contact[:phone_number] = contact[:phone_numbers][0][:number] if contact[:phone_numbers][0]
|
152
|
+
|
153
|
+
if entry['gContact$website'] && entry['gContact$website'][0]["rel"] == "profile"
|
154
|
+
contact[:id] = contact_id(entry['gContact$website'][0]["href"])
|
155
|
+
contact[:profile_picture] = image_url(contact[:id])
|
156
|
+
else
|
157
|
+
contact[:profile_picture] = image_url_from_email(contact[:email])
|
158
|
+
end
|
159
|
+
|
160
|
+
if entry['gContact$event']
|
161
|
+
contact[:dates] = []
|
162
|
+
entry['gContact$event'].each do |event|
|
163
|
+
if event['rel']
|
164
|
+
contact[:dates] << {:name => event['rel'], :date => birthday(event['gd$when']['startTime'])}
|
165
|
+
elsif event['label']
|
166
|
+
contact[:dates] << {:name => event['label'], :date => birthday(event['gd$when']['startTime'])}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
if entry['gd$organization']
|
172
|
+
contact[:company] = entry['gd$organization'][0]['gd$orgName']['$t'] if entry['gd$organization'][0]['gd$orgName']
|
173
|
+
contact[:position] = entry['gd$organization'][0]['gd$orgTitle']['$t'] if entry['gd$organization'][0]['gd$orgTitle']
|
174
|
+
end
|
65
175
|
|
66
176
|
contacts << contact if contact[:name]
|
67
177
|
end
|
68
|
-
contacts.uniq! {|c| c[:email] || c[:name]}
|
178
|
+
contacts.uniq! {|c| c[:email] || c[:profile_picture] || c[:name]}
|
69
179
|
contacts
|
70
180
|
end
|
71
181
|
|
182
|
+
def image_url gmail_id
|
183
|
+
return "https://profiles.google.com/s2/photos/profile/" + gmail_id if gmail_id
|
184
|
+
end
|
185
|
+
|
186
|
+
def current_user me, access_token, token_type
|
187
|
+
return nil if me.nil?
|
188
|
+
me = JSON.parse(me)
|
189
|
+
user = {:id => me['id'], :email => me['email'], :name => me['name'], :first_name => me['given_name'],
|
190
|
+
:last_name => me['family_name'], :gender => me['gender'], :birthday => birthday(me['birthday']), :profile_picture => image_url(me['id']),
|
191
|
+
:access_token => access_token, :token_type => token_type
|
192
|
+
}
|
193
|
+
user
|
194
|
+
end
|
195
|
+
|
196
|
+
def birthday dob
|
197
|
+
return nil if dob.nil?
|
198
|
+
birthday = dob.split('-')
|
199
|
+
return birthday_format(birthday[2], birthday[3], nil) if birthday.size == 4
|
200
|
+
return birthday_format(birthday[1], birthday[2], birthday[0]) if birthday.size == 3
|
201
|
+
end
|
202
|
+
|
203
|
+
def contact_id(profile_url)
|
204
|
+
id = (profile_url.present?) ? File.basename(profile_url) : nil
|
205
|
+
id
|
206
|
+
end
|
207
|
+
|
72
208
|
end
|
73
209
|
end
|
74
210
|
end
|