contacts 1.2.3 → 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -3
- data/lib/contacts/aol.rb +5 -2
- data/lib/contacts/base.rb +1 -1
- data/lib/contacts/hotmail.rb +4 -3
- data/lib/contacts/yahoo.rb +8 -14
- data/test/example_accounts.yml +40 -0
- data/test/test_helper.rb +31 -0
- data/test/test_suite.rb +4 -0
- data/test/unit/aol_contact_importer_test.rb +39 -0
- data/test/unit/gmail_contact_importer_test.rb +39 -0
- data/test/unit/hotmail_contact_importer_test.rb +41 -0
- data/test/unit/test_accounts_test.rb +23 -0
- data/test/unit/yahoo_csv_contact_importer_test.rb +35 -0
- metadata +24 -16
data/Rakefile
CHANGED
@@ -43,13 +43,13 @@ spec = Gem::Specification.new do |s|
|
|
43
43
|
|
44
44
|
#### Basic information.
|
45
45
|
|
46
|
-
s.name = '
|
46
|
+
s.name = 'contacts'
|
47
47
|
s.version = PKG_VERSION
|
48
48
|
s.summary = <<-EOF
|
49
|
-
|
49
|
+
A universal interface to grab contact list information from various providers including Yahoo, AOL, Gmail, Hotmail, and Plaxo.
|
50
50
|
EOF
|
51
51
|
s.description = <<-EOF
|
52
|
-
|
52
|
+
A universal interface to grab contact list information from various providers including Yahoo, AOL, Gmail, Hotmail, and Plaxo.
|
53
53
|
EOF
|
54
54
|
|
55
55
|
#### Which files are to be included in this gem? Everything! (Except CVS directories.)
|
data/lib/contacts/aol.rb
CHANGED
@@ -13,7 +13,10 @@ class Contacts
|
|
13
13
|
PROTOCOL_ERROR = "AOL has changed its protocols, please upgrade this library first. If that does not work, dive into the code and submit a patch at http://github.com/cardmagic/contacts"
|
14
14
|
|
15
15
|
def real_connect
|
16
|
-
|
16
|
+
if login.strip =~ /^(.+)@aol\.com$/ # strip off the @aol.com for AOL logins
|
17
|
+
login = $1
|
18
|
+
end
|
19
|
+
|
17
20
|
postdata = {
|
18
21
|
"loginId" => login,
|
19
22
|
"password" => password,
|
@@ -77,7 +80,7 @@ class Contacts
|
|
77
80
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
78
81
|
end
|
79
82
|
|
80
|
-
if data.index("Invalid
|
83
|
+
if data.index("Invalid Username or Password. Please try again.")
|
81
84
|
raise AuthenticationError, "Username and password do not match"
|
82
85
|
elsif data.index("Required field must not be blank")
|
83
86
|
raise AuthenticationError, "Login and password must not be blank"
|
data/lib/contacts/base.rb
CHANGED
data/lib/contacts/hotmail.rb
CHANGED
@@ -78,9 +78,9 @@ class Contacts
|
|
78
78
|
email_match_text_beginning = Regexp.escape("http://m.mail.live.com/?rru=compose&to=")
|
79
79
|
email_match_text_end = Regexp.escape("&")
|
80
80
|
|
81
|
-
raw_html = resp.body.
|
82
|
-
|
83
|
-
raw_html.inject do |memo, row|
|
81
|
+
raw_html = resp.body.split("
|
82
|
+
").grep(/(?:e|dn)lk[0-9]+/)
|
83
|
+
raw_html.inject(-1) do |memo, row|
|
84
84
|
c_info = row.match(/(e|dn)lk([0-9])+/)
|
85
85
|
|
86
86
|
# Same contact, or different?
|
@@ -109,6 +109,7 @@ class Contacts
|
|
109
109
|
@contacts << contact
|
110
110
|
end
|
111
111
|
end
|
112
|
+
|
112
113
|
return @contacts
|
113
114
|
end
|
114
115
|
end
|
data/lib/contacts/yahoo.rb
CHANGED
@@ -62,15 +62,11 @@ class Contacts
|
|
62
62
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
63
63
|
end
|
64
64
|
|
65
|
-
parse data
|
66
|
-
|
67
|
-
parse more_data
|
68
|
-
|
69
65
|
if more_data =~ /"TotalABContacts":(\d+)/
|
70
66
|
total = $1.to_i
|
71
|
-
((total / 50)).times do |i|
|
67
|
+
((total / 50.0).ceil).times do |i|
|
72
68
|
# now proceed with the new ".crumb" parameter to get the csv data
|
73
|
-
url = URI.parse(contact_list_url.sub("bucket=1","bucket=#{i
|
69
|
+
url = URI.parse(contact_list_url.sub("bucket=1","bucket=#{i}").sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
|
74
70
|
http = open_http(url)
|
75
71
|
resp, more_data = http.get("#{url.path}?#{url.query}",
|
76
72
|
"Cookie" => @cookies,
|
@@ -81,7 +77,7 @@ class Contacts
|
|
81
77
|
if resp.code_type != Net::HTTPOK
|
82
78
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
83
79
|
end
|
84
|
-
|
80
|
+
|
85
81
|
parse more_data
|
86
82
|
end
|
87
83
|
end
|
@@ -94,13 +90,11 @@ class Contacts
|
|
94
90
|
|
95
91
|
def parse(data, options={})
|
96
92
|
@contacts ||= []
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
@contacts
|
103
|
-
end
|
93
|
+
@contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map do |contact|
|
94
|
+
name = contact["contactName"].split(",")
|
95
|
+
[[name.pop, name.join(",")].join(" ").strip, contact["email"]]
|
96
|
+
end if data =~ /^\{"response":/
|
97
|
+
@contacts
|
104
98
|
end
|
105
99
|
|
106
100
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
gmail:
|
2
|
+
username: <changeme>
|
3
|
+
password: <changeme>
|
4
|
+
contacts:
|
5
|
+
-
|
6
|
+
name: "FirstName1 LastName1"
|
7
|
+
email_address: "firstname1@example.com"
|
8
|
+
-
|
9
|
+
name: "FirstName2 LastName2"
|
10
|
+
email_address: "firstname2@example.com"
|
11
|
+
yahoo:
|
12
|
+
username: <changeme>
|
13
|
+
password: <changeme>
|
14
|
+
contacts:
|
15
|
+
-
|
16
|
+
name: "FirstName1 LastName1"
|
17
|
+
email_address: "firstname1@example.com"
|
18
|
+
-
|
19
|
+
name: "FirstName2 LastName2"
|
20
|
+
email_address: "firstname2@example.com"
|
21
|
+
hotmail:
|
22
|
+
username: <changeme>
|
23
|
+
password: <changeme>
|
24
|
+
contacts:
|
25
|
+
-
|
26
|
+
name: "FirstName1 LastName1"
|
27
|
+
email_address: "firstname1@example.com"
|
28
|
+
-
|
29
|
+
name: "FirstName2 LastName2"
|
30
|
+
email_address: "firstname2@example.com"
|
31
|
+
aol:
|
32
|
+
username: <changeme>
|
33
|
+
password: <changeme>
|
34
|
+
contacts:
|
35
|
+
-
|
36
|
+
name: "FirstName1 LastName1"
|
37
|
+
email_address: "firstname1@example.com"
|
38
|
+
-
|
39
|
+
name: "FirstName2 LastName2"
|
40
|
+
email_address: "firstname2@example.com"
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift(dir + "/../lib/")
|
3
|
+
require 'test/unit'
|
4
|
+
require 'contacts'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
class ContactImporterTestCase < Test::Unit::TestCase
|
8
|
+
# Add more helper methods to be used by all tests here...
|
9
|
+
def default_test
|
10
|
+
assert true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestAccounts
|
15
|
+
def self.[](type)
|
16
|
+
load[type]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.load(file = File.dirname(__FILE__) + "/accounts.yml")
|
20
|
+
raise "/test/accounts.yml file not found, please create, see /test/example_accounts.yml for information" unless File.exist?(file)
|
21
|
+
|
22
|
+
accounts = {}
|
23
|
+
YAML::load(File.open(file)).each do |type, contents|
|
24
|
+
contacts = contents["contacts"].collect {|contact| [contact["name"], contact["email_address"]]}
|
25
|
+
accounts[type.to_sym] = Account.new(type.to_sym, contents["username"], contents["password"], contacts)
|
26
|
+
end
|
27
|
+
accounts
|
28
|
+
end
|
29
|
+
|
30
|
+
Account = Struct.new :type, :username, :password, :contacts
|
31
|
+
end
|
data/test/test_suite.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
require 'contacts'
|
4
|
+
|
5
|
+
class AolContactImporterTest < ContactImporterTestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@account = TestAccounts[:aol]
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_successful_login
|
12
|
+
Contacts.new(:aol, @account.username, @account.password)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_importer_fails_with_invalid_password
|
16
|
+
assert_raise(Contacts::AuthenticationError) do
|
17
|
+
Contacts.new(:aol, @account.username, "wrong_password")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_importer_fails_with_blank_password
|
22
|
+
assert_raise(Contacts::AuthenticationError) do
|
23
|
+
Contacts.new(:aol, @account.username, "")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_importer_fails_with_blank_username
|
28
|
+
assert_raise(Contacts::AuthenticationError) do
|
29
|
+
Contacts.new(:aol, "", @account.password)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_fetch_contacts
|
34
|
+
contacts = Contacts.new(:aol, @account.username, @account.password).contacts
|
35
|
+
@account.contacts.each do |contact|
|
36
|
+
assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
require 'contacts'
|
4
|
+
|
5
|
+
class GmailContactImporterTest < ContactImporterTestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@account = TestAccounts[:gmail]
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_successful_login
|
12
|
+
Contacts.new(:gmail, @account.username, @account.password)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_importer_fails_with_invalid_password
|
16
|
+
assert_raise(Contacts::AuthenticationError) do
|
17
|
+
Contacts.new(:gmail, @account.username, "wrong_password")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_importer_fails_with_blank_password
|
22
|
+
assert_raise(Contacts::AuthenticationError) do
|
23
|
+
Contacts.new(:gmail, @account.username, "")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_importer_fails_with_blank_username
|
28
|
+
assert_raise(Contacts::AuthenticationError) do
|
29
|
+
Contacts.new(:gmail, "", @account.password)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_fetch_contacts
|
34
|
+
contacts = Contacts.new(:gmail, @account.username, @account.password).contacts
|
35
|
+
@account.contacts.each do |contact|
|
36
|
+
assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
require 'contacts'
|
4
|
+
|
5
|
+
class HotmailContactImporterTest < ContactImporterTestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@account = TestAccounts[:hotmail]
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_successful_login
|
12
|
+
Contacts.new(:hotmail, @account.username, @account.password)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_importer_fails_with_invalid_password
|
16
|
+
assert_raise(Contacts::AuthenticationError) do
|
17
|
+
Contacts.new(:hotmail, @account.username,"wrong_password")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_fetch_contacts
|
22
|
+
contacts = Contacts.new(:hotmail, @account.username, @account.password).contacts
|
23
|
+
@account.contacts.each do |contact|
|
24
|
+
assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_importer_fails_with_invalid_msn_password
|
29
|
+
assert_raise(Contacts::AuthenticationError) do
|
30
|
+
Contacts.new(:hotmail, "test@msn.com","wrong_password")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Since the hotmail scraper doesn't read names, test email
|
35
|
+
def test_fetch_email
|
36
|
+
contacts = Contacts.new(:hotmail, @account.username, @account.password).contacts
|
37
|
+
@account.contacts.each do |contact|
|
38
|
+
assert contacts.any?{|book_contact| book_contact.last == contact.last }, "Could not find: #{contact.inspect} in #{contacts.inspect}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
|
4
|
+
class TestAccountsTest < ContactImporterTestCase
|
5
|
+
def test_test_accounts_loads_data_from_example_accounts_file
|
6
|
+
account = TestAccounts.load(File.dirname(__FILE__) + "/../example_accounts.yml")[:gmail]
|
7
|
+
|
8
|
+
assert_equal :gmail, account.type
|
9
|
+
assert_equal "<changeme>", account.username
|
10
|
+
assert_equal "<changeme>", account.password
|
11
|
+
assert_equal [["FirstName1 LastName1", "firstname1@example.com"], ["FirstName2 LastName2", "firstname2@example.com"]], account.contacts
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_test_accounts_blows_up_if_file_doesnt_exist
|
15
|
+
assert_raise(RuntimeError) do
|
16
|
+
TestAccounts.load("file_that_does_not_exist.yml")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_we_can_load_from_account_file
|
21
|
+
assert_not_nil TestAccounts[:gmail].username
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
require 'contacts'
|
4
|
+
|
5
|
+
class YahooContactImporterTest < ContactImporterTestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@account = TestAccounts[:yahoo]
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_a_successful_login
|
12
|
+
Contacts.new(:yahoo, @account.username, @account.password)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_importer_fails_with_invalid_password
|
16
|
+
assert_raise(Contacts::AuthenticationError) do
|
17
|
+
Contacts.new(:yahoo, @account.username, "wrong_password")
|
18
|
+
end
|
19
|
+
# run the "successful" login test to ensure we reset yahoo's failed login lockout counter
|
20
|
+
# See http://www.pivotaltracker.com/story/show/138210
|
21
|
+
# yahoo needs some time to unset the failed login state, apparently...
|
22
|
+
# ...1 sec and 5 secs still failed sporadically
|
23
|
+
sleep 10
|
24
|
+
assert_nothing_raised do
|
25
|
+
Contacts.new(:yahoo, @account.username, @account.password)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_a_fetch_contacts
|
30
|
+
contacts = Contacts.new(:yahoo, @account.username, @account.password).contacts
|
31
|
+
@account.contacts.each do |contact|
|
32
|
+
assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Carlson
|
8
|
-
autorequire:
|
8
|
+
autorequire: contacts
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-07-06 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: 0.4.1
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: gdata
|
@@ -28,11 +28,11 @@ dependencies:
|
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.1.1
|
34
34
|
version:
|
35
|
-
description: A universal interface to grab contact list information from various providers including Yahoo, AOL, Gmail, Hotmail, and Plaxo
|
35
|
+
description: " A universal interface to grab contact list information from various providers including Yahoo, AOL, Gmail, Hotmail, and Plaxo.\n"
|
36
36
|
email: lucas@rufy.com
|
37
37
|
executables: []
|
38
38
|
|
@@ -41,20 +41,28 @@ extensions: []
|
|
41
41
|
extra_rdoc_files: []
|
42
42
|
|
43
43
|
files:
|
44
|
-
-
|
45
|
-
- Rakefile
|
46
|
-
- README
|
47
|
-
- examples/grab_contacts.rb
|
48
|
-
- lib/contacts.rb
|
44
|
+
- lib/contacts/aol.rb
|
49
45
|
- lib/contacts/base.rb
|
50
|
-
- lib/contacts/json_picker.rb
|
51
46
|
- lib/contacts/gmail.rb
|
52
|
-
- lib/contacts/aol.rb
|
53
47
|
- lib/contacts/hotmail.rb
|
48
|
+
- lib/contacts/json_picker.rb
|
54
49
|
- lib/contacts/plaxo.rb
|
55
50
|
- lib/contacts/yahoo.rb
|
51
|
+
- lib/contacts.rb
|
52
|
+
- test/example_accounts.yml
|
53
|
+
- test/test_helper.rb
|
54
|
+
- test/test_suite.rb
|
55
|
+
- test/unit/aol_contact_importer_test.rb
|
56
|
+
- test/unit/gmail_contact_importer_test.rb
|
57
|
+
- test/unit/hotmail_contact_importer_test.rb
|
58
|
+
- test/unit/test_accounts_test.rb
|
59
|
+
- test/unit/yahoo_csv_contact_importer_test.rb
|
60
|
+
- LICENSE
|
61
|
+
- Rakefile
|
62
|
+
- README
|
63
|
+
- examples/grab_contacts.rb
|
56
64
|
has_rdoc: true
|
57
|
-
homepage: http://
|
65
|
+
homepage: http://rubyforge.org/projects/contacts
|
58
66
|
licenses: []
|
59
67
|
|
60
68
|
post_install_message:
|
@@ -74,8 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
82
|
- !ruby/object:Gem::Version
|
75
83
|
version: "0"
|
76
84
|
version:
|
77
|
-
requirements:
|
78
|
-
|
85
|
+
requirements:
|
86
|
+
- A json parser, the gdata ruby gem
|
79
87
|
rubyforge_project:
|
80
88
|
rubygems_version: 1.3.5
|
81
89
|
signing_key:
|