google_contacts_api 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +3 -0
- data/VERSION +1 -1
- data/google_contacts_api.gemspec +11 -2
- data/lib/google_contacts_api.rb +9 -304
- data/lib/google_contacts_api/api.rb +44 -0
- data/lib/google_contacts_api/contact.rb +72 -0
- data/lib/google_contacts_api/contact_set.rb +9 -0
- data/lib/google_contacts_api/contacts.rb +28 -0
- data/lib/google_contacts_api/group.rb +36 -0
- data/lib/google_contacts_api/group_set.rb +9 -0
- data/lib/google_contacts_api/result.rb +58 -0
- data/lib/google_contacts_api/result_set.rb +37 -0
- data/lib/google_contacts_api/user.rb +35 -0
- metadata +12 -3
data/README.markdown
CHANGED
@@ -18,12 +18,15 @@ contacts.first.title
|
|
18
18
|
contacts.first.id
|
19
19
|
```
|
20
20
|
|
21
|
+
In addition, Contacts and Groups are subclasses of [Hashie::Mash](https://github.com/intridea/hashie), so you can access any of the underlying data directly. Note that data is retrieved using Google's JSON API so the equivalent content of an XML element from the XML API is stored under the key "$t".
|
22
|
+
|
21
23
|
## TODO
|
22
24
|
|
23
25
|
I welcome patches and pull requests, see the guidelines below (handily auto-generated
|
24
26
|
by jeweler).
|
25
27
|
|
26
28
|
* Tests! (using RSpec, please)
|
29
|
+
* Read more contact information (structured name, address, phone, ...)
|
27
30
|
* Posting/putting/deleting groups, contacts and their photos
|
28
31
|
* Support ClientLogin
|
29
32
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/google_contacts_api.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{google_contacts_api}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alvin Liang"]
|
12
|
-
s.date = %q{2011-07-
|
12
|
+
s.date = %q{2011-07-09}
|
13
13
|
s.description = %q{Lets you read from the Google Contacts API. Posting to come later. Tests to come later.}
|
14
14
|
s.email = %q{ayliang@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,6 +25,15 @@ Gem::Specification.new do |s|
|
|
25
25
|
"VERSION",
|
26
26
|
"google_contacts_api.gemspec",
|
27
27
|
"lib/google_contacts_api.rb",
|
28
|
+
"lib/google_contacts_api/api.rb",
|
29
|
+
"lib/google_contacts_api/contact.rb",
|
30
|
+
"lib/google_contacts_api/contact_set.rb",
|
31
|
+
"lib/google_contacts_api/contacts.rb",
|
32
|
+
"lib/google_contacts_api/group.rb",
|
33
|
+
"lib/google_contacts_api/group_set.rb",
|
34
|
+
"lib/google_contacts_api/result.rb",
|
35
|
+
"lib/google_contacts_api/result_set.rb",
|
36
|
+
"lib/google_contacts_api/user.rb",
|
28
37
|
"test/helper.rb",
|
29
38
|
"test/test_google_contacts_api.rb"
|
30
39
|
]
|
data/lib/google_contacts_api.rb
CHANGED
@@ -1,304 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
BASE_URL = "https://www.google.com/m8/feeds/"
|
11
|
-
|
12
|
-
attr_reader :oauth
|
13
|
-
def initialize(oauth)
|
14
|
-
# TODO: Later, accept ClientLogin
|
15
|
-
@oauth = oauth
|
16
|
-
end
|
17
|
-
|
18
|
-
# Get request to specified link, with query params
|
19
|
-
# For get, post, put, delete, always use JSON, it's simpler
|
20
|
-
# and lets us use Hashie::Mash. Note that in the JSON conversion from XML,
|
21
|
-
# ":" is replaced with $, element content is keyed with $t
|
22
|
-
def get(link, params = {}, headers = {})
|
23
|
-
params["alt"] = "json"
|
24
|
-
@oauth.get("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
25
|
-
end
|
26
|
-
|
27
|
-
# Post request to specified link, with query params
|
28
|
-
# Not tried yet, might be issues with params
|
29
|
-
def post(link, params = {}, headers = {})
|
30
|
-
params["alt"] = "json"
|
31
|
-
@oauth.post("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Put request to specified link, with query params
|
35
|
-
# Not tried yet
|
36
|
-
def put(link, params = {}, headers = {})
|
37
|
-
params["alt"] = "json"
|
38
|
-
@oauth.put("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Delete request to specified link, with query params
|
42
|
-
# Not tried yet
|
43
|
-
def delete(link, params = {}, headers = {})
|
44
|
-
params["alt"] = "json"
|
45
|
-
@oauth.delete("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
module Contacts
|
50
|
-
# Retrieve the contacts for this user or group
|
51
|
-
def contacts(params = {})
|
52
|
-
params = params.with_indifferent_access
|
53
|
-
|
54
|
-
# compose params into a string
|
55
|
-
# See http://code.google.com/apis/contacts/docs/3.0/reference.html#Parameters
|
56
|
-
# alt, q, max-results, start-index, updated-min,
|
57
|
-
# orderby, showdeleted, requirealldeleted, sortorder, group
|
58
|
-
params["max-results"] = 100000 unless params.key?("max-results")
|
59
|
-
url = "contacts/default/full"
|
60
|
-
response = @api.get(url, params)
|
61
|
-
|
62
|
-
# TODO: Define some fancy exceptions
|
63
|
-
case response.code
|
64
|
-
when 401; raise
|
65
|
-
when 403; raise
|
66
|
-
when 404; raise
|
67
|
-
when 400...500; raise
|
68
|
-
when 500...600; raise
|
69
|
-
end
|
70
|
-
ContactSet.new(response.body, @api)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class User
|
75
|
-
include Contacts
|
76
|
-
|
77
|
-
attr_reader :api
|
78
|
-
def initialize(oauth)
|
79
|
-
@api = GoogleContactsApi::Api.new(oauth)
|
80
|
-
end
|
81
|
-
|
82
|
-
# Retrieve the groups for this user
|
83
|
-
# TODO: Handle 403, 404, 401
|
84
|
-
def groups(params = {})
|
85
|
-
params = params.with_indifferent_access
|
86
|
-
# compose params into a string
|
87
|
-
# See http://code.google.com/apis/contacts/docs/3.0/reference.html#Parameters
|
88
|
-
# alt, q, max-results, start-index, updated-min,
|
89
|
-
# orderby, showdeleted, requirealldeleted, sortorder
|
90
|
-
params["max-results"] = 100000 unless params.key?("max-results")
|
91
|
-
url = "groups/default/full"
|
92
|
-
# TODO: So weird thing, version 3 doesn't return system groups
|
93
|
-
# When it does, uncomment this line and use it to request instead
|
94
|
-
# response = @api.get(url, params)
|
95
|
-
response = @api.get(url, params, {"GData-Version" => "2"})
|
96
|
-
|
97
|
-
case response.code
|
98
|
-
when 401; raise
|
99
|
-
when 403; raise
|
100
|
-
when 404; raise
|
101
|
-
when 400...500; raise
|
102
|
-
when 500...600; raise
|
103
|
-
end
|
104
|
-
GroupSet.new(response.body, @api)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Base class for GroupSet and ContactSet
|
109
|
-
class ResultSet
|
110
|
-
include Enumerable
|
111
|
-
attr_reader :api
|
112
|
-
attr_accessor :total_results, :start_index, :items_per_page, :parsed
|
113
|
-
|
114
|
-
def initialize(response_body, api = nil)
|
115
|
-
@api = api
|
116
|
-
@parsed = Hashie::Mash.new(JSON.parse(response_body))
|
117
|
-
@total_results = @parsed.feed["openSearch$totalResults"]["$t"].to_i
|
118
|
-
@start_index = @parsed.feed["openSearch$startIndex"]["$t"].to_i
|
119
|
-
@items_per_page = @parsed.feed["openSearch$itemsPerPage"]["$t"].to_i
|
120
|
-
@results = []
|
121
|
-
end
|
122
|
-
|
123
|
-
def each
|
124
|
-
@results.each { |x| yield x }
|
125
|
-
end
|
126
|
-
|
127
|
-
def has_more?
|
128
|
-
# 1-based indexing
|
129
|
-
@start_index - 1 + @items_per_page <= @total_results
|
130
|
-
end
|
131
|
-
|
132
|
-
def inspect
|
133
|
-
"<#{self.class}: @start_index=#{@start_index}, @items_per_page=#{@items_per_page}, @total_results=#{@total_results}>"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
class GroupSet < ResultSet
|
138
|
-
# Populate from a response that contains contacts
|
139
|
-
def initialize(response_body, api = nil)
|
140
|
-
super
|
141
|
-
@results = @parsed.feed.entry.map { |e| Group.new(e, nil, api) }
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
class ContactSet < ResultSet
|
146
|
-
# Populate from a response that contains contacts
|
147
|
-
def initialize(response_body, api = nil)
|
148
|
-
super
|
149
|
-
@results = @parsed.feed.entry.map { |e| Contact.new(e, nil, api) }
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
# Base class for Group and Contact
|
154
|
-
class Result < Hashie::Mash
|
155
|
-
# Note that the title is really just the (full) name
|
156
|
-
# ":" replaced with $, element content is keyed with $t
|
157
|
-
|
158
|
-
# These are the accessors we can write
|
159
|
-
# :id, :title, :updated, :content
|
160
|
-
|
161
|
-
attr_reader :api
|
162
|
-
# Populate from a single result Hash/Hashie
|
163
|
-
def initialize(source_hash = nil, default = nil, api = nil, &blk)
|
164
|
-
@api = api if api
|
165
|
-
super(source_hash, default, &blk)
|
166
|
-
end
|
167
|
-
|
168
|
-
# TODO: Conditional retrieval? There might not be an etag in the
|
169
|
-
# JSON representation, there is in the XML representation
|
170
|
-
def etag
|
171
|
-
end
|
172
|
-
|
173
|
-
def id
|
174
|
-
_id = self["id"]
|
175
|
-
_id ? _id["$t"] : nil
|
176
|
-
end
|
177
|
-
|
178
|
-
def title
|
179
|
-
_title = self["title"]
|
180
|
-
_title ? _title["$t"] : nil
|
181
|
-
end
|
182
|
-
|
183
|
-
def content
|
184
|
-
_content = self["content"]
|
185
|
-
_content ? content["$t"] : nil
|
186
|
-
end
|
187
|
-
|
188
|
-
def updated
|
189
|
-
_updated = self["updated"]
|
190
|
-
_updated ? DateTime.parse(_updated["$t"]) : nil
|
191
|
-
end
|
192
|
-
|
193
|
-
# Returns the array of categories, as category is an array for Hashie.
|
194
|
-
def categories
|
195
|
-
category
|
196
|
-
end
|
197
|
-
|
198
|
-
def deleted?
|
199
|
-
raise NotImplementedError
|
200
|
-
end
|
201
|
-
|
202
|
-
def inspect
|
203
|
-
"<#{self.class}: #{title}>"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
class Group < Result
|
208
|
-
include Contacts
|
209
|
-
# Populate from a single entry element in the result response
|
210
|
-
# when requesting a set of Contacts
|
211
|
-
|
212
|
-
def system_group?
|
213
|
-
!self["gContact$systemGroup"].nil?
|
214
|
-
end
|
215
|
-
|
216
|
-
def contacts(params = {})
|
217
|
-
# contacts in this group
|
218
|
-
@contacts ||= super({"group" => self.id}.merge(params))
|
219
|
-
end
|
220
|
-
|
221
|
-
def contacts!(params = {})
|
222
|
-
# contacts in this group
|
223
|
-
@contacts = super({"group" => self.id}.merge(params))
|
224
|
-
end
|
225
|
-
|
226
|
-
# Returns the array of links, as link is an array for Hashie.
|
227
|
-
def links
|
228
|
-
self["link"].map { |l| l.href }
|
229
|
-
end
|
230
|
-
|
231
|
-
def self_link
|
232
|
-
_link = self["link"].find { |l| l.rel == "self" }
|
233
|
-
_link ? _link.href : nil
|
234
|
-
end
|
235
|
-
|
236
|
-
def edit_link
|
237
|
-
_link = self["link"].find { |l| l.rel == "edit" }
|
238
|
-
_link ? _link.href : nil
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
class Contact < Result
|
243
|
-
# :categories, (:content again), :links, (:title again), :email
|
244
|
-
# :extended_properties, :deleted, :im, :name,
|
245
|
-
# :organizations, :phone_numbers, :structured_postal_addresses, :where
|
246
|
-
|
247
|
-
# Returns the array of links, as link is an array for Hashie.
|
248
|
-
def links
|
249
|
-
self["link"].map { |l| l.href }
|
250
|
-
end
|
251
|
-
|
252
|
-
def self_link
|
253
|
-
_link = self["link"].find { |l| l.rel == "self" }
|
254
|
-
_link ? _link.href : nil
|
255
|
-
end
|
256
|
-
|
257
|
-
def alternate_link
|
258
|
-
_link = self["link"].find { |l| l.rel == "alternate" }
|
259
|
-
_link ? _link.href : nil
|
260
|
-
end
|
261
|
-
|
262
|
-
def photo_link
|
263
|
-
_link = self["link"].find { |l| l.rel == "http://schemas.google.com/contacts/2008/rel#photo" }
|
264
|
-
_link ? _link.href : nil
|
265
|
-
end
|
266
|
-
|
267
|
-
# Returns binary data for the photo. You can probably
|
268
|
-
# use it in a data-uri. This is in PNG format.
|
269
|
-
def photo
|
270
|
-
return nil unless photo_link
|
271
|
-
response = @api.oauth.get(photo_link)
|
272
|
-
|
273
|
-
case response.code
|
274
|
-
# maybe return a placeholder instead of nil
|
275
|
-
when 400; return nil
|
276
|
-
when 401; return nil
|
277
|
-
when 403; return nil
|
278
|
-
when 404; return nil
|
279
|
-
when 400...500; return nil
|
280
|
-
when 500...600; return nil
|
281
|
-
else; return response.body
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
def edit_photo_link
|
286
|
-
_link = self["link"].find { |l| l.rel == "http://schemas.google.com/contacts/2008/rel#edit_photo" }
|
287
|
-
_link ? _link.href : nil
|
288
|
-
end
|
289
|
-
|
290
|
-
def edit_link
|
291
|
-
_link = self["link"].find { |l| l.rel == "edit" }
|
292
|
-
_link ? _link.href : nil
|
293
|
-
end
|
294
|
-
|
295
|
-
def emails
|
296
|
-
self["gd$email"].map { |e| e.address }
|
297
|
-
end
|
298
|
-
|
299
|
-
def primary_email
|
300
|
-
_email = self["gd$email"].find { |e| e.primary == "true" }
|
301
|
-
_email ? _email.address : nil
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
1
|
+
require 'google_contacts_api/api'
|
2
|
+
require 'google_contacts_api/contacts'
|
3
|
+
require 'google_contacts_api/user'
|
4
|
+
require 'google_contacts_api/result_set'
|
5
|
+
require 'google_contacts_api/group_set'
|
6
|
+
require 'google_contacts_api/contact_set'
|
7
|
+
require 'google_contacts_api/result'
|
8
|
+
require 'google_contacts_api/group'
|
9
|
+
require 'google_contacts_api/contact'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
module GoogleContactsApi
|
4
|
+
class Api
|
5
|
+
# keep separate in case of new auth method
|
6
|
+
BASE_URL = "https://www.google.com/m8/feeds/"
|
7
|
+
|
8
|
+
attr_reader :oauth
|
9
|
+
def initialize(oauth)
|
10
|
+
# TODO: Later, accept ClientLogin
|
11
|
+
@oauth = oauth
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get request to specified link, with query params
|
15
|
+
# For get, post, put, delete, always use JSON, it's simpler
|
16
|
+
# and lets us use Hashie::Mash. Note that in the JSON conversion from XML,
|
17
|
+
# ":" is replaced with $, element content is keyed with $t
|
18
|
+
def get(link, params = {}, headers = {})
|
19
|
+
params["alt"] = "json"
|
20
|
+
@oauth.get("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Post request to specified link, with query params
|
24
|
+
# Not tried yet, might be issues with params
|
25
|
+
def post(link, params = {}, headers = {})
|
26
|
+
params["alt"] = "json"
|
27
|
+
@oauth.post("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Put request to specified link, with query params
|
31
|
+
# Not tried yet
|
32
|
+
def put(link, params = {}, headers = {})
|
33
|
+
params["alt"] = "json"
|
34
|
+
@oauth.put("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Delete request to specified link, with query params
|
38
|
+
# Not tried yet
|
39
|
+
def delete(link, params = {}, headers = {})
|
40
|
+
params["alt"] = "json"
|
41
|
+
@oauth.delete("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module GoogleContactsApi
|
2
|
+
class Contact < GoogleContactsApi::Result
|
3
|
+
# :categories, (:content again), :links, (:title again), :email
|
4
|
+
# :extended_properties, :deleted, :im, :name,
|
5
|
+
# :organizations, :phone_numbers, :structured_postal_addresses, :where
|
6
|
+
|
7
|
+
# Returns the array of links, as link is an array for Hashie.
|
8
|
+
def links
|
9
|
+
self["link"].map { |l| l.href }
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns link to get this contact
|
13
|
+
def self_link
|
14
|
+
_link = self["link"].find { |l| l.rel == "self" }
|
15
|
+
_link ? _link.href : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns alternative, possibly off-Google home page link
|
19
|
+
def alternate_link
|
20
|
+
_link = self["link"].find { |l| l.rel == "alternate" }
|
21
|
+
_link ? _link.href : nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns link for photo
|
25
|
+
# (still need authentication to get the photo data, though)
|
26
|
+
def photo_link
|
27
|
+
_link = self["link"].find { |l| l.rel == "http://schemas.google.com/contacts/2008/rel#photo" }
|
28
|
+
_link ? _link.href : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns binary data for the photo. You can probably
|
32
|
+
# use it in a data-uri. This is in PNG format.
|
33
|
+
def photo
|
34
|
+
return nil unless @api && photo_link
|
35
|
+
response = @api.oauth.get(photo_link)
|
36
|
+
|
37
|
+
case response.code
|
38
|
+
# maybe return a placeholder instead of nil
|
39
|
+
when 400; return nil
|
40
|
+
when 401; return nil
|
41
|
+
when 403; return nil
|
42
|
+
when 404; return nil
|
43
|
+
when 400...500; return nil
|
44
|
+
when 500...600; return nil
|
45
|
+
else; return response.body
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns link to add/replace the photo
|
50
|
+
def edit_photo_link
|
51
|
+
_link = self["link"].find { |l| l.rel == "http://schemas.google.com/contacts/2008/rel#edit_photo" }
|
52
|
+
_link ? _link.href : nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns link to edit the contact
|
56
|
+
def edit_link
|
57
|
+
_link = self["link"].find { |l| l.rel == "edit" }
|
58
|
+
_link ? _link.href : nil
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns all email addresses for the contact
|
62
|
+
def emails
|
63
|
+
self["gd$email"].map { |e| e.address }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns primary email for the contact
|
67
|
+
def primary_email
|
68
|
+
_email = self["gd$email"].find { |e| e.primary == "true" }
|
69
|
+
_email ? _email.address : nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module GoogleContactsApi
|
2
|
+
class ContactSet < GoogleContactsApi::ResultSet
|
3
|
+
# Populate from a response that contains contacts
|
4
|
+
def initialize(response_body, api = nil)
|
5
|
+
super
|
6
|
+
@results = @parsed.feed.entry.map { |e| GoogleContactsApi::Contact.new(e, nil, api) }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GoogleContactsApi
|
2
|
+
module Contacts
|
3
|
+
# Retrieve the contacts for this user or group
|
4
|
+
def contacts(params = {})
|
5
|
+
# TODO: Should return empty ContactSet (haven't implemented one yet)
|
6
|
+
return [] unless @api
|
7
|
+
params = params.with_indifferent_access
|
8
|
+
|
9
|
+
# compose params into a string
|
10
|
+
# See http://code.google.com/apis/contacts/docs/3.0/reference.html#Parameters
|
11
|
+
# alt, q, max-results, start-index, updated-min,
|
12
|
+
# orderby, showdeleted, requirealldeleted, sortorder, group
|
13
|
+
params["max-results"] = 100000 unless params.key?("max-results")
|
14
|
+
url = "contacts/default/full"
|
15
|
+
response = @api.get(url, params)
|
16
|
+
|
17
|
+
# TODO: Define some fancy exceptions
|
18
|
+
case response.code
|
19
|
+
when 401; raise
|
20
|
+
when 403; raise
|
21
|
+
when 404; raise
|
22
|
+
when 400...500; raise
|
23
|
+
when 500...600; raise
|
24
|
+
end
|
25
|
+
GoogleContactsApi::ContactSet.new(response.body, @api)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GoogleContactsApi
|
2
|
+
class Group < GoogleContactsApi::Result
|
3
|
+
include GoogleContactsApi::Contacts
|
4
|
+
# Populate from a single entry element in the result response
|
5
|
+
# when requesting a set of Contacts
|
6
|
+
|
7
|
+
def system_group?
|
8
|
+
!self["gContact$systemGroup"].nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def contacts(params = {})
|
12
|
+
# contacts in this group
|
13
|
+
@contacts ||= super({"group" => self.id}.merge(params))
|
14
|
+
end
|
15
|
+
|
16
|
+
def contacts!(params = {})
|
17
|
+
# contacts in this group
|
18
|
+
@contacts = super({"group" => self.id}.merge(params))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the array of links, as link is an array for Hashie.
|
22
|
+
def links
|
23
|
+
self["link"].map { |l| l.href }
|
24
|
+
end
|
25
|
+
|
26
|
+
def self_link
|
27
|
+
_link = self["link"].find { |l| l.rel == "self" }
|
28
|
+
_link ? _link.href : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def edit_link
|
32
|
+
_link = self["link"].find { |l| l.rel == "edit" }
|
33
|
+
_link ? _link.href : nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module GoogleContactsApi
|
2
|
+
class GroupSet < GoogleContactsApi::ResultSet
|
3
|
+
# Populate from a response that contains contacts
|
4
|
+
def initialize(response_body, api = nil)
|
5
|
+
super
|
6
|
+
@results = @parsed.feed.entry.map { |e| GoogleContactsApi::Group.new(e, nil, api) }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module GoogleContactsApi
|
4
|
+
# Base class for Group and Contact
|
5
|
+
class Result < Hashie::Mash
|
6
|
+
# Note that the title is really just the (full) name
|
7
|
+
# ":" replaced with $, element content is keyed with $t
|
8
|
+
|
9
|
+
# These are the accessors we can write
|
10
|
+
# :id, :title, :updated, :content
|
11
|
+
|
12
|
+
attr_reader :api
|
13
|
+
# Populate from a single result Hash/Hashie
|
14
|
+
def initialize(source_hash = nil, default = nil, api = nil, &blk)
|
15
|
+
@api = api if api
|
16
|
+
super(source_hash, default, &blk)
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: Conditional retrieval? There might not be an etag in the
|
20
|
+
# JSON representation, there is in the XML representation
|
21
|
+
def etag
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
_id = self["id"]
|
26
|
+
_id ? _id["$t"] : nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def title
|
30
|
+
_title = self["title"]
|
31
|
+
_title ? _title["$t"] : nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def content
|
35
|
+
_content = self["content"]
|
36
|
+
_content ? _content["$t"] : nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def updated
|
40
|
+
_updated = self["updated"]
|
41
|
+
_updated ? DateTime.parse(_updated["$t"]) : nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the array of categories, as category is an array for Hashie.
|
45
|
+
# There is a scheme and a term.
|
46
|
+
def categories
|
47
|
+
category
|
48
|
+
end
|
49
|
+
|
50
|
+
def deleted?
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
"<#{self.class}: #{title}>"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module GoogleContactsApi
|
4
|
+
# Base class for GroupSet and ContactSet
|
5
|
+
class ResultSet
|
6
|
+
include Enumerable
|
7
|
+
attr_reader :api
|
8
|
+
attr_accessor :total_results, :start_index, :items_per_page, :parsed
|
9
|
+
|
10
|
+
# Initialize a new ResultSet from the response, with the given
|
11
|
+
# GoogleContacts::Api object if specified.
|
12
|
+
def initialize(response_body, api = nil)
|
13
|
+
@api = api
|
14
|
+
@parsed = Hashie::Mash.new(JSON.parse(response_body))
|
15
|
+
@total_results = @parsed.feed["openSearch$totalResults"]["$t"].to_i
|
16
|
+
@start_index = @parsed.feed["openSearch$startIndex"]["$t"].to_i
|
17
|
+
@items_per_page = @parsed.feed["openSearch$itemsPerPage"]["$t"].to_i
|
18
|
+
@results = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Yields to block for each result
|
22
|
+
def each
|
23
|
+
@results.each { |x| yield x }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return true if there are more results with the same
|
27
|
+
# parameters you used
|
28
|
+
def has_more?
|
29
|
+
# 1-based indexing
|
30
|
+
@start_index - 1 + @items_per_page <= @total_results
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect #:nodoc:
|
34
|
+
"<#{self.class}: @start_index=#{@start_index}, @items_per_page=#{@items_per_page}, @total_results=#{@total_results}>"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module GoogleContactsApi
|
2
|
+
class User
|
3
|
+
include GoogleContactsApi::Contacts
|
4
|
+
|
5
|
+
attr_reader :api
|
6
|
+
def initialize(oauth)
|
7
|
+
@api = GoogleContactsApi::Api.new(oauth)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Retrieve the groups for this user
|
11
|
+
# TODO: Handle 403, 404, 401
|
12
|
+
def groups(params = {})
|
13
|
+
params = params.with_indifferent_access
|
14
|
+
# compose params into a string
|
15
|
+
# See http://code.google.com/apis/contacts/docs/3.0/reference.html#Parameters
|
16
|
+
# alt, q, max-results, start-index, updated-min,
|
17
|
+
# orderby, showdeleted, requirealldeleted, sortorder
|
18
|
+
params["max-results"] = 100000 unless params.key?("max-results")
|
19
|
+
url = "groups/default/full"
|
20
|
+
# TODO: So weird thing, version 3 doesn't return system groups
|
21
|
+
# When it does, uncomment this line and use it to request instead
|
22
|
+
# response = @api.get(url, params)
|
23
|
+
response = @api.get(url, params, {"GData-Version" => "2"})
|
24
|
+
|
25
|
+
case response.code
|
26
|
+
when 401; raise
|
27
|
+
when 403; raise
|
28
|
+
when 404; raise
|
29
|
+
when 400...500; raise
|
30
|
+
when 500...600; raise
|
31
|
+
end
|
32
|
+
GoogleContactsApi::GroupSet.new(response.body, @api)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: google_contacts_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Alvin Liang
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-07-
|
13
|
+
date: 2011-07-09 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -141,6 +141,15 @@ files:
|
|
141
141
|
- VERSION
|
142
142
|
- google_contacts_api.gemspec
|
143
143
|
- lib/google_contacts_api.rb
|
144
|
+
- lib/google_contacts_api/api.rb
|
145
|
+
- lib/google_contacts_api/contact.rb
|
146
|
+
- lib/google_contacts_api/contact_set.rb
|
147
|
+
- lib/google_contacts_api/contacts.rb
|
148
|
+
- lib/google_contacts_api/group.rb
|
149
|
+
- lib/google_contacts_api/group_set.rb
|
150
|
+
- lib/google_contacts_api/result.rb
|
151
|
+
- lib/google_contacts_api/result_set.rb
|
152
|
+
- lib/google_contacts_api/user.rb
|
144
153
|
- test/helper.rb
|
145
154
|
- test/test_google_contacts_api.rb
|
146
155
|
has_rdoc: true
|
@@ -157,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
166
|
requirements:
|
158
167
|
- - ">="
|
159
168
|
- !ruby/object:Gem::Version
|
160
|
-
hash:
|
169
|
+
hash: 620704382492912941
|
161
170
|
segments:
|
162
171
|
- 0
|
163
172
|
version: "0"
|