google_r 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ require 'ostruct'
2
+
3
+ class GoogleR::Calendar
4
+ attr_accessor :google_id, :etag, :summary, :description, :time_zone
5
+
6
+ def self.url
7
+ "https://www.googleapis.com"
8
+ end
9
+
10
+ def self.api_headers
11
+ {
12
+ 'GData-Version' => '3.0',
13
+ 'Content-Type' => 'application/json',
14
+ }
15
+ end
16
+
17
+ def self.path
18
+ "/calendar/v3/users/me/calendarList"
19
+ end
20
+
21
+ def path
22
+ if new?
23
+ "/calendar/v3/calendars"
24
+ else
25
+ "/calendar/v3/calendars/#{google_id}"
26
+ end
27
+ end
28
+
29
+ def self.from_json(json, *attrs)
30
+ if json["kind"] == "calendar#calendar" || json["kind"] == "calendar#calendarListEntry"
31
+ calendar = self.new
32
+ calendar.google_id = json["id"]
33
+ calendar.etag = json["etag"]
34
+ calendar.summary = json["summary"]
35
+ calendar.description = json["description"]
36
+ calendar.time_zone = json["timeZone"]
37
+ calendar
38
+ else
39
+ raise "Not implemented:\n#{json.inspect}"
40
+ end
41
+ end
42
+
43
+ def to_google(yajl_opts = {})
44
+ hash = {
45
+ "kind" => "calendar#calendar",
46
+ }
47
+ hash["etag"] = etag if etag
48
+ hash["id"] = google_id if google_id
49
+ hash["summary"] = summary if summary
50
+ hash["description"] = description if description
51
+ hash["timeZone"] = time_zone if time_zone
52
+ Yajl::Encoder.encode(hash, yajl_opts)
53
+ end
54
+
55
+ def new?
56
+ self.google_id.nil?
57
+ end
58
+ end
@@ -0,0 +1,241 @@
1
+ require 'ostruct'
2
+
3
+ class GoogleR::Contact
4
+ Email = Struct.new(:address, :display_name, :label, :rel, :primary)
5
+ Phone = Struct.new(:rel, :text)
6
+ Organization = Struct.new(:name, :title, :rel)
7
+ Address = Struct.new(:street, :neighborhood, :pobox, :postcode, :city, :region, :country, :rel)
8
+ Website = Struct.new(:href, :rel)
9
+
10
+ attr_reader :emails, :phones, :organizations, :addresses, :groups, :websites
11
+ attr_accessor :given_name, :additional_name, :name_prefix, :name_suffix, :family_name,
12
+ :google_id, :etag, :content, :updated, :user_fields, :nickname
13
+
14
+ def initialize
15
+ @emails = []
16
+ @phones = []
17
+ @organizations = []
18
+ @addresses = []
19
+ @groups = []
20
+ @websites = []
21
+ @user_fields = {}
22
+ end
23
+
24
+ def self.url
25
+ "https://www.google.com"
26
+ end
27
+
28
+ def self.path
29
+ "/m8/feeds/contacts/default/full/"
30
+ end
31
+
32
+ def self.api_headers
33
+ {
34
+ 'GData-Version' => '3.0',
35
+ 'Content-Type' => 'application/atom+xml',
36
+ }
37
+ end
38
+
39
+ def path
40
+ if new?
41
+ self.class.path
42
+ else
43
+ self.class.path + google_id.split("/")[-1]
44
+ end
45
+ end
46
+
47
+ def full_name
48
+ [name_prefix, given_name, additional_name, family_name, name_suffix].compact.join(" ")
49
+ end
50
+
51
+ def to_google
52
+ builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
53
+ root_attrs = {
54
+ 'xmlns:atom' => 'http://www.w3.org/2005/Atom',
55
+ 'xmlns:gd' => 'http://schemas.google.com/g/2005',
56
+ 'xmlns:gContact' => 'http://schemas.google.com/contact/2008',
57
+ }
58
+ root_attrs["gd:etag"] = self.etag unless new?
59
+ xml.entry(root_attrs) do
60
+ unless new?
61
+ xml.id_ self.google_id
62
+ end
63
+
64
+ xml.updated self.updated.strftime("%Y-%m-%dT%H:%M:%S.%LZ") unless self.updated.nil?
65
+
66
+ if self.full_name != ''
67
+ xml['gd'].name do
68
+ xml['gd'].givenName self.given_name unless self.given_name.nil?
69
+ xml['gd'].additionalName self.additional_name unless self.additional_name.nil?
70
+ xml['gd'].familyName self.family_name unless self.family_name.nil?
71
+ xml['gd'].namePrefix self.name_prefix unless self.name_prefix.nil?
72
+ xml['gd'].nameSuffix self.name_suffix unless self.name_suffix.nil?
73
+ end
74
+ end
75
+
76
+ xml['atom'].content({'type' => 'text'}, self.content) unless self.content.nil?
77
+ xml['gContact'].nickname self.nickname unless self.nickname.nil?
78
+
79
+ phones.each do |phone|
80
+ xml['gd'].phoneNumber({'rel' => phone.rel}, phone.text)
81
+ end
82
+
83
+ emails.each do |email|
84
+ attrs = {'address' => email.address}
85
+ attrs['rel'] = email.rel if email.rel
86
+ attrs['label'] = email.label if email.label
87
+ attrs['primary'] = email.primary
88
+ xml['gd'].email(attrs)
89
+ end
90
+
91
+ organizations.each do |org|
92
+ xml['gd'].organization({:rel => org.rel}) do
93
+ xml['gd'].orgName org.name
94
+ xml['gd'].orgTitle org.title
95
+ end
96
+ end
97
+
98
+ addresses.each do |address|
99
+ xml['gd'].structuredPostalAddress({'rel' => address.rel}) do
100
+ xml['gd'].street address.street unless address.street.nil?
101
+ xml['gd'].neighborhood address.neighborhood unless address.neighborhood.nil?
102
+ xml['gd'].pobox address.pobox unless address.pobox.nil?
103
+ xml['gd'].postcode address.postcode unless address.postcode.nil?
104
+ xml['gd'].city address.city unless address.city.nil?
105
+ xml['gd'].region address.region unless address.region.nil?
106
+ xml['gd'].country address.country unless address.country.nil?
107
+ end
108
+ end
109
+
110
+ user_fields.each do |key, value|
111
+ xml['gContact'].userDefinedField({'key' => key, 'value' => value})
112
+ end
113
+
114
+ websites.each do |website|
115
+ xml['gContact'].website({'href' => website.href, 'rel' => website.rel})
116
+ end
117
+
118
+ groups.each do |group|
119
+ xml['gContact'].groupMembershipInfo({'href' => group.google_id, 'deleted' => 'false'})
120
+ end
121
+
122
+ xml.parent.namespace = xml.parent.namespace_definitions.find { |ns| ns.prefix == "atom" }
123
+ end
124
+ end
125
+ builder.to_xml
126
+ end
127
+
128
+ def add_email(email)
129
+ @emails << email
130
+ end
131
+
132
+ def add_phone(phone)
133
+ @phones << phone
134
+ end
135
+
136
+ def add_organization(organization)
137
+ @organizations << organization
138
+ end
139
+
140
+ def add_address(address)
141
+ @addresses << address
142
+ end
143
+
144
+ def add_group(group)
145
+ @groups << group
146
+ end
147
+
148
+ def add_website(website)
149
+ @websites << website
150
+ end
151
+
152
+ def self.from_xml(doc, *attrs)
153
+ is_collection = doc.search("totalResults").size > 0
154
+ return doc.search("entry").map { |e| from_xml(e) } if is_collection
155
+
156
+ contact = GoogleR::Contact.new
157
+
158
+ google_id = doc.search("id")
159
+
160
+ if google_id.empty?
161
+ contact.etag = contact.google_id = nil
162
+ else
163
+ contact.etag = doc["etag"]
164
+ contact.google_id = google_id.inner_text
165
+ end
166
+
167
+ doc.search("email").each do |email|
168
+ contact.add_email(GoogleR::Contact::Email.new(email[:address], email[:display_name], email[:label], email[:rel], email[:primary] == "true"))
169
+ end
170
+
171
+ doc.search("phoneNumber").each do |phone|
172
+ contact.add_phone(GoogleR::Contact::Phone.new(phone[:rel], phone.inner_text))
173
+ end
174
+
175
+ doc.search("organization").each do |org|
176
+ name = org.search("orgName").inner_text
177
+ title = org.search("orgTitle").inner_text
178
+ rel = org[:rel]
179
+ contact.add_organization(GoogleR::Contact::Organization.new(name, title, rel))
180
+ end
181
+
182
+ doc.search("structuredPostalAddress").each do |address|
183
+ rel = address[:rel]
184
+ street = address.search("street").inner_text
185
+ neighborhood = address.search("neighborhood").inner_text
186
+ pobox = address.search("pobox").inner_text
187
+ postcode = address.search("postcode").inner_text
188
+ city = address.search("city").inner_text
189
+ region = address.search("region").inner_text
190
+ country = address.search("country").inner_text
191
+ contact.add_address(GoogleR::Contact::Address.new(street, neighborhood, pobox, postcode, city, region, country, rel))
192
+ end
193
+
194
+ doc.search("userDefinedField").each do |field|
195
+ contact.user_fields[field[:key]] = field[:value]
196
+ end
197
+
198
+ doc.search("groupMembershipInfo").each do |entry|
199
+ group = GoogleR::Group.new
200
+ group.google_id = entry[:href]
201
+ contact.add_group(group)
202
+ end
203
+
204
+ doc.search("website").each do |entry|
205
+ website = GoogleR::Contact::Website.new
206
+ website.href = entry[:href]
207
+ website.rel = entry[:rel]
208
+ contact.add_website(website)
209
+ end
210
+
211
+ name_prefix = doc.search("name/namePrefix")
212
+ contact.name_prefix = name_prefix.inner_text unless name_prefix.empty?
213
+
214
+ given_name = doc.search("name/givenName")
215
+ contact.given_name = given_name.inner_text unless given_name.empty?
216
+
217
+ additional_name = doc.search("name/additionalName")
218
+ contact.additional_name = additional_name.inner_text unless additional_name.empty?
219
+
220
+ family_name = doc.search("name/familyName")
221
+ contact.family_name = family_name.inner_text unless family_name.empty?
222
+
223
+ name_suffix = doc.search("name/nameSuffix")
224
+ contact.name_suffix = name_suffix.inner_text unless name_suffix.empty?
225
+
226
+ content = doc.search("content")
227
+ contact.content = content.inner_text unless content.empty?
228
+
229
+ updated = doc.search("updated")
230
+ contact.updated = Time.parse(updated.inner_text) unless updated.empty?
231
+
232
+ nickname = doc.search("nickname")
233
+ contact.nickname = nickname.inner_text unless nickname.empty?
234
+
235
+ contact
236
+ end
237
+
238
+ def new?
239
+ self.google_id.nil?
240
+ end
241
+ end
@@ -0,0 +1,99 @@
1
+ require 'ostruct'
2
+
3
+ class GoogleR::Event
4
+ attr_accessor :google_id, :etag, :start_time, :end_time, :calendar, :description, :summary,
5
+ :visibility, :updated, :created, :status, :start_time_zone, :end_time_zone
6
+
7
+ def initialize(calendar, opts = {})
8
+ self.calendar = calendar
9
+ self.visibility = opts[:visibility] || "private"
10
+ end
11
+
12
+ def self.url
13
+ "https://www.googleapis.com"
14
+ end
15
+
16
+ def self.api_headers
17
+ {
18
+ 'GData-Version' => '3.0',
19
+ 'Content-Type' => 'application/json',
20
+ }
21
+ end
22
+
23
+ def path
24
+ if new?
25
+ "/calendar/v3/calendars/#{calendar.google_id}/events"
26
+ else
27
+ "/calendar/v3/calendars/#{calendar.google_id}/events/#{google_id}"
28
+ end
29
+ end
30
+
31
+ def self.path(calendar_google_id)
32
+ "/calendar/v3/calendars/#{calendar_google_id}/events"
33
+ end
34
+
35
+ def self.from_json(json, *attrs)
36
+ calendar = attrs[0].calendar
37
+
38
+ if json["kind"] == "calendar#events"
39
+ (json["items"] || []).map { |e| from_json(e, *attrs) }
40
+ elsif json["kind"] == "calendar#event"
41
+ event = self.new(calendar)
42
+ event.google_id = json["id"]
43
+ event.etag = json["etag"]
44
+ event.description = json["description"]
45
+ event.summary = json["summary"]
46
+ event.visibility = json["visibility"]
47
+ event.status = json["status"]
48
+
49
+ start_time = json["start"]["dateTime"] || json["start"]["date"]
50
+ if start_time
51
+ event.start_time = Time.parse(start_time)
52
+ event.start_time_zone = json["start"]["timeZone"]
53
+ end
54
+
55
+ end_time = json["end"]["dateTime"] || json["end"]["date"]
56
+ if end_time
57
+ event.end_time = Time.parse(end_time)
58
+ event.end_time_zone = json["end"]["timeZone"]
59
+ end
60
+
61
+ event.updated = Time.parse(json["updated"]) if json['updated']
62
+ event.created = Time.parse(json["created"]) if json['created']
63
+ event
64
+ else
65
+ raise "Not implemented:\n#{json.inspect}"
66
+ end
67
+ end
68
+
69
+ def to_google(yajl_opts = {})
70
+ hash = {
71
+ "kind" => "calendar#event",
72
+ }
73
+ hash["etag"] = etag if etag
74
+ hash["id"] = google_id if google_id
75
+ hash["description"] = description if description
76
+ hash["summary"] = summary if summary
77
+ start = {}
78
+ start["dateTime"] = format_time(start_time) if start_time
79
+ start["date"] = nil if start_time
80
+ start["timeZone"] = start_time_zone if start_time_zone
81
+ finish = {}
82
+ finish["dateTime"] = format_time(end_time) if end_time
83
+ finish["date"] = nil if end_time
84
+ finish["timeZone"] = end_time_zone if end_time_zone
85
+ hash["start"] = start
86
+ hash["end"] = finish
87
+ hash["visibility"] = visibility if visibility
88
+ hash["status"] = status if status
89
+ Yajl::Encoder.encode(hash, yajl_opts)
90
+ end
91
+
92
+ def new?
93
+ self.google_id.nil?
94
+ end
95
+
96
+ def format_time(time)
97
+ time.strftime("%Y-%m-%dT%H:%M:%S%:z")
98
+ end
99
+ end
@@ -0,0 +1,16 @@
1
+ class GoogleR
2
+ class Error < Exception
3
+ attr_reader :status, :response
4
+
5
+ def initialize(status, response)
6
+ @status, @response = status, response
7
+ end
8
+
9
+ def message
10
+ [
11
+ "Response code: #{@status}",
12
+ "Response body: #{@response}",
13
+ ].join("\n")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,88 @@
1
+ require 'ostruct'
2
+
3
+ class GoogleR::Group
4
+ Property = Struct.new(:name, :info)
5
+
6
+ attr_accessor :property, :etag, :google_id, :title, :updated
7
+
8
+ def self.url
9
+ "https://www.google.com"
10
+ end
11
+
12
+ def self.path
13
+ "/m8/feeds/groups/default/full/"
14
+ end
15
+
16
+ def self.api_headers
17
+ {
18
+ 'GData-Version' => '3.0',
19
+ 'Content-Type' => 'application/atom+xml',
20
+ }
21
+ end
22
+
23
+ def path
24
+ if new?
25
+ self.class.path
26
+ else
27
+ self.class.path + google_id.split("/")[-1]
28
+ end
29
+ end
30
+
31
+ def to_google
32
+ builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
33
+ root_attrs = {
34
+ 'xmlns:atom' => 'http://www.w3.org/2005/Atom',
35
+ 'xmlns:gd' => 'http://schemas.google.com/g/2005',
36
+ }
37
+ root_attrs["gd:etag"] = self.etag unless new?
38
+ xml.entry(root_attrs) do
39
+ xml.id_ self.google_id unless new?
40
+ xml.updated self.updated.strftime("%Y-%m-%dT%H:%M:%S.%LZ") unless self.updated.nil?
41
+
42
+ xml['atom'].title({:type => "text"}, self.title) unless self.title.nil?
43
+ if self.property
44
+ xml['gd'].extendedProperty({:name => self.property.name}) do
45
+ xml.info self.property.info unless self.property.info.nil?
46
+ end
47
+ end
48
+ xml.parent.namespace = xml.parent.namespace_definitions.find { |ns| ns.prefix == "atom" }
49
+ end
50
+ end
51
+ builder.to_xml
52
+ end
53
+
54
+ def self.from_xml(doc, *attrs)
55
+ is_collection = doc.search("totalResults").size > 0
56
+ return doc.search("entry").map { |e| from_xml(e) } if is_collection
57
+
58
+ group = self.new
59
+
60
+ google_id = doc.search("id")
61
+ if google_id.empty?
62
+ group.etag = group.google_id = nil
63
+ else
64
+ group.etag = doc["etag"]
65
+ group.google_id = google_id.inner_text
66
+ end
67
+
68
+ title = doc.search("title")
69
+ group.title = title.inner_text unless title.size == 0
70
+
71
+ updated = doc.search("updated")
72
+ group.updated = Time.parse(updated.inner_text) unless updated.empty?
73
+
74
+ extended = doc.search("extendedProperty")
75
+ if extended.size != 0
76
+ info = extended.search("info")
77
+ info = info.size == 0 ? nil : info.inner_text
78
+ property = GoogleR::Group::Property.new(extended[0][:name], info)
79
+ group.property = property
80
+ end
81
+
82
+ group
83
+ end
84
+
85
+ def new?
86
+ self.google_id.nil?
87
+ end
88
+ end