gmail_contacts 1.7 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +7 -0
- data/Rakefile +2 -2
- data/lib/gmail_contacts.rb +96 -21
- data/lib/gmail_contacts/test_stub.rb +39 -56
- data/sample/authsub.rb +14 -3
- data/test/test_gmail_contacts.rb +101 -36
- metadata +111 -24
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -11,8 +11,8 @@ Hoe.spec 'gmail_contacts' do
|
|
11
11
|
self.rubyforge_name = 'seattlerb'
|
12
12
|
self.testlib = :minitest
|
13
13
|
|
14
|
-
extra_deps << ['
|
15
|
-
extra_deps << ['
|
14
|
+
extra_deps << ['nokogiri', '~> 1.4']
|
15
|
+
extra_deps << ['net-http-persistent', '~> 1.2', '> 1.2']
|
16
16
|
extra_dev_deps << ['minitest', '~> 1.3']
|
17
17
|
end
|
18
18
|
|
data/lib/gmail_contacts.rb
CHANGED
@@ -1,16 +1,40 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http/persistent'
|
3
3
|
require 'nokogiri'
|
4
4
|
|
5
5
|
##
|
6
6
|
# GmailContacts sits atop GData and turns the contact feed into
|
7
7
|
# GmailContacts::Contact objects for friendly consumption.
|
8
8
|
#
|
9
|
+
# See sample/authsub.rb for an example which uses GmailContacts.
|
10
|
+
#
|
9
11
|
# GmailContacts was sponsored by AT&T Interactive.
|
12
|
+
#
|
13
|
+
# == Upgrading from 1.x
|
14
|
+
#
|
15
|
+
# gmail_contacts no longer depends on gdata and performs its own AuthSub
|
16
|
+
# handling. Use GmailContacts#authsub_url instead of #authsub_url on
|
17
|
+
# #contact_api.
|
18
|
+
#
|
19
|
+
# gmail_contacts no longer uses gdata to raise exceptions and instead raise
|
20
|
+
# Net::HTTPServerException instead. Rescue Net::HTTPServerException instead
|
21
|
+
# of GData::Client::RequestError. Net::HTTPServerException responds to
|
22
|
+
# #response which you can use to determine what kind of error you got:
|
23
|
+
#
|
24
|
+
# begin
|
25
|
+
# gc.fetch 'nobody@example', false
|
26
|
+
# rescue Net::HTTPServerException => e
|
27
|
+
# case e.response
|
28
|
+
# when Net::HTTPForbidden then
|
29
|
+
# puts "You are not allowed to view contacts for this user"
|
30
|
+
# end
|
31
|
+
# end
|
10
32
|
|
11
33
|
class GmailContacts
|
12
34
|
|
13
|
-
VERSION = '
|
35
|
+
VERSION = '2.0'
|
36
|
+
|
37
|
+
class Error < RuntimeError; end
|
14
38
|
|
15
39
|
Contact = Struct.new :title, :emails, :ims, :phone_numbers, :addresses,
|
16
40
|
:photo_url
|
@@ -40,9 +64,10 @@ class GmailContacts
|
|
40
64
|
attr_reader :author_name
|
41
65
|
|
42
66
|
##
|
43
|
-
#
|
67
|
+
# The current authsub token. If you upgrade a request token to a session
|
68
|
+
# token the value will change.
|
44
69
|
|
45
|
-
|
70
|
+
attr_reader :authsub_token
|
46
71
|
|
47
72
|
##
|
48
73
|
# Contact data
|
@@ -63,11 +88,7 @@ class GmailContacts
|
|
63
88
|
|
64
89
|
##
|
65
90
|
# Creates a new GmailContacts using +authsub_token+. If you don't yet have
|
66
|
-
# an AuthSub token, call
|
67
|
-
# endpoint.
|
68
|
-
#
|
69
|
-
# See GData::Client::Base in the gdata gem and
|
70
|
-
# http://code.google.com/apis/accounts/docs/AuthSub.html for more details.
|
91
|
+
# an AuthSub token, call #authsub_url.
|
71
92
|
|
72
93
|
def initialize(authsub_token = nil, session_token = false)
|
73
94
|
@authsub_token = authsub_token
|
@@ -79,8 +100,38 @@ class GmailContacts
|
|
79
100
|
@author_name = nil
|
80
101
|
@contacts ||= []
|
81
102
|
|
82
|
-
@
|
83
|
-
@
|
103
|
+
@google = URI.parse 'https://www.google.com'
|
104
|
+
@http = Net::HTTP::Persistent.new "gmail_contacts_#{object_id}"
|
105
|
+
@http.debug_output = $stderr
|
106
|
+
@http.headers['Authorization'] = "AuthSub token=\"#{@authsub_token}\""
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Returns a URL that will allow a user to authorize contact retrieval.
|
111
|
+
# Redirect the user to this URL and they will (should) approve your contact
|
112
|
+
# retrieval request.
|
113
|
+
#
|
114
|
+
# +next_url+ is where Google will redirect the user after they grant your
|
115
|
+
# request.
|
116
|
+
#
|
117
|
+
# See http://code.google.com/apis/accounts/docs/AuthSub.html for more
|
118
|
+
# details.
|
119
|
+
|
120
|
+
def authsub_url next_url, secure = false, session = true, domain = nil
|
121
|
+
query = {
|
122
|
+
'next' => CGI.escape(next_url),
|
123
|
+
'scope' => 'http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F',
|
124
|
+
'secure' => (secure ? 1 : 0),
|
125
|
+
'session' => (session ? 1 : 0),
|
126
|
+
}
|
127
|
+
|
128
|
+
query['hd'] = CGI.escape domain if domain
|
129
|
+
|
130
|
+
query = query.map do |key, value|
|
131
|
+
"#{key}=#{value}"
|
132
|
+
end.sort.join '&'
|
133
|
+
|
134
|
+
"https://www.google.com/accounts/AuthSubRequest?#{query}"
|
84
135
|
end
|
85
136
|
|
86
137
|
##
|
@@ -89,10 +140,10 @@ class GmailContacts
|
|
89
140
|
def fetch(email, revoke = true)
|
90
141
|
get_token
|
91
142
|
|
92
|
-
uri = "http://www.google.com/m8/feeds/contacts/#{email}/full"
|
143
|
+
uri = URI.parse "http://www.google.com/m8/feeds/contacts/#{email}/full"
|
93
144
|
|
94
145
|
loop do
|
95
|
-
res =
|
146
|
+
res = request uri
|
96
147
|
|
97
148
|
xml = Nokogiri::XML res.body
|
98
149
|
|
@@ -101,7 +152,7 @@ class GmailContacts
|
|
101
152
|
next_uri = xml.xpath('//xmlns:feed/xmlns:link[@rel="next"]').first
|
102
153
|
break unless next_uri
|
103
154
|
|
104
|
-
uri
|
155
|
+
uri += next_uri['href']
|
105
156
|
end
|
106
157
|
|
107
158
|
yield if block_given?
|
@@ -118,17 +169,24 @@ class GmailContacts
|
|
118
169
|
else
|
119
170
|
contact.photo_url
|
120
171
|
end
|
121
|
-
|
172
|
+
response = request URI.parse photo_url
|
122
173
|
|
123
|
-
|
174
|
+
response.body
|
124
175
|
end
|
125
176
|
|
126
177
|
##
|
127
|
-
# Fetches an AuthSub session token
|
178
|
+
# Fetches an AuthSub session token. Changes the value of #authsub_token so
|
179
|
+
# you can store it in a database or wherever.
|
128
180
|
|
129
181
|
def get_token
|
130
182
|
return if @session_token
|
131
|
-
|
183
|
+
|
184
|
+
response = request @google + '/accounts/AuthSubSessionToken'
|
185
|
+
|
186
|
+
response.body =~ /^Token=(.*)/
|
187
|
+
|
188
|
+
@authsub_token = $1
|
189
|
+
@http.headers['Authorization'] = "AuthSub token=\"#{@authsub_token}\""
|
132
190
|
@session_token = true
|
133
191
|
end
|
134
192
|
|
@@ -181,10 +239,27 @@ class GmailContacts
|
|
181
239
|
end
|
182
240
|
|
183
241
|
##
|
184
|
-
#
|
242
|
+
# Performs a GET for +uri+ and returns the Net::HTTPResponse. Raises
|
243
|
+
# Net::HTTPError if the response wasn't a success (OK, Created, Found).
|
244
|
+
|
245
|
+
def request uri
|
246
|
+
response = @http.request uri
|
247
|
+
|
248
|
+
case response
|
249
|
+
when Net::HTTPOK, Net::HTTPCreated, Net::HTTPFound then
|
250
|
+
response
|
251
|
+
else
|
252
|
+
response.error!
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
##
|
257
|
+
# Revokes our AuthSub session token
|
185
258
|
|
186
259
|
def revoke_token
|
187
|
-
@
|
260
|
+
request @google + '/accounts/AuthSubRevokeToken'
|
261
|
+
|
262
|
+
@session_token = false
|
188
263
|
end
|
189
264
|
|
190
265
|
##
|
@@ -8,13 +8,13 @@ require 'gmail_contacts'
|
|
8
8
|
#
|
9
9
|
# require 'gmail_contacts'
|
10
10
|
# require 'gmail_contacts/test_stub'
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# class TestMyClass < Test::Unit::TestCase
|
13
13
|
# def test_something
|
14
14
|
# GmailContacts.stub
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# # ... your code using gc
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# end
|
19
19
|
# end
|
20
20
|
#
|
@@ -23,6 +23,15 @@ require 'gmail_contacts'
|
|
23
23
|
#
|
24
24
|
# If you set the authsub token to 'wrong_user_authsub_token', the test stub
|
25
25
|
# will raise a GData::Client::AuthorizationError when you call #fetch.
|
26
|
+
#
|
27
|
+
# If you set the authsub token to 'authsub_token', #get_token will change it
|
28
|
+
# to 'authsub_token-upgraded' to indicate it was upgraded to a session token.
|
29
|
+
#
|
30
|
+
# If you fetch a photo with 404 in the url, #fetch_photo will raise a
|
31
|
+
# Net::HTTPServerException with a 404 response inside.
|
32
|
+
#
|
33
|
+
# #revoke_token will set the token to 'authsub_token-revoked' to indicate it
|
34
|
+
# was revoked.
|
26
35
|
|
27
36
|
class GmailContacts::TestStub
|
28
37
|
|
@@ -138,6 +147,8 @@ class GmailContacts
|
|
138
147
|
|
139
148
|
@stubbed = false
|
140
149
|
|
150
|
+
attr_reader :http
|
151
|
+
|
141
152
|
def self.stub
|
142
153
|
return if @stubbed
|
143
154
|
@stubbed = true
|
@@ -146,25 +157,23 @@ class GmailContacts
|
|
146
157
|
|
147
158
|
def get_token
|
148
159
|
if @authsub_token == 'recycled_authsub_token' then
|
149
|
-
|
150
|
-
res.status_code = 403
|
151
|
-
res.body = 'recycled token'
|
152
|
-
raise GData::Client::AuthorizationError, res
|
160
|
+
Net::HTTPForbidden.new(nil, '403', 'Forbidden').error!
|
153
161
|
end
|
154
|
-
|
155
|
-
@
|
156
|
-
|
157
|
-
@
|
162
|
+
|
163
|
+
@authsub_token = 'authsub_token-upgraded' if
|
164
|
+
@authsub_token == 'authsub_token'
|
165
|
+
@session_token = true
|
166
|
+
|
167
|
+
@http.stub_reset
|
168
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
169
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
158
170
|
end
|
159
171
|
|
160
172
|
alias old_fetch fetch
|
161
173
|
|
162
174
|
def fetch(*args)
|
163
175
|
if @authsub_token == 'wrong_user_authsub_token' then
|
164
|
-
|
165
|
-
res.status_code = 403
|
166
|
-
res.body = 'wrong user'
|
167
|
-
raise GData::Client::AuthorizationError, res
|
176
|
+
Net::HTTPForbidden.new(nil, '403', 'Forbidden').error!
|
168
177
|
end
|
169
178
|
|
170
179
|
old_fetch(*args)
|
@@ -179,77 +188,51 @@ class GmailContacts
|
|
179
188
|
contact.photo_url
|
180
189
|
end
|
181
190
|
|
182
|
-
|
183
|
-
|
184
|
-
def res.status_code() 404 end
|
185
|
-
def res.body() 'Photo not found' end
|
186
|
-
raise GData::Client::UnknownError, res
|
187
|
-
end
|
191
|
+
Net::HTTPNotFound.new(nil, '404', 'Not Found').error! if
|
192
|
+
photo_url =~ /404/
|
188
193
|
|
189
194
|
old_fetch_photo contact
|
190
195
|
end
|
191
196
|
|
197
|
+
alias old_revoke_token revoke_token
|
198
|
+
|
199
|
+
def revoke_token
|
200
|
+
@authsub_token = 'authsub_token-revoked'
|
201
|
+
@session_token = false
|
202
|
+
end
|
203
|
+
|
192
204
|
end
|
193
205
|
|
194
206
|
end
|
195
207
|
# :startdoc:
|
196
208
|
|
197
|
-
|
198
|
-
# Extension that provides a stub for testing GmailContacts
|
199
|
-
#
|
200
|
-
# See GmailContacts::TestStub for usage details
|
201
|
-
|
202
|
-
class GData::Client::Contacts
|
209
|
+
class Net::HTTP::Persistent
|
203
210
|
|
204
211
|
##
|
205
212
|
# Accessor for data the stub will return
|
206
213
|
|
207
214
|
attr_accessor :stub_data
|
208
215
|
|
209
|
-
##
|
210
|
-
# Accessor for the stub AuthSub token
|
211
|
-
|
212
|
-
attr_accessor :stub_token
|
213
|
-
|
214
216
|
##
|
215
217
|
# Accessor for URLs the stub accessed
|
216
218
|
|
217
219
|
attr_accessor :stub_urls
|
218
220
|
|
219
|
-
|
220
|
-
# Sets the authsub token to +token+, but does no HTTP requests
|
221
|
-
|
222
|
-
def authsub_token=(token)
|
223
|
-
@stub_token = token
|
224
|
-
auth_handler = Object.new
|
225
|
-
auth_handler.instance_variable_set :@revoked, nil
|
226
|
-
auth_handler.instance_variable_set :@upgraded, nil
|
227
|
-
auth_handler.instance_variable_set :@token, token
|
228
|
-
def auth_handler.revoke() @revoked = true end
|
229
|
-
def auth_handler.revoked?() @revoked end
|
230
|
-
def auth_handler.upgrade() @upgraded = true end
|
231
|
-
def auth_handler.upgraded?() @upgraded end
|
232
|
-
def auth_handler.token()
|
233
|
-
[@token,
|
234
|
-
(@revoked ? 'revoked' : nil),
|
235
|
-
(@upgraded ? 'upgraded' : nil)].compact.join '-'
|
236
|
-
end
|
237
|
-
self.auth_handler = auth_handler
|
238
|
-
end
|
221
|
+
alias old_request request
|
239
222
|
|
240
223
|
##
|
241
|
-
# Fetches +url+, records in
|
224
|
+
# Fetches +url+, records in stub_urls, and returns data if there's still
|
242
225
|
# data in stub_data, or raises an exception
|
243
226
|
|
244
|
-
def
|
245
|
-
@stub_urls << url
|
227
|
+
def request(url)
|
228
|
+
@stub_urls << url.to_s
|
246
229
|
raise 'stub data empty' if @stub_data.empty?
|
247
230
|
|
248
231
|
data = @stub_data.shift
|
249
232
|
|
250
233
|
return data.call if Proc === data
|
251
234
|
|
252
|
-
res =
|
235
|
+
res = Net::HTTPOK.new nil, '200', 'OK'
|
253
236
|
def res.body() @data end
|
254
237
|
res.instance_variable_set :@data, data
|
255
238
|
res
|
data/sample/authsub.rb
CHANGED
@@ -7,6 +7,9 @@ webrick = WEBrick::HTTPServer.new :Port => 3000
|
|
7
7
|
webrick.mount_proc '/' do |req, res|
|
8
8
|
res.content_type = 'text/html'
|
9
9
|
|
10
|
+
##
|
11
|
+
# This is the initial page, a form with an email to fetch contacts for
|
12
|
+
|
10
13
|
if req.path == '/' then
|
11
14
|
res.body = <<-BODY
|
12
15
|
<form action="http://#{Socket.gethostname}:3000/go">
|
@@ -15,12 +18,20 @@ webrick.mount_proc '/' do |req, res|
|
|
15
18
|
</form>
|
16
19
|
BODY
|
17
20
|
|
21
|
+
##
|
22
|
+
# This is where we redirect the user to Google for approval, click "grant"
|
23
|
+
# on that page.
|
24
|
+
|
18
25
|
elsif req.path == '/go' then
|
19
26
|
gmail_contacts = GmailContacts.new
|
20
|
-
url = gmail_contacts.
|
21
|
-
"http
|
27
|
+
url = gmail_contacts.authsub_url \
|
28
|
+
"http://localhost:3000/return?email=#{req.query['email']}"
|
22
29
|
res.set_redirect WEBrick::HTTPStatus::SeeOther, url
|
23
30
|
|
31
|
+
##
|
32
|
+
# Google sends us back here, so we create a new GmailContacts with the token
|
33
|
+
# they gave us and fetch the contacts for the email provided to /go
|
34
|
+
|
24
35
|
elsif req.path == '/return' then
|
25
36
|
res.body = "<h1>contacts</h1>\n"
|
26
37
|
|
@@ -37,7 +48,7 @@ webrick.mount_proc '/' do |req, res|
|
|
37
48
|
res.body << "<li>#{contact.title} - #{contact.primary_email}\n"
|
38
49
|
end
|
39
50
|
|
40
|
-
res.body << "
|
51
|
+
res.body << "</ul>\n"
|
41
52
|
rescue => e
|
42
53
|
res.body << <<-BODY
|
43
54
|
<h1>error</h1>
|
data/test/test_gmail_contacts.rb
CHANGED
@@ -7,9 +7,9 @@ require 'pp'
|
|
7
7
|
class TestGmailContacts < MiniTest::Unit::TestCase
|
8
8
|
|
9
9
|
def setup
|
10
|
-
@gc = GmailContacts.new 'token'
|
11
|
-
@
|
12
|
-
@
|
10
|
+
@gc = GmailContacts.new 'token', true
|
11
|
+
@http = @gc.http
|
12
|
+
@http.stub_reset
|
13
13
|
|
14
14
|
@eric =
|
15
15
|
GmailContacts::Contact.new('Eric', %w[eric@example.com eric@example.net],
|
@@ -20,64 +20,70 @@ class TestGmailContacts < MiniTest::Unit::TestCase
|
|
20
20
|
"http://www.google.com/m8/feeds/photos/media/eric%40example.com/18")
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_initialize
|
24
|
+
assert_equal 'AuthSub token="token"', @http.headers['Authorization']
|
25
|
+
assert_match %r%_\d+$%, @http.name
|
26
|
+
end
|
27
|
+
|
23
28
|
def test_fetch
|
24
|
-
@
|
25
|
-
@
|
29
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
30
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
31
|
+
@http.stub_data << ''
|
26
32
|
|
27
33
|
@gc.fetch 'eric@example.com'
|
28
34
|
|
29
35
|
assert_equal 3, @gc.contacts.length
|
30
36
|
|
31
|
-
assert_equal
|
37
|
+
assert_equal 3, @http.stub_urls.length
|
32
38
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric@example.com/full',
|
33
|
-
@
|
39
|
+
@http.stub_urls.shift
|
34
40
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric%40example.com/full?start-index=3&max-results=2',
|
35
|
-
@
|
36
|
-
|
37
|
-
|
38
|
-
assert @api.auth_handler.revoked?
|
41
|
+
@http.stub_urls.shift
|
42
|
+
assert_equal 'https://www.google.com/accounts/AuthSubRevokeToken',
|
43
|
+
@http.stub_urls.shift
|
39
44
|
end
|
40
45
|
|
41
|
-
def
|
42
|
-
@
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
46
|
+
def test_fetch_auto_upgrade
|
47
|
+
@gc = GmailContacts.new 'token'
|
48
|
+
@http = @gc.http
|
49
|
+
@http.stub_reset
|
50
|
+
@http.stub_data << ''
|
51
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
52
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
53
|
+
@http.stub_data << ''
|
50
54
|
|
51
|
-
|
55
|
+
@gc.fetch 'eric@example.com'
|
52
56
|
|
53
|
-
assert_equal
|
54
|
-
assert_equal 'http://www.google.com/m8/feeds/contacts/notme@example.com/full',
|
55
|
-
@api.stub_urls.shift
|
57
|
+
assert_equal 3, @gc.contacts.length
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
assert_equal 4, @http.stub_urls.length
|
60
|
+
assert_equal 'https://www.google.com/accounts/AuthSubSessionToken',
|
61
|
+
@http.stub_urls.shift
|
62
|
+
assert_equal 'http://www.google.com/m8/feeds/contacts/eric@example.com/full',
|
63
|
+
@http.stub_urls.shift
|
64
|
+
assert_equal 'http://www.google.com/m8/feeds/contacts/eric%40example.com/full?start-index=3&max-results=2',
|
65
|
+
@http.stub_urls.shift
|
66
|
+
assert_equal 'https://www.google.com/accounts/AuthSubRevokeToken',
|
67
|
+
@http.stub_urls.shift
|
59
68
|
end
|
60
69
|
|
61
70
|
def test_fetch_no_revoke
|
62
|
-
@
|
63
|
-
@
|
71
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
72
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
64
73
|
|
65
74
|
@gc.fetch 'eric@example.com', false
|
66
75
|
|
67
76
|
assert_equal 3, @gc.contacts.length
|
68
77
|
|
69
|
-
assert_equal 2, @
|
78
|
+
assert_equal 2, @http.stub_urls.length
|
70
79
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric@example.com/full',
|
71
|
-
@
|
80
|
+
@http.stub_urls.shift
|
72
81
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric%40example.com/full?start-index=3&max-results=2',
|
73
|
-
@
|
74
|
-
|
75
|
-
assert @api.auth_handler.upgraded?
|
76
|
-
refute @api.auth_handler.revoked?
|
82
|
+
@http.stub_urls.shift
|
77
83
|
end
|
78
84
|
|
79
85
|
def test_fetch_photo
|
80
|
-
@
|
86
|
+
@http.stub_data << 'THIS IS A PHOTO!'
|
81
87
|
|
82
88
|
photo = @gc.fetch_photo @eric
|
83
89
|
|
@@ -85,13 +91,36 @@ class TestGmailContacts < MiniTest::Unit::TestCase
|
|
85
91
|
end
|
86
92
|
|
87
93
|
def test_fetch_photo_url
|
88
|
-
@
|
94
|
+
@http.stub_data << 'THIS IS A PHOTO!'
|
89
95
|
|
90
96
|
photo = @gc.fetch_photo @eric.photo_url
|
91
97
|
|
92
98
|
assert_equal 'THIS IS A PHOTO!', photo
|
93
99
|
end
|
94
100
|
|
101
|
+
def test_get_token
|
102
|
+
assert @gc.token?, 'sanity, we should already have a session token'
|
103
|
+
|
104
|
+
assert_nil @gc.get_token
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_get_token_non_session
|
108
|
+
@gc = GmailContacts.new 'token'
|
109
|
+
@http = @gc.http
|
110
|
+
@http.stub_reset
|
111
|
+
@http.stub_data << 'Token=new token'
|
112
|
+
|
113
|
+
@gc.get_token
|
114
|
+
|
115
|
+
assert @gc.token?
|
116
|
+
assert_equal 'new token', @gc.authsub_token
|
117
|
+
assert_equal 'AuthSub token="new token"', @http.headers['Authorization']
|
118
|
+
|
119
|
+
assert_equal 1, @http.stub_urls.length
|
120
|
+
assert_equal 'https://www.google.com/accounts/AuthSubSessionToken',
|
121
|
+
@http.stub_urls.shift
|
122
|
+
end
|
123
|
+
|
95
124
|
def test_parse
|
96
125
|
@gc.parse Nokogiri::XML(GmailContacts::TestStub::CONTACTS)
|
97
126
|
|
@@ -134,5 +163,41 @@ class TestGmailContacts < MiniTest::Unit::TestCase
|
|
134
163
|
assert_equal expected, @gc.contacts
|
135
164
|
end
|
136
165
|
|
166
|
+
def test_request
|
167
|
+
@http.stub_data << 'blah'
|
168
|
+
|
169
|
+
res = @gc.request 'http://example'
|
170
|
+
|
171
|
+
assert_equal 'blah', res.body
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_request_unsuccessful
|
175
|
+
@http.stub_data << proc do
|
176
|
+
Net::HTTPForbidden.new nil, '403', 'Forbidden'
|
177
|
+
end
|
178
|
+
|
179
|
+
assert_raises Net::HTTPServerException do
|
180
|
+
@gc.request 'http://example'
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_revoke_token
|
185
|
+
@http.stub_data << ''
|
186
|
+
|
187
|
+
@gc.revoke_token
|
188
|
+
|
189
|
+
refute @gc.token?
|
190
|
+
|
191
|
+
assert_equal 1, @http.stub_urls.length
|
192
|
+
assert_equal 'https://www.google.com/accounts/AuthSubRevokeToken',
|
193
|
+
@http.stub_urls.shift
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_token_eh
|
197
|
+
assert @gc.token?
|
198
|
+
|
199
|
+
refute GmailContacts.new.token?
|
200
|
+
end
|
201
|
+
|
137
202
|
end
|
138
203
|
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gmail_contacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 3
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: "2.0"
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Eric Hodel
|
@@ -30,49 +35,125 @@ cert_chain:
|
|
30
35
|
x52qPcexcYZR7w==
|
31
36
|
-----END CERTIFICATE-----
|
32
37
|
|
33
|
-
date:
|
38
|
+
date: 2010-06-03 00:00:00 -07:00
|
34
39
|
default_executable:
|
35
40
|
dependencies:
|
36
41
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
name: nokogiri
|
43
|
+
prerelease: false
|
44
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
41
46
|
requirements:
|
42
47
|
- - ~>
|
43
48
|
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
|
46
|
-
-
|
47
|
-
|
49
|
+
hash: 7
|
50
|
+
segments:
|
51
|
+
- 1
|
52
|
+
- 4
|
53
|
+
version: "1.4"
|
48
54
|
type: :runtime
|
49
|
-
|
50
|
-
|
55
|
+
version_requirements: *id001
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: net-http-persistent
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
51
61
|
requirements:
|
52
62
|
- - ~>
|
53
63
|
- !ruby/object:Gem::Version
|
64
|
+
hash: 11
|
65
|
+
segments:
|
66
|
+
- 1
|
67
|
+
- 2
|
68
|
+
version: "1.2"
|
69
|
+
- - ">"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 11
|
72
|
+
segments:
|
73
|
+
- 1
|
74
|
+
- 2
|
54
75
|
version: "1.2"
|
55
|
-
|
76
|
+
type: :runtime
|
77
|
+
version_requirements: *id002
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rubyforge
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 9
|
87
|
+
segments:
|
88
|
+
- 2
|
89
|
+
- 0
|
90
|
+
- 3
|
91
|
+
version: 2.0.3
|
92
|
+
type: :development
|
93
|
+
version_requirements: *id003
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: gemcutter
|
96
|
+
prerelease: false
|
97
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 11
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
- 5
|
106
|
+
- 0
|
107
|
+
version: 0.5.0
|
108
|
+
type: :development
|
109
|
+
version_requirements: *id004
|
56
110
|
- !ruby/object:Gem::Dependency
|
57
111
|
name: minitest
|
112
|
+
prerelease: false
|
113
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 1
|
121
|
+
- 5
|
122
|
+
- 0
|
123
|
+
version: 1.5.0
|
58
124
|
type: :development
|
59
|
-
|
60
|
-
|
125
|
+
version_requirements: *id005
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: minitest
|
128
|
+
prerelease: false
|
129
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
61
131
|
requirements:
|
62
132
|
- - ~>
|
63
133
|
- !ruby/object:Gem::Version
|
134
|
+
hash: 9
|
135
|
+
segments:
|
136
|
+
- 1
|
137
|
+
- 3
|
64
138
|
version: "1.3"
|
65
|
-
|
139
|
+
type: :development
|
140
|
+
version_requirements: *id006
|
66
141
|
- !ruby/object:Gem::Dependency
|
67
142
|
name: hoe
|
68
|
-
|
69
|
-
|
70
|
-
|
143
|
+
prerelease: false
|
144
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
71
146
|
requirements:
|
72
147
|
- - ">="
|
73
148
|
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
|
149
|
+
hash: 27
|
150
|
+
segments:
|
151
|
+
- 2
|
152
|
+
- 5
|
153
|
+
- 0
|
154
|
+
version: 2.5.0
|
155
|
+
type: :development
|
156
|
+
version_requirements: *id007
|
76
157
|
description: |-
|
77
158
|
Simple Gmail contacts extraction using GData.
|
78
159
|
|
@@ -109,21 +190,27 @@ rdoc_options:
|
|
109
190
|
require_paths:
|
110
191
|
- lib
|
111
192
|
required_ruby_version: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
112
194
|
requirements:
|
113
195
|
- - ">="
|
114
196
|
- !ruby/object:Gem::Version
|
197
|
+
hash: 3
|
198
|
+
segments:
|
199
|
+
- 0
|
115
200
|
version: "0"
|
116
|
-
version:
|
117
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
118
203
|
requirements:
|
119
204
|
- - ">="
|
120
205
|
- !ruby/object:Gem::Version
|
206
|
+
hash: 3
|
207
|
+
segments:
|
208
|
+
- 0
|
121
209
|
version: "0"
|
122
|
-
version:
|
123
210
|
requirements: []
|
124
211
|
|
125
212
|
rubyforge_project: seattlerb
|
126
|
-
rubygems_version: 1.3.
|
213
|
+
rubygems_version: 1.3.7
|
127
214
|
signing_key:
|
128
215
|
specification_version: 3
|
129
216
|
summary: Simple Gmail contacts extraction using GData
|
metadata.gz.sig
CHANGED
Binary file
|