omnicontacts 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|