omnicontacts 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/omnicontacts.rb +1 -1
- data/lib/omnicontacts/authorization/oauth2.rb +3 -0
- data/lib/omnicontacts/http_utils.rb +38 -1
- data/lib/omnicontacts/importer.rb +1 -0
- data/lib/omnicontacts/importer/facebook.rb +93 -0
- data/lib/omnicontacts/importer/gmail.rb +29 -15
- data/lib/omnicontacts/importer/hotmail.rb +16 -7
- data/lib/omnicontacts/importer/yahoo.rb +44 -29
- data/spec/omnicontacts/authorization/oauth1_spec.rb +1 -1
- data/spec/omnicontacts/authorization/oauth2_spec.rb +2 -2
- data/spec/omnicontacts/http_utils_spec.rb +1 -1
- data/spec/omnicontacts/importer/facebook_spec.rb +58 -0
- data/spec/omnicontacts/importer/gmail_spec.rb +65 -25
- data/spec/omnicontacts/importer/hotmail_spec.rb +27 -18
- data/spec/omnicontacts/importer/yahoo_spec.rb +26 -9
- data/spec/omnicontacts/integration_test_spec.rb +1 -1
- metadata +16 -14
data/lib/omnicontacts.rb
CHANGED
@@ -56,6 +56,9 @@ module OmniContacts
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def access_token_from_response response
|
59
|
+
if auth_host == "graph.facebook.com"
|
60
|
+
response = query_string_to_map(response).to_json
|
61
|
+
end
|
59
62
|
json = JSON.parse(response)
|
60
63
|
raise json["error"] if json["error"]
|
61
64
|
[json["access_token"], json["token_type"], json["refresh_token"]]
|
@@ -11,6 +11,43 @@ module OmniContacts
|
|
11
11
|
|
12
12
|
module_function
|
13
13
|
|
14
|
+
# return has of birthday day, month and year
|
15
|
+
def birthday_format month, day, year
|
16
|
+
return {:day => day.to_i, :month => month.to_i, :year => year.to_i}if year && month && day
|
17
|
+
return {:day => day.to_i, :month => month.to_i, :year => nil} if !year && month && day
|
18
|
+
return nil if (!year && !month) || (!year && !day)
|
19
|
+
end
|
20
|
+
|
21
|
+
# normalize the name
|
22
|
+
def normalize_name name
|
23
|
+
return nil if name.nil?
|
24
|
+
name.chomp!
|
25
|
+
name = name.split(' ').map(&:capitalize).join(' ')
|
26
|
+
name.squeeze!(' ')
|
27
|
+
name.strip!
|
28
|
+
return name
|
29
|
+
end
|
30
|
+
|
31
|
+
# create a full name given the individual first and last name
|
32
|
+
def full_name first_name, last_name
|
33
|
+
return "#{first_name} #{last_name}" if first_name && last_name
|
34
|
+
return "#{first_name}" if first_name && !last_name
|
35
|
+
return "#{last_name}" if !first_name && last_name
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# create a username/name from a given email
|
40
|
+
def email_to_name username_or_email
|
41
|
+
username_or_email = username_or_email.split('@').first if username_or_email.include?('@')
|
42
|
+
if group = (/(?<first>[a-z|A-Z]+)[\.|_](?<last>[a-z|A-Z]+)/).match(username_or_email)
|
43
|
+
first_name = normalize_name(group[:first])
|
44
|
+
last_name = normalize_name(group[:last])
|
45
|
+
return first_name, last_name, "#{first_name} #{last_name}"
|
46
|
+
end
|
47
|
+
username = normalize_name(username_or_email)
|
48
|
+
return username, nil, username
|
49
|
+
end
|
50
|
+
|
14
51
|
def query_string_to_map query_string
|
15
52
|
query_string.split('&').reduce({}) do |memo, key_value|
|
16
53
|
(key, value) = key_value.split('=')
|
@@ -74,7 +111,7 @@ module OmniContacts
|
|
74
111
|
|
75
112
|
# Executes an HTTP GET request over SSL
|
76
113
|
# It raises a RuntimeError if the response code is not equal to 200
|
77
|
-
def https_get host, path, params, headers =
|
114
|
+
def https_get host, path, params, headers = nil
|
78
115
|
https_connection host do |connection|
|
79
116
|
connection.request_get(path + "?" + to_query_string(params), headers)
|
80
117
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require "omnicontacts/middleware/oauth2"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module OmniContacts
|
5
|
+
module Importer
|
6
|
+
class Facebook < Middleware::OAuth2
|
7
|
+
|
8
|
+
attr_reader :auth_host, :authorize_path, :auth_token_path, :scope
|
9
|
+
|
10
|
+
def initialize *args
|
11
|
+
super *args
|
12
|
+
@auth_host = 'graph.facebook.com'
|
13
|
+
@authorize_path = '/oauth/authorize'
|
14
|
+
@scope = 'email,user_relationships,user_birthday,friends_birthday'
|
15
|
+
@auth_token_path = '/oauth/access_token'
|
16
|
+
@contacts_host = 'graph.facebook.com'
|
17
|
+
@friends_path = '/me/friends'
|
18
|
+
@family_path = '/me/family'
|
19
|
+
@self_path = '/me'
|
20
|
+
end
|
21
|
+
|
22
|
+
def fetch_contacts_using_access_token access_token, access_token_secret
|
23
|
+
self_response = https_get(@contacts_host, @self_path, :access_token => access_token)
|
24
|
+
spouse_id = extract_spouse_id(self_response)
|
25
|
+
spouse_response = nil
|
26
|
+
if spouse_id
|
27
|
+
spouse_path = "/#{spouse_id}"
|
28
|
+
spouse_response = https_get(@contacts_host, spouse_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture'})
|
29
|
+
end
|
30
|
+
family_response = https_get(@contacts_host, @family_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture'})
|
31
|
+
friends_response = https_get(@contacts_host, @friends_path, {:access_token => access_token, :fields => 'first_name,last_name,name,id,gender,birthday,picture'})
|
32
|
+
contacts_from_response(spouse_response, family_response, friends_response)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def extract_spouse_id self_response
|
38
|
+
response = JSON.parse(self_response)
|
39
|
+
id = nil
|
40
|
+
if response['significant_other'] && response['relationship_status'] == 'Married'
|
41
|
+
id = response['significant_other']['id']
|
42
|
+
end
|
43
|
+
id
|
44
|
+
end
|
45
|
+
|
46
|
+
def contacts_from_response(spouse_response, family_response, friends_response)
|
47
|
+
contacts = []
|
48
|
+
family_ids = Set.new
|
49
|
+
if spouse_response
|
50
|
+
spouse_contact = create_contact_element(JSON.parse(spouse_response))
|
51
|
+
spouse_contact[:relation] = 'spouse'
|
52
|
+
contacts << spouse_contact
|
53
|
+
family_ids.add(spouse_contact[:id])
|
54
|
+
end
|
55
|
+
if family_response
|
56
|
+
family_response = JSON.parse(family_response)
|
57
|
+
family_response['data'].each do |family_contact|
|
58
|
+
contacts << create_contact_element(family_contact)
|
59
|
+
family_ids.add(family_contact['id'])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if friends_response
|
63
|
+
friends_response = JSON.parse(friends_response)
|
64
|
+
friends_response['data'].each do |friends_contact|
|
65
|
+
contacts << create_contact_element(friends_contact) unless family_ids.include?(friends_contact['id'])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
contacts
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_contact_element contact_info
|
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}
|
74
|
+
contact[:id] = contact_info['id']
|
75
|
+
contact[:first_name] = normalize_name(contact_info['first_name'])
|
76
|
+
contact[:last_name] = normalize_name(contact_info['last_name'])
|
77
|
+
contact[:name] = contact_info['name']
|
78
|
+
contact[:email] = contact_info['email']
|
79
|
+
contact[:gender] = contact_info['gender']
|
80
|
+
birthday = contact_info['birthday'].split('/') if contact_info['birthday']
|
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']
|
83
|
+
contact[:relation] = contact_info['relationship']
|
84
|
+
contact
|
85
|
+
end
|
86
|
+
|
87
|
+
def escape_windows_format value
|
88
|
+
value.gsub(/[\r\s]/, '')
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require "omnicontacts/middleware/oauth2"
|
2
|
-
require "rexml/document"
|
3
2
|
|
4
3
|
module OmniContacts
|
5
4
|
module Importer
|
@@ -20,34 +19,49 @@ module OmniContacts
|
|
20
19
|
|
21
20
|
def fetch_contacts_using_access_token access_token, token_type
|
22
21
|
contacts_response = https_get(@contacts_host, @contacts_path, contacts_req_params, contacts_req_headers(access_token, token_type))
|
23
|
-
|
22
|
+
contacts_from_response contacts_response
|
24
23
|
end
|
25
24
|
|
26
25
|
private
|
27
26
|
|
28
27
|
def contacts_req_params
|
29
|
-
{
|
28
|
+
{'max-results' => @max_results.to_s, 'alt' => 'json'}
|
30
29
|
end
|
31
30
|
|
32
31
|
def contacts_req_headers token, token_type
|
33
32
|
{"GData-Version" => "3.0", "Authorization" => "#{token_type} #{token}"}
|
34
33
|
end
|
35
34
|
|
36
|
-
def
|
37
|
-
|
35
|
+
def contacts_from_response response_as_json
|
36
|
+
response = JSON.parse(response_as_json)
|
38
37
|
contacts = []
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
if
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
contacts << contact
|
38
|
+
response['feed']['entry'].each do |entry|
|
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}
|
41
|
+
contact[:id] = entry['id']['$t'] if entry['id']
|
42
|
+
if entry['gd$name']
|
43
|
+
contact[:first_name] = normalize_name(entry['gd$name']['gd$givenName']['$t']) if entry['gd$name']['gd$givenName']
|
44
|
+
contact[:last_name] = normalize_name(entry['gd$name']['gd$familyName']['$t']) if entry['gd$name']['gd$familyName']
|
45
|
+
contact[:name] = normalize_name(entry['gd$name']['gd$fullName']['$t']) if entry['gd$name']['gd$fullName']
|
46
|
+
contact[:name] = full_name(contact[:first_name],contact[:last_name]) if contact[:name].nil?
|
49
47
|
end
|
48
|
+
|
49
|
+
contact[:email] = entry['gd$email'][0]['address'] if entry['gd$email']
|
50
|
+
contact[:first_name], contact[:last_name], contact[:name] = email_to_name(contact[:name]) if !contact[:name].nil? && contact[:name].include?('@')
|
51
|
+
contact[:first_name], contact[:last_name], contact[:name] = email_to_name(contact[:email]) if contact[:name].nil? && contact[:email]
|
52
|
+
#format - year-month-date
|
53
|
+
if entry['gContact$birthday']
|
54
|
+
birthday = entry['gContact$birthday']['when'].split('-')
|
55
|
+
contact[:birthday] = birthday_format(birthday[2], birthday[3], nil) if birthday.size == 4
|
56
|
+
contact[:birthday] = birthday_format(birthday[1], birthday[2], birthday[0]) if birthday.size == 3
|
57
|
+
end
|
58
|
+
# value is either "male" or "female"
|
59
|
+
contact[:gender] = entry['gContact$gender']['value'] if entry['gContact$gender']
|
60
|
+
contact[:relation] = entry['gContact$relation']['rel'] if entry['gContact$relation']
|
61
|
+
|
62
|
+
contacts << contact if contact[:name]
|
50
63
|
end
|
64
|
+
contacts.uniq! {|c| c[:email] || c[:name]}
|
51
65
|
contacts
|
52
66
|
end
|
53
67
|
|
@@ -11,7 +11,7 @@ module OmniContacts
|
|
11
11
|
super *args
|
12
12
|
@auth_host = "oauth.live.com"
|
13
13
|
@authorize_path = "/authorize"
|
14
|
-
@scope = "wl.basic"
|
14
|
+
@scope = "wl.signin, wl.basic, wl.birthday , wl.emails ,wl.contacts_birthday , wl.contacts_photos"
|
15
15
|
@auth_token_path = "/token"
|
16
16
|
@contacts_host = "apis.live.net"
|
17
17
|
@contacts_path = "/v5.0/me/contacts"
|
@@ -24,13 +24,22 @@ module OmniContacts
|
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
def contacts_from_response
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
def contacts_from_response response_as_json
|
28
|
+
response = JSON.parse(response_as_json)
|
29
|
+
contacts = []
|
30
|
+
response['data'].each do |entry|
|
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}
|
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'])
|
37
|
+
contact[:birthday] = birthday_format(entry['birth_month'], entry['birth_day'], entry['birth_year'])
|
38
|
+
contact[:gender] = entry['gender']
|
39
|
+
contact[:image_source] = 'https://apis.live.net/v5.0/' + entry['user_id'] + '/picture' if entry['user_id']
|
40
|
+
contacts << contact if contact[:name] || contact[:first_name]
|
32
41
|
end
|
33
|
-
|
42
|
+
contacts
|
34
43
|
end
|
35
44
|
|
36
45
|
def escape_windows_format value
|
@@ -9,15 +9,15 @@ module OmniContacts
|
|
9
9
|
|
10
10
|
def initialize *args
|
11
11
|
super *args
|
12
|
-
@auth_host =
|
13
|
-
@auth_token_path =
|
14
|
-
@auth_path =
|
15
|
-
@access_token_path =
|
16
|
-
@contacts_host =
|
12
|
+
@auth_host = 'api.login.yahoo.com'
|
13
|
+
@auth_token_path = '/oauth/v2/get_request_token'
|
14
|
+
@auth_path = '/oauth/v2/request_auth'
|
15
|
+
@access_token_path = '/oauth/v2/get_token'
|
16
|
+
@contacts_host = 'social.yahooapis.com'
|
17
17
|
end
|
18
18
|
|
19
19
|
def fetch_contacts_from_token_and_verifier auth_token, auth_token_secret, auth_verifier
|
20
|
-
(access_token, access_token_secret, guid) = fetch_access_token(auth_token, auth_token_secret, auth_verifier, [
|
20
|
+
(access_token, access_token_secret, guid) = fetch_access_token(auth_token, auth_token_secret, auth_verifier, ['xoauth_yahoo_guid'])
|
21
21
|
contacts_path = "/v1/user/#{guid}/contacts"
|
22
22
|
contacts_response = http_get(@contacts_host, contacts_path, contacts_req_params(access_token, access_token_secret, contacts_path))
|
23
23
|
contacts_from_response contacts_response
|
@@ -27,37 +27,52 @@ module OmniContacts
|
|
27
27
|
|
28
28
|
def contacts_req_params access_token, access_token_secret, contacts_path
|
29
29
|
params = {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
:format => 'json',
|
31
|
+
:oauth_consumer_key => consumer_key,
|
32
|
+
:oauth_nonce => encode(random_string),
|
33
|
+
:oauth_signature_method => 'HMAC-SHA1',
|
34
|
+
:oauth_timestamp => timestamp,
|
35
|
+
:oauth_token => access_token,
|
36
|
+
:oauth_version => OmniContacts::Authorization::OAuth1::OAUTH_VERSION,
|
37
|
+
:view => 'compact'
|
38
38
|
}
|
39
39
|
contacts_url = "http://#{@contacts_host}#{contacts_path}"
|
40
|
-
params[
|
40
|
+
params['oauth_signature'] = oauth_signature('GET', contacts_url, params, access_token_secret)
|
41
41
|
params
|
42
42
|
end
|
43
43
|
|
44
|
-
def contacts_from_response
|
45
|
-
|
46
|
-
|
47
|
-
return
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
contact[:
|
44
|
+
def contacts_from_response response_as_json
|
45
|
+
response = JSON.parse(response_as_json)
|
46
|
+
contacts = []
|
47
|
+
return contacts unless response['contacts']['contact']
|
48
|
+
response['contacts']['contact'].each do |entry|
|
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}
|
51
|
+
yahoo_id = nil
|
52
|
+
contact[:id] = entry['id'].to_s
|
53
|
+
entry['fields'].each do |field|
|
54
|
+
if field['type'] == 'name'
|
55
|
+
contact[:first_name] = normalize_name(field['value']['givenName'])
|
56
|
+
contact[:last_name] = normalize_name(field['value']['familyName'])
|
57
|
+
contact[:name] = full_name(contact[:first_name],contact[:last_name])
|
58
|
+
end
|
59
|
+
contact[:email] = field['value'] if field['type'] == 'email'
|
60
|
+
|
61
|
+
if field['type'] == 'yahooid'
|
62
|
+
yahoo_id = field['value']
|
63
|
+
end
|
64
|
+
|
65
|
+
contact[:first_name], contact[:last_name], contact[:name] = email_to_name(contact[:email]) if contact[:name].nil? && contact[:email]
|
66
|
+
# contact[:first_name], contact[:last_name], contact[:name] = email_to_name(yahoo_id) if (yahoo_id && contact[:name].nil? && contact[:email].nil?)
|
67
|
+
|
68
|
+
if field['type'] == 'birthday'
|
69
|
+
contact[:birthday] = birthday_format(field['value']['month'], field['value']['day'],field['value']['year'])
|
56
70
|
end
|
57
71
|
end
|
58
|
-
|
72
|
+
contacts << contact if contact[:name]
|
59
73
|
end
|
60
|
-
|
74
|
+
contacts.uniq! {|c| c[:email] || c[:name]}
|
75
|
+
contacts
|
61
76
|
end
|
62
77
|
|
63
78
|
end
|
@@ -39,7 +39,7 @@ describe OmniContacts::Authorization::OAuth1 do
|
|
39
39
|
|
40
40
|
it "should raise an error if request is invalid" do
|
41
41
|
test_target.should_receive(:https_post).and_return("invalid_request")
|
42
|
-
expect { test_target.fetch_authorization_token }.
|
42
|
+
expect { test_target.fetch_authorization_token }.to raise_error
|
43
43
|
end
|
44
44
|
|
45
45
|
end
|
@@ -55,12 +55,12 @@ describe OmniContacts::Authorization::OAuth2 do
|
|
55
55
|
|
56
56
|
it "should raise if the http request fails" do
|
57
57
|
test_target.should_receive(:https_post).and_raise("Invalid code")
|
58
|
-
expect { test_target.fetch_access_token("code") }.
|
58
|
+
expect { test_target.fetch_access_token("code") }.to raise_error
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should raise an error if the JSON response contains an error field" do
|
62
62
|
test_target.should_receive(:https_post).and_return(%[{"error": "error_message"}])
|
63
|
-
expect { test_target.fetch_access_token("code") }.
|
63
|
+
expect { test_target.fetch_access_token("code") }.to raise_error
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
@@ -67,7 +67,7 @@ describe OmniContacts::HTTPUtils do
|
|
67
67
|
@connection.should_receive(:request_get).and_return(@response)
|
68
68
|
@response.should_receive(:code).and_return("500")
|
69
69
|
@response.should_receive(:body).and_return("some error message")
|
70
|
-
expect { @test_target.send(:https_get, "host", "path", {}) }.
|
70
|
+
expect { @test_target.send(:https_get, "host", "path", {}) }.to raise_error
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "omnicontacts/importer/facebook"
|
3
|
+
|
4
|
+
describe OmniContacts::Importer::Facebook do
|
5
|
+
|
6
|
+
let(:facebook) { OmniContacts::Importer::Facebook.new({}, "client_id", "client_secret") }
|
7
|
+
|
8
|
+
let(:contacts_as_json) {
|
9
|
+
'{"data":[
|
10
|
+
{
|
11
|
+
"first_name":"John",
|
12
|
+
"last_name":"Smith",
|
13
|
+
"name":"John Smith",
|
14
|
+
"id":"608061886",
|
15
|
+
"gender":"male",
|
16
|
+
"birthday":"06/21",
|
17
|
+
"relationship":"cousin",
|
18
|
+
"picture":{"data":{"url":"http://profile.ak.fbcdn.net/hprofile-ak-snc6/186364_608061886_2089044200_q.jpg","is_silhouette":false}}
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}' }
|
22
|
+
|
23
|
+
describe "fetch_contacts_using_access_token" do
|
24
|
+
let(:token) { "token" }
|
25
|
+
let(:token_type) { "token_type" }
|
26
|
+
|
27
|
+
|
28
|
+
it "should request the contacts by providing the token in the url and fields params only for family and friends requests" do
|
29
|
+
facebook.should_receive(:https_get) do |host, path, params, headers|
|
30
|
+
params[:access_token].should eq(token)
|
31
|
+
params[:fields].should be_nil
|
32
|
+
contacts_as_json
|
33
|
+
end
|
34
|
+
facebook.should_receive(:https_get) do |host, path, params, headers|
|
35
|
+
params[:access_token].should eq(token)
|
36
|
+
params[:fields].should eq('first_name,last_name,name,id,gender,birthday,picture')
|
37
|
+
contacts_as_json
|
38
|
+
end.at_most(2).times
|
39
|
+
facebook.fetch_contacts_using_access_token token, token_type
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should correctly parse id, name,email,gender, birthday, image source and relation" do
|
43
|
+
3.times { facebook.should_receive(:https_get).and_return(contacts_as_json) }
|
44
|
+
result = facebook.fetch_contacts_using_access_token token, token_type
|
45
|
+
result.size.should be(1)
|
46
|
+
result.first[:id].should eq('608061886')
|
47
|
+
result.first[:first_name].should eq('John')
|
48
|
+
result.first[:last_name].should eq('Smith')
|
49
|
+
result.first[:name].should eq('John Smith')
|
50
|
+
result.first[:email].should be_nil
|
51
|
+
result.first[:gender].should eq('male')
|
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')
|
54
|
+
result.first[:relation].should eq('cousin')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -5,24 +5,66 @@ describe OmniContacts::Importer::Gmail do
|
|
5
5
|
|
6
6
|
let(:gmail) { OmniContacts::Importer::Gmail.new({}, "client_id", "client_secret") }
|
7
7
|
|
8
|
-
let(:
|
9
|
-
"
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
let(:contacts_as_json) {
|
9
|
+
'{"version":"1.0","encoding":"UTF-8",
|
10
|
+
"feed":{
|
11
|
+
"xmlns":"http://www.w3.org/2005/Atom",
|
12
|
+
"xmlns$openSearch":"http://a9.com/-/spec/opensearch/1.1/",
|
13
|
+
"xmlns$gContact":"http://schemas.google.com/contact/2008",
|
14
|
+
"xmlns$batch":"http://schemas.google.com/gdata/batch",
|
15
|
+
"xmlns$gd":"http://schemas.google.com/g/2005",
|
16
|
+
"gd$etag":"W/\"C0YHRno7fSt7I2A9WhBSQ0Q.\"",
|
17
|
+
|
18
|
+
"id":{"$t":"logged_in_user@gmail.com"},
|
19
|
+
"updated":{"$t":"2013-02-20T20:12:17.405Z"},
|
20
|
+
"category":[{
|
21
|
+
"scheme":"http://schemas.google.com/g/2005#kind",
|
22
|
+
"term":"http://schemas.google.com/contact/2008#contact"
|
23
|
+
}],
|
16
24
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
25
|
+
"title":{"$t":"Users\'s Contacts"},
|
26
|
+
"link":[
|
27
|
+
{"rel":"alternate","type":"text/html","href":"http://www.google.com/"},
|
28
|
+
{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full"},
|
29
|
+
{"rel":"http://schemas.google.com/g/2005#post","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full"},
|
30
|
+
{"rel":"http://schemas.google.com/g/2005#batch","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full/batch"},
|
31
|
+
{"rel":"self","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full?alt\u003djson\u0026max-results\u003d1"},
|
32
|
+
{"rel":"next","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full?alt\u003djson\u0026start-index\u003d2\u0026max-results\u003d1"}
|
33
|
+
],
|
34
|
+
"author":[{"name":{"$t":"Asma"},"email":{"$t":"logged_in_user@gmail.com"}}],
|
35
|
+
"generator":{"version":"1.0","uri":"http://www.google.com/m8/feeds","$t":"Contacts"},
|
36
|
+
"openSearch$totalResults":{"$t":"1007"},
|
37
|
+
"openSearch$startIndex":{"$t":"1"},
|
38
|
+
"openSearch$itemsPerPage":{"$t":"1"},
|
39
|
+
"entry":[
|
40
|
+
{
|
41
|
+
"gd$etag":"\"R3oyfDVSLyt7I2A9WhBTSEULRA0.\"",
|
42
|
+
"id":{"$t":"http://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/base/1"},
|
43
|
+
"updated":{"$t":"2013-02-14T22:36:36.494Z"},
|
44
|
+
"app$edited":{"xmlns$app":"http://www.w3.org/2007/app","$t":"2013-02-14T22:36:36.494Z"},
|
45
|
+
"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/contact/2008#contact"}],
|
46
|
+
"title":{"$t":"Edward Bennet"},
|
47
|
+
"link":[
|
48
|
+
{"rel":"http://schemas.google.com/contacts/2008/rel#photo","type":"image/*","href":"https://www.google.com/m8/feeds/photos/media/logged_in_user%40gmail.com/1"},
|
49
|
+
{"rel":"self","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full/1"},
|
50
|
+
{"rel":"edit","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/full/1"}
|
51
|
+
],
|
52
|
+
"gd$name":{
|
53
|
+
"gd$fullName":{"$t":"Edward Bennet"},
|
54
|
+
"gd$givenName":{"$t":"Edward"},
|
55
|
+
"gd$familyName":{"$t":"Bennet"}
|
56
|
+
},
|
57
|
+
"gContact$birthday":{"when":"1954-07-02"},
|
58
|
+
"gContact$relation":{"rel":"father"},
|
59
|
+
"gContact$gender":{"value":"male"},
|
60
|
+
"gd$email":[{"rel":"http://schemas.google.com/g/2005#other","address":"bennet@gmail.com","primary":"true"}],
|
61
|
+
"gContact$groupMembershipInfo":[{"deleted":"false","href":"http://www.google.com/m8/feeds/groups/logged_in_user%40gmail.com/base/6"}]
|
62
|
+
}]
|
63
|
+
}
|
64
|
+
}'
|
22
65
|
}
|
23
66
|
|
24
67
|
describe "fetch_contacts_using_access_token" do
|
25
|
-
|
26
68
|
let(:token) { "token" }
|
27
69
|
let(:token_type) { "token_type" }
|
28
70
|
|
@@ -30,25 +72,23 @@ describe OmniContacts::Importer::Gmail do
|
|
30
72
|
gmail.should_receive(:https_get) do |host, path, params, headers|
|
31
73
|
headers["GData-Version"].should eq("3.0")
|
32
74
|
headers["Authorization"].should eq("#{token_type} #{token}")
|
33
|
-
|
75
|
+
contacts_as_json
|
34
76
|
end
|
35
77
|
gmail.fetch_contacts_using_access_token token, token_type
|
36
78
|
end
|
37
79
|
|
38
|
-
it "should correctly parse name and
|
39
|
-
gmail.should_receive(:https_get).and_return(
|
80
|
+
it "should correctly parse id, name,email,gender, birthday, image source and relation" do
|
81
|
+
gmail.should_receive(:https_get).and_return(contacts_as_json)
|
40
82
|
result = gmail.fetch_contacts_using_access_token token, token_type
|
41
83
|
result.size.should be(1)
|
84
|
+
result.first[:id].should eq('http://www.google.com/m8/feeds/contacts/logged_in_user%40gmail.com/base/1')
|
85
|
+
result.first[:first_name].should eq('Edward')
|
86
|
+
result.first[:last_name].should eq('Bennet')
|
42
87
|
result.first[:name].should eq("Edward Bennet")
|
43
88
|
result.first[:email].should eq("bennet@gmail.com")
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
gmail.should_receive(:https_get).and_return(contact_without_fullname)
|
48
|
-
result = gmail.fetch_contacts_using_access_token token, token_type
|
49
|
-
result.size.should be(1)
|
50
|
-
result.first[:name].should be_nil
|
51
|
-
result.first[:email].should eq("bennet@gmail.com")
|
89
|
+
result.first[:gender].should eq("male")
|
90
|
+
result.first[:birthday].should eq({:day=>02, :month=>07, :year=>1954})
|
91
|
+
result.first[:relation].should eq('father')
|
52
92
|
end
|
53
93
|
|
54
94
|
end
|
@@ -6,21 +6,23 @@ describe OmniContacts::Importer::Hotmail do
|
|
6
6
|
let(:hotmail) { OmniContacts::Importer::Hotmail.new({}, "client_id", "client_secret") }
|
7
7
|
|
8
8
|
let(:contacts_as_json) {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
9
|
+
'{
|
10
|
+
"data": [
|
11
|
+
{
|
12
|
+
"id": "contact.7fac34bb000000000000000000000000",
|
13
|
+
"first_name": "John",
|
14
|
+
"last_name": "Smith",
|
15
|
+
"name": "John Smith",
|
16
|
+
"gender": null,
|
17
|
+
"user_id": "123456",
|
18
|
+
"is_friend": false,
|
19
|
+
"is_favorite": false,
|
20
|
+
"birth_day": 5,
|
21
|
+
"birth_month": 6,
|
22
|
+
"birth_year":1952
|
23
|
+
}
|
24
|
+
]}'
|
25
|
+
}
|
24
26
|
|
25
27
|
describe "fetch_contacts_using_access_token" do
|
26
28
|
|
@@ -35,12 +37,19 @@ describe OmniContacts::Importer::Hotmail do
|
|
35
37
|
hotmail.fetch_contacts_using_access_token token, token_type
|
36
38
|
end
|
37
39
|
|
38
|
-
it "should correctly parse
|
40
|
+
it "should correctly parse id, name,email,gender, birthday, image source and relation" do
|
39
41
|
hotmail.should_receive(:https_get).and_return(contacts_as_json)
|
40
42
|
result = hotmail.fetch_contacts_using_access_token token, token_type
|
41
43
|
result.size.should be(1)
|
42
|
-
result.first[:
|
43
|
-
result.first[:
|
44
|
+
result.first[:id].should eq('123456')
|
45
|
+
result.first[:first_name].should eq("John")
|
46
|
+
result.first[:last_name].should eq('Smith')
|
47
|
+
result.first[:name].should eq("John Smith")
|
48
|
+
result.first[:email].should be_nil
|
49
|
+
result.first[:gender].should be_nil
|
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')
|
52
|
+
result.first[:relation].should be_nil
|
44
53
|
end
|
45
54
|
end
|
46
55
|
|
@@ -5,11 +5,23 @@ describe OmniContacts::Importer::Yahoo do
|
|
5
5
|
|
6
6
|
describe "fetch_contacts_from_token_and_verifier" do
|
7
7
|
let(:contacts_as_json) {
|
8
|
-
'{
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
'{
|
9
|
+
"contacts": {
|
10
|
+
"start":1,
|
11
|
+
"count":1,
|
12
|
+
"contact":[
|
13
|
+
{
|
14
|
+
"id":10,
|
15
|
+
"fields":[
|
16
|
+
{"id":819, "type":"email", "value":"johnny@yahoo.com"},
|
17
|
+
{"id":806,"type":"name","value":{"givenName":"John","middleName":"","familyName":"Smith"},"editedBy":"OWNER","categories":[]},
|
18
|
+
{"id":33555343,"type":"guid","value":"7ET6MYV2UQ6VR6CBSNMCLFJIVI"},
|
19
|
+
{"id":946,"type":"birthday","value":{"day":"22","month":"2","year":"1952"},"editedBy":"OWNER","categories":[]}
|
20
|
+
]
|
21
|
+
}
|
22
|
+
]
|
23
|
+
}
|
24
|
+
}' }
|
13
25
|
|
14
26
|
let(:yahoo) { OmniContacts::Importer::Yahoo.new({}, "consumer_key", "consumer_secret") }
|
15
27
|
|
@@ -29,13 +41,19 @@ describe OmniContacts::Importer::Yahoo do
|
|
29
41
|
yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
|
30
42
|
end
|
31
43
|
|
32
|
-
it "should parse
|
44
|
+
it "should correctly parse id, name,email,gender, birthday, image source and relation" do
|
33
45
|
yahoo.should_receive(:fetch_access_token).and_return(["access_token", "access_token_secret", "guid"])
|
34
46
|
yahoo.should_receive(:http_get).and_return(contacts_as_json)
|
35
47
|
result = yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
|
36
48
|
result.size.should be(1)
|
37
|
-
result.first[:
|
38
|
-
result.first[:
|
49
|
+
result.first[:id].should eq('10')
|
50
|
+
result.first[:first_name].should eq('John')
|
51
|
+
result.first[:last_name].should eq('Smith')
|
52
|
+
result.first[:name].should eq("John Smith")
|
53
|
+
result.first[:email].should eq("johnny@yahoo.com")
|
54
|
+
result.first[:gender].should be_nil
|
55
|
+
result.first[:birthday].should eq({:day=>22, :month=>2, :year=>1952})
|
56
|
+
result.first[:relation].should be_nil
|
39
57
|
end
|
40
58
|
|
41
59
|
it "should return an empty list of contacts" do
|
@@ -44,7 +62,6 @@ describe OmniContacts::Importer::Yahoo do
|
|
44
62
|
yahoo.should_receive(:http_get).and_return(empty_contacts_list)
|
45
63
|
result = yahoo.fetch_contacts_from_token_and_verifier "auth_token", "auth_token_secret", "oauth_verifier"
|
46
64
|
result.should be_empty
|
47
|
-
|
48
65
|
end
|
49
66
|
|
50
67
|
end
|
@@ -45,7 +45,7 @@ describe IntegrationTest do
|
|
45
45
|
|
46
46
|
it "should throw an exception" do
|
47
47
|
IntegrationTest.instance.mock('test', :some_error)
|
48
|
-
expect {IntegrationTest.instance.mock_fetch_contacts(@provider)}.
|
48
|
+
expect {IntegrationTest.instance.mock_fetch_contacts(@provider)}.to raise_error
|
49
49
|
end
|
50
50
|
end
|
51
51
|
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.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &2601350 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2601350
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &2600880 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2600880
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: simplecov
|
38
|
-
requirement: &
|
38
|
+
requirement: &2600430 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2600430
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
|
-
requirement: &
|
49
|
+
requirement: &2600050 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2600050
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rack-test
|
60
|
-
requirement: &
|
60
|
+
requirement: &2599530 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2599530
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &2598870 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2598870
|
80
80
|
description: A generalized Rack middleware for importing contacts from major email
|
81
81
|
providers.
|
82
82
|
email:
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- lib/omnicontacts/builder.rb
|
97
97
|
- lib/omnicontacts/http_utils.rb
|
98
98
|
- lib/omnicontacts/importer.rb
|
99
|
+
- lib/omnicontacts/importer/facebook.rb
|
99
100
|
- lib/omnicontacts/importer/gmail.rb
|
100
101
|
- lib/omnicontacts/importer/hotmail.rb
|
101
102
|
- lib/omnicontacts/importer/yahoo.rb
|
@@ -107,6 +108,7 @@ files:
|
|
107
108
|
- spec/omnicontacts/authorization/oauth1_spec.rb
|
108
109
|
- spec/omnicontacts/authorization/oauth2_spec.rb
|
109
110
|
- spec/omnicontacts/http_utils_spec.rb
|
111
|
+
- spec/omnicontacts/importer/facebook_spec.rb
|
110
112
|
- spec/omnicontacts/importer/gmail_spec.rb
|
111
113
|
- spec/omnicontacts/importer/hotmail_spec.rb
|
112
114
|
- spec/omnicontacts/importer/yahoo_spec.rb
|