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 CHANGED
@@ -1,6 +1,6 @@
1
1
  module OmniContacts
2
2
 
3
- VERSION = "0.2.5"
3
+ VERSION = "0.3.0"
4
4
 
5
5
  autoload :Builder, "omnicontacts/builder"
6
6
  autoload :Importer, "omnicontacts/importer"
@@ -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
@@ -4,6 +4,7 @@ module OmniContacts
4
4
  autoload :Gmail, "omnicontacts/importer/gmail"
5
5
  autoload :Yahoo, "omnicontacts/importer/yahoo"
6
6
  autoload :Hotmail, "omnicontacts/importer/hotmail"
7
+ autoload :Facebook, "omnicontacts/importer/facebook"
7
8
 
8
9
  end
9
10
  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
- parse_contacts contacts_response
22
+ contacts_from_response contacts_response
24
23
  end
25
24
 
26
25
  private
27
26
 
28
27
  def contacts_req_params
29
- {"max-results" => @max_results.to_s}
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 parse_contacts contacts_as_xml
37
- xml = REXML::Document.new(contacts_as_xml)
35
+ def contacts_from_response response_as_json
36
+ response = JSON.parse(response_as_json)
38
37
  contacts = []
39
- xml.elements.each('//entry') do |entry|
40
- gd_email = entry.elements['gd:email']
41
- if gd_email
42
- contact = {:email => gd_email.attributes['address']}
43
- gd_name = entry.elements['gd:name']
44
- if gd_name
45
- gd_full_name = gd_name.elements['gd:fullName']
46
- contact[:name] = gd_full_name.text if gd_full_name
47
- end
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 contacts_as_json
28
- json = JSON.parse(escape_windows_format(contacts_as_json))
29
- result = []
30
- json["data"].each do |contact|
31
- result << {:email => contact["name"]} if valid_email? contact["name"]
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
- result
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 = "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"
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, ["xoauth_yahoo_guid"])
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
- :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"
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["oauth_signature"] = oauth_signature("GET", contacts_url, params, access_token_secret)
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 contacts_as_json
45
- json = JSON.parse(contacts_as_json)
46
- result = []
47
- return result unless json["contacts"]["contact"]
48
- json["contacts"]["contact"].each do |entry|
49
- contact = {}
50
- entry["fields"].each do |field|
51
- contact[:email] = field["value"] if field["type"] == "email"
52
- if field["type"] == "name"
53
- name = field["value"]["givenName"]
54
- surname = field["value"]["familyName"]
55
- contact[:name] = "#{name} #{surname}" if name && surname
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
- result << contact if contact[:email]
72
+ contacts << contact if contact[:name]
59
73
  end
60
- result
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 }.should raise_error
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") }.should raise_error
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") }.should raise_error
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", {}) }.should raise_error
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(:contacts_as_xml) {
9
- "<entry xmlns:gd='http://schemas.google.com/g/2005'>
10
- <gd:name>
11
- <gd:fullName>Edward Bennet</gd:fullName>
12
- </gd:name>
13
- <gd:email rel='http://schemas.google.com/g/2005#work' primary='true' address='bennet@gmail.com'/>
14
- </entry>"
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
- let(:contact_without_fullname) {
18
- "<entry xmlns:gd='http://schemas.google.com/g/2005'>
19
- <gd:name/>
20
- <gd:email rel='http://schemas.google.com/g/2005#work' primary='true' address='bennet@gmail.com'/>
21
- </entry>"
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
- contacts_as_xml
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 email" do
39
- gmail.should_receive(:https_get).and_return(contacts_as_xml)
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
- end
45
-
46
- it "should handle contact without fullname" do
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
- \"data\":
11
- [{
12
- \"id\": \"contact.b4466224b2ca42798c3d4ea90c75aa56\",
13
- \"first_name\": null,
14
- \"last_name\": null,
15
- \"name\": \"henrik@hotmail.com\",
16
- \"gender\": null,
17
- \"is_friend\": false,
18
- \"is_favorite\": false,
19
- \"user_id\": null,
20
- \"birth_day\": 29,
21
- \"birth_month\": 3
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 the contacts" do
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[:name].should be_nil
43
- result.first[:email].should eq("henrik@hotmail.com")
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
- '{"contacts":
9
- {"start":1, "count":1,
10
- "contact":[{"id":10, "fields":[{"id":819, "type":"email", "value":"john@yahoo.com"},
11
- {"type":"name", "value": { "givenName":"John", "familyName":"Doe"} }] }]
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 the contacts correctly" do
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[:name].should eq("John Doe")
38
- result.first[:email].should eq("john@yahoo.com")
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)}.should raise_error
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.2.5
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-04-10 00:00:00.000000000 Z
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: &3692640 !ruby/object:Gem::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: *3692640
24
+ version_requirements: *2601350
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &3692410 !ruby/object:Gem::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: *3692410
35
+ version_requirements: *2600880
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: simplecov
38
- requirement: &3692200 !ruby/object:Gem::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: *3692200
46
+ version_requirements: *2600430
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &3691980 !ruby/object:Gem::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: *3691980
57
+ version_requirements: *2600050
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rack-test
60
- requirement: &3691770 !ruby/object:Gem::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: *3691770
68
+ version_requirements: *2599530
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &3691540 !ruby/object:Gem::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: *3691540
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