h13ronim-gcal4ruby 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +32 -0
- data/README +85 -0
- data/lib/gcal4ruby/base.rb +260 -0
- data/lib/gcal4ruby/calendar.rb +446 -0
- data/lib/gcal4ruby/event.rb +484 -0
- data/lib/gcal4ruby/recurrence.rb +164 -0
- data/lib/gcal4ruby/service.rb +151 -0
- data/lib/gcal4ruby.rb +1 -0
- data/test/unit.rb +141 -0
- metadata +62 -0
@@ -0,0 +1,446 @@
|
|
1
|
+
require 'gcal4ruby/event'
|
2
|
+
|
3
|
+
module GCal4Ruby
|
4
|
+
#The Calendar Class is the representation of a Google Calendar. Each user account
|
5
|
+
#can have multiple calendars. You must have an authenticated Service object before
|
6
|
+
#using the Calendar object.
|
7
|
+
#=Usage
|
8
|
+
#All usages assume a successfully authenticated Service.
|
9
|
+
#1. Create a new Calendar
|
10
|
+
# cal = Calendar.new(service)
|
11
|
+
#
|
12
|
+
#2. Find an existing Calendar
|
13
|
+
# cal = Calendar.find(service, "New Calendar", :first)
|
14
|
+
#
|
15
|
+
#3. Find all calendars containing the search term
|
16
|
+
# cal = Calendar.find(service, "Soccer Team")
|
17
|
+
#
|
18
|
+
#4. Find a calendar by ID
|
19
|
+
# cal = Calendar.find(service, id, :first)
|
20
|
+
#
|
21
|
+
#After a calendar object has been created or loaded, you can change any of the
|
22
|
+
#attributes like you would any other object. Be sure to save the calendar to write changes
|
23
|
+
#to the Google Calendar service.
|
24
|
+
|
25
|
+
class Calendar
|
26
|
+
CALENDAR_FEED = "http://www.google.com/calendar/feeds/default/owncalendars/full"
|
27
|
+
|
28
|
+
#The calendar title
|
29
|
+
attr_accessor :title
|
30
|
+
|
31
|
+
#A short description of the calendar
|
32
|
+
attr_accessor :summary
|
33
|
+
|
34
|
+
#The parent Service object passed on initialization
|
35
|
+
attr_reader :service
|
36
|
+
|
37
|
+
#The unique calendar id
|
38
|
+
attr_reader :id
|
39
|
+
|
40
|
+
#Boolean value indicating the calendar visibility
|
41
|
+
attr_accessor :hidden
|
42
|
+
|
43
|
+
#The calendar timezone[http://code.google.com/apis/calendar/docs/2.0/reference.html#gCaltimezone]
|
44
|
+
attr_accessor :timezone
|
45
|
+
|
46
|
+
#The calendar color. Must be one of these[http://code.google.com/apis/calendar/docs/2.0/reference.html#gCalcolor] values.
|
47
|
+
attr_accessor :color
|
48
|
+
|
49
|
+
#The calendar geo location, if any
|
50
|
+
attr_accessor :where
|
51
|
+
|
52
|
+
#A boolean value indicating whether the calendar appears by default when viewed online
|
53
|
+
attr_accessor :selected
|
54
|
+
|
55
|
+
#The event feed for the calendar
|
56
|
+
attr_reader :event_feed
|
57
|
+
|
58
|
+
#A flag indicating whether the calendar is editable by this account
|
59
|
+
attr_reader :editable
|
60
|
+
|
61
|
+
#Returns true if the calendar exists on the Google Calendar system (i.e. was
|
62
|
+
#loaded or has been saved). Otherwise returns false.
|
63
|
+
def exists?
|
64
|
+
return @exists
|
65
|
+
end
|
66
|
+
|
67
|
+
#Returns true if the calendar is publically accessable, otherwise returns false.
|
68
|
+
def public?
|
69
|
+
return @public
|
70
|
+
end
|
71
|
+
|
72
|
+
#Returns an array of Event objects corresponding to each event in the calendar.
|
73
|
+
def events
|
74
|
+
events = []
|
75
|
+
ret = @service.send_get(@event_feed)
|
76
|
+
REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
|
77
|
+
entry.attributes["xmlns:gCal"] = "http://schemas.google.com/gCal/2005"
|
78
|
+
entry.attributes["xmlns:gd"] = "http://schemas.google.com/g/2005"
|
79
|
+
entry.attributes["xmlns:app"] = "http://www.w3.org/2007/app"
|
80
|
+
entry.attributes["xmlns"] = "http://www.w3.org/2005/Atom"
|
81
|
+
e = Event.new(self)
|
82
|
+
if e.load(entry.to_s)
|
83
|
+
events << e
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return events
|
87
|
+
end
|
88
|
+
|
89
|
+
#Set the calendar to public (p = true) or private (p = false). Publically viewable
|
90
|
+
#calendars can be accessed by anyone without having to log in to google calendar. See
|
91
|
+
#Calendar#to_iframe for options to display a public calendar in a webpage.
|
92
|
+
def public=(p)
|
93
|
+
if p
|
94
|
+
permissions = 'http://schemas.google.com/gCal/2005#read'
|
95
|
+
else
|
96
|
+
permissions = 'none'
|
97
|
+
end
|
98
|
+
|
99
|
+
#if p != @public
|
100
|
+
path = "http://www.google.com/calendar/feeds/#{@id}/acl/full/default"
|
101
|
+
request = REXML::Document.new(ACL_XML)
|
102
|
+
request.root.elements.each() do |ele|
|
103
|
+
if ele.name == 'role'
|
104
|
+
ele.attributes['value'] = permissions
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
if @service.send_put(path, request.to_s, {"Content-Type" => "application/atom+xml", "Content-Length" => request.length.to_s})
|
109
|
+
@public = p
|
110
|
+
return true
|
111
|
+
else
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
#end
|
115
|
+
end
|
116
|
+
|
117
|
+
#Accepts a Service object. Returns the new Calendar if successful, otherwise raises the InvalidService
|
118
|
+
#error.
|
119
|
+
def initialize(service)
|
120
|
+
super()
|
121
|
+
if !service.is_a?(Service)
|
122
|
+
raise InvalidService
|
123
|
+
end
|
124
|
+
@xml = CALENDAR_XML
|
125
|
+
@service = service
|
126
|
+
@exists = false
|
127
|
+
@title = ""
|
128
|
+
@summary = ""
|
129
|
+
@public = false
|
130
|
+
@id = nil
|
131
|
+
@hidden = false
|
132
|
+
@timezone = "America/Los_Angeles"
|
133
|
+
@color = "#2952A3"
|
134
|
+
@where = ""
|
135
|
+
return true
|
136
|
+
end
|
137
|
+
|
138
|
+
#Deletes a calendar. If successful, returns true, otherwise false. If successful, the
|
139
|
+
#calendar object is cleared.
|
140
|
+
def delete
|
141
|
+
if @exists
|
142
|
+
if @service.send_delete(CALENDAR_FEED+"/"+@id)
|
143
|
+
@exists = false
|
144
|
+
@title = nil
|
145
|
+
@summary = nil
|
146
|
+
@public = false
|
147
|
+
@id = nil
|
148
|
+
@hidden = false
|
149
|
+
@timezone = nil
|
150
|
+
@color = nil
|
151
|
+
@where = nil
|
152
|
+
return true
|
153
|
+
else
|
154
|
+
return false
|
155
|
+
end
|
156
|
+
else
|
157
|
+
return false
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
#If the calendar does not exist, creates it, otherwise updates the calendar info. Returns
|
162
|
+
#true if the save is successful, otherwise false.
|
163
|
+
def save
|
164
|
+
if @exists
|
165
|
+
ret = service.send_put(@edit_feed, to_xml(), {'Content-Type' => 'application/atom+xml'})
|
166
|
+
else
|
167
|
+
ret = service.send_post(CALENDAR_FEED, to_xml(), {'Content-Type' => 'application/atom+xml'})
|
168
|
+
end
|
169
|
+
if !@exists
|
170
|
+
if load(ret.read_body)
|
171
|
+
return true
|
172
|
+
else
|
173
|
+
raise CalendarSaveFailed
|
174
|
+
end
|
175
|
+
end
|
176
|
+
return true
|
177
|
+
end
|
178
|
+
|
179
|
+
#Class method for querying the google service for specific calendars. The service parameter
|
180
|
+
#should be an appropriately authenticated Service. The term parameter can be any string. The
|
181
|
+
#scope parameter may be either :all to return an array of matches, or :first to return
|
182
|
+
#the first match as a Calendar object.
|
183
|
+
def self.find(service, query_term=nil, params = {})
|
184
|
+
t = query_term.downcase
|
185
|
+
cals = service.calendars
|
186
|
+
ret = []
|
187
|
+
cals.each do |cal|
|
188
|
+
title = cal.title || ""
|
189
|
+
summary = cal.summary || ""
|
190
|
+
id = cal.id || ""
|
191
|
+
if id == query_term
|
192
|
+
return cal
|
193
|
+
end
|
194
|
+
if title.downcase.match(t) or summary.downcase.match(t)
|
195
|
+
if params[:scope] == :first
|
196
|
+
return cal
|
197
|
+
else
|
198
|
+
ret << cal
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
ret
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.get(service, id)
|
206
|
+
url = 'http://www.google.com/calendar/feeds/default/allcalendars/full/'+id
|
207
|
+
ret = service.send_get(url)
|
208
|
+
puts "==return=="
|
209
|
+
puts ret.body
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.query(service, query_term)
|
213
|
+
url = 'http://www.google.com/calendar/feeds/default/allcalendars/full'+"?q="+CGI.escape(query_term)
|
214
|
+
ret = service.send_get(url)
|
215
|
+
puts "==return=="
|
216
|
+
puts ret.body
|
217
|
+
end
|
218
|
+
|
219
|
+
#Reloads the calendar objects information from the stored server version. Returns true
|
220
|
+
#if successful, otherwise returns false. Any information not saved will be overwritten.
|
221
|
+
def reload
|
222
|
+
if not @exists
|
223
|
+
return false
|
224
|
+
end
|
225
|
+
t = Calendar.find(service, @id, :first)
|
226
|
+
if t
|
227
|
+
load(t.to_xml)
|
228
|
+
else
|
229
|
+
return false
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
#Returns the xml representation of the Calenar.
|
234
|
+
def to_xml
|
235
|
+
xml = REXML::Document.new(@xml)
|
236
|
+
xml.root.elements.each(){}.map do |ele|
|
237
|
+
case ele.name
|
238
|
+
when "title"
|
239
|
+
ele.text = @title
|
240
|
+
when "summary"
|
241
|
+
ele.text = @summary
|
242
|
+
when "timezone"
|
243
|
+
ele.attributes["value"] = @timezone
|
244
|
+
when "hidden"
|
245
|
+
ele.attributes["value"] = @hidden.to_s
|
246
|
+
when "color"
|
247
|
+
ele.attributes["value"] = @color
|
248
|
+
when "selected"
|
249
|
+
ele.attributes["value"] = @selected.to_s
|
250
|
+
end
|
251
|
+
end
|
252
|
+
xml.to_s
|
253
|
+
end
|
254
|
+
|
255
|
+
#Loads the Calendar with returned data from Google Calendar feed. Returns true if successful.
|
256
|
+
def load(string)
|
257
|
+
@exists = true
|
258
|
+
@xml = string
|
259
|
+
xml = REXML::Document.new(string)
|
260
|
+
xml.root.elements.each(){}.map do |ele|
|
261
|
+
case ele.name
|
262
|
+
when "id"
|
263
|
+
@id = ele.text.gsub("http://www.google.com/calendar/feeds/default/calendars/", "")
|
264
|
+
when 'title'
|
265
|
+
@title = ele.text
|
266
|
+
when 'summary'
|
267
|
+
@summary = ele.text
|
268
|
+
when "color"
|
269
|
+
@color = ele.attributes['value']
|
270
|
+
when 'hidden'
|
271
|
+
@hidden = ele.attributes["value"] == "true" ? true : false
|
272
|
+
when 'timezone'
|
273
|
+
@timezone = ele.attributes["value"]
|
274
|
+
when "selected"
|
275
|
+
@selected = ele.attributes["value"] == "true" ? true : false
|
276
|
+
when "link"
|
277
|
+
if ele.attributes['rel'] == 'edit'
|
278
|
+
@edit_feed = ele.attributes['href']
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
@event_feed = "http://www.google.com/calendar/feeds/#{@id}/private/full"
|
284
|
+
|
285
|
+
if @service.check_public
|
286
|
+
puts "Getting ACL Feed" if @service.debug
|
287
|
+
|
288
|
+
#rescue error on shared calenar ACL list access
|
289
|
+
begin
|
290
|
+
ret = @service.send_get("http://www.google.com/calendar/feeds/#{@id}/acl/full/")
|
291
|
+
rescue Exception => e
|
292
|
+
@public = false
|
293
|
+
@editable = false
|
294
|
+
return true
|
295
|
+
end
|
296
|
+
@editable = true
|
297
|
+
r = REXML::Document.new(ret.read_body)
|
298
|
+
r.root.elements.each("entry") do |ele|
|
299
|
+
ele.elements.each do |e|
|
300
|
+
#puts "e = "+e.to_s if @service.debug
|
301
|
+
#puts "previous element = "+e.previous_element.to_s if @service.debug
|
302
|
+
if e.name == 'role' and e.previous_element.name == 'scope' and e.previous_element.attributes['type'] == 'default'
|
303
|
+
if e.attributes['value'].match('#read')
|
304
|
+
@public = true
|
305
|
+
else
|
306
|
+
@public = false
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
else
|
312
|
+
@public = false
|
313
|
+
@editable = true
|
314
|
+
end
|
315
|
+
return true
|
316
|
+
end
|
317
|
+
|
318
|
+
#Helper function to return the currently loaded calendar formatted iframe embedded google calendar.
|
319
|
+
#1. *params*: a hash of parameters that affect the display of the embedded calendar:
|
320
|
+
# height:: the height of the embedded calendar in pixels
|
321
|
+
# width:: the width of the embedded calendar in pixels
|
322
|
+
# title:: the title to display
|
323
|
+
# bgcolor:: the background color. Limited choices, see google docs for allowable values.
|
324
|
+
# color:: the color of the calendar elements. Limited choices, see google docs for allowable values.
|
325
|
+
# showTitle:: set to 'false' to hide the title
|
326
|
+
# showDate:: set to 'false' to hide the current date
|
327
|
+
# showNav:: set to 'false to hide the navigation tools
|
328
|
+
# showPrint:: set to 'false' to hide the print icon
|
329
|
+
# showTabs:: set to 'false' to hide the tabs
|
330
|
+
# showCalendars:: set to 'false' to hide the calendars selection drop down
|
331
|
+
# showTimezone:: set to 'false' to hide the timezone selection
|
332
|
+
# border:: the border width in pixels
|
333
|
+
# dates:: a range of dates to display in the format of 'yyyymmdd/yyyymmdd'. Example: 20090820/20091001
|
334
|
+
# privateKey:: use to display a private calendar. You can find this key under the calendar settings pane of the Google Calendar website.
|
335
|
+
def to_iframe(params = {})
|
336
|
+
if not self.id
|
337
|
+
raise "The calendar must exist and be saved before you can use this method."
|
338
|
+
end
|
339
|
+
params[:id] = self.id
|
340
|
+
params[:height] ||= "600"
|
341
|
+
params[:width] ||= "600"
|
342
|
+
params[:bgcolor] ||= "#FFFFFF"
|
343
|
+
params[:color] ||= "#2952A3"
|
344
|
+
params[:showTitle] = params[:showTitle] == false ? "showTitle=0" : ''
|
345
|
+
params[:showNav] = params[:showNav] == false ? "showNav=0" : ''
|
346
|
+
params[:showDate] = params[:showDate] == false ? "showDate=0" : ''
|
347
|
+
params[:showPrint] = params[:showPrint] == false ? "showPrint=0" : ''
|
348
|
+
params[:showTabs] = params[:showTabs] == false ? "showTabs=0" : ''
|
349
|
+
params[:showCalendars] = params[:showCalendars] == false ? "showCalendars=0" : ''
|
350
|
+
params[:showTimezone] = params[:showTimezone] == false ? 'showTz=0' : ''
|
351
|
+
params[:border] ||= "0"
|
352
|
+
output = ''
|
353
|
+
params.each do |key, value|
|
354
|
+
case key
|
355
|
+
when :height then output += "height=#{value}"
|
356
|
+
when :width then output += "width=#{value}"
|
357
|
+
when :title then output += "title=#{CGI.escape(value)}"
|
358
|
+
when :bgcolor then output += "bgcolor=#{CGI.escape(value)}"
|
359
|
+
when :showTitle then output += value
|
360
|
+
when :showDate then output += value
|
361
|
+
when :showNav then output += value
|
362
|
+
when :showPrint then output += value
|
363
|
+
when :showTabs then output += value
|
364
|
+
when :showCalendars then output += value
|
365
|
+
when :showTimezone then output += value
|
366
|
+
when :viewMode then output += "mode=#{value}"
|
367
|
+
when :dates then output += "dates=#{CGI.escape(value)}"
|
368
|
+
when :privateKey then output += "pvttk=#{value}"
|
369
|
+
end
|
370
|
+
output += "&"
|
371
|
+
end
|
372
|
+
|
373
|
+
output += "src=#{params[:id]}&color=#{CGI.escape(params[:color])}"
|
374
|
+
|
375
|
+
"<iframe src='http://www.google.com/calendar/embed?#{output}' style='#{params[:border]} px solid;' width='#{params[:width]}' height='#{params[:height]}' frameborder='#{params[:border]}' scrolling='no'></iframe>"
|
376
|
+
end
|
377
|
+
|
378
|
+
#Helper function to return a specified calendar id as a formatted iframe embedded google calendar. This function does not require loading the calendar information from the Google calendar
|
379
|
+
#service, but does require you know the google calendar id.
|
380
|
+
#1. *id*: the unique google assigned id for the calendar to display.
|
381
|
+
#2. *params*: a hash of parameters that affect the display of the embedded calendar:
|
382
|
+
# height:: the height of the embedded calendar in pixels
|
383
|
+
# width:: the width of the embedded calendar in pixels
|
384
|
+
# title:: the title to display
|
385
|
+
# bgcolor:: the background color. Limited choices, see google docs for allowable values.
|
386
|
+
# color:: the color of the calendar elements. Limited choices, see google docs for allowable values.
|
387
|
+
# showTitle:: set to 'false' to hide the title
|
388
|
+
# showDate:: set to 'false' to hide the current date
|
389
|
+
# showNav:: set to 'false to hide the navigation tools
|
390
|
+
# showPrint:: set to 'false' to hide the print icon
|
391
|
+
# showTabs:: set to 'false' to hide the tabs
|
392
|
+
# showCalendars:: set to 'false' to hide the calendars selection drop down
|
393
|
+
# showTimezone:: set to 'false' to hide the timezone selection
|
394
|
+
# border:: the border width in pixels
|
395
|
+
# dates:: a range of dates to display in the format of 'yyyymmdd/yyyymmdd'. Example: 20090820/20091001
|
396
|
+
# privateKey:: use to display a private calendar. You can find this key under the calendar settings pane of the Google Calendar website.
|
397
|
+
def self.to_iframe(id, params = {})
|
398
|
+
params[:id] = id
|
399
|
+
params[:height] ||= "600"
|
400
|
+
params[:width] ||= "600"
|
401
|
+
params[:bgcolor] ||= "#FFFFFF"
|
402
|
+
params[:color] ||= "#2952A3"
|
403
|
+
params[:showTitle] = params[:showTitle] == false ? "showTitle=0" : ''
|
404
|
+
params[:showNav] = params[:showNav] == false ? "showNav=0" : ''
|
405
|
+
params[:showDate] = params[:showDate] == false ? "showDate=0" : ''
|
406
|
+
params[:showPrint] = params[:showPrint] == false ? "showPrint=0" : ''
|
407
|
+
params[:showTabs] = params[:showTabs] == false ? "showTabs=0" : ''
|
408
|
+
params[:showCalendars] = params[:showCalendars] == false ? "showCalendars=0" : ''
|
409
|
+
params[:showTimezone] = params[:showTimezone] == false ? 'showTz=0' : ''
|
410
|
+
params[:border] ||= "0"
|
411
|
+
output = ''
|
412
|
+
params.each do |key, value|
|
413
|
+
case key
|
414
|
+
when :height then output += "height=#{value}"
|
415
|
+
when :width then output += "width=#{value}"
|
416
|
+
when :title then output += "title=#{CGI.escape(value)}"
|
417
|
+
when :bgcolor then output += "bgcolor=#{CGI.escape(value)}"
|
418
|
+
when :showTitle then output += value
|
419
|
+
when :showDate then output += value
|
420
|
+
when :showNav then output += value
|
421
|
+
when :showPrint then output += value
|
422
|
+
when :showTabs then output += value
|
423
|
+
when :showCalendars then output += value
|
424
|
+
when :showTimezone then output += value
|
425
|
+
when :viewMode then output += "mode=#{value}"
|
426
|
+
when :dates then output += "dates=#{CGI.escape(value)}"
|
427
|
+
when :privateKey then output += "pvttk=#{value}"
|
428
|
+
end
|
429
|
+
output += "&"
|
430
|
+
end
|
431
|
+
|
432
|
+
output += "src=#{params[:id]}&color=#{CGI.escape(params[:color])}"
|
433
|
+
|
434
|
+
"<iframe src='http://www.google.com/calendar/embed?#{output}' style='#{params[:border]} px solid;' width='#{params[:width]}' height='#{params[:height]}' frameborder='#{params[:border]}' scrolling='no'></iframe>"
|
435
|
+
end
|
436
|
+
|
437
|
+
private
|
438
|
+
@xml
|
439
|
+
@exists = false
|
440
|
+
@public = false
|
441
|
+
@event_feed = ''
|
442
|
+
@edit_feed = ''
|
443
|
+
|
444
|
+
end
|
445
|
+
|
446
|
+
end
|