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 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