clio-gcal4ruby 0.3.2

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.
@@ -0,0 +1,320 @@
1
+ require 'gcal4ruby/event'
2
+
3
+ module GCal4Ruby
4
+ class Calendar
5
+ GOOGLE_PARAM_NAMES = {
6
+ :mode => "mode",
7
+ :height => "height",
8
+ :width => "width",
9
+ :bg_color => "bgcolor",
10
+ :color => "color",
11
+ :show_title => "showTitle",
12
+ :show_nav => "showNav",
13
+ :show_date => "showDate",
14
+ :show_print => "showPrint",
15
+ :show_tabs => "showTabs",
16
+ :show_calendars => "showCalendars",
17
+ :show_timezone => "showTimezone"
18
+ }
19
+
20
+ IFRAME_DEFAULTS = {
21
+ :mode => "WEEK",
22
+ :height => "600",
23
+ :width => "600",
24
+ :bg_color => "#FFFFFF",
25
+ :color => "#2852A3",
26
+ :show_title => false,
27
+ :show_nav => true,
28
+ :show_date => true,
29
+ :show_print => true,
30
+ :show_tabs => true,
31
+ :show_calendars => true,
32
+ :show_timezone => true
33
+ }
34
+
35
+ CALENDAR_FEED = "http://www.google.com/calendar/feeds/default/owncalendars/full"
36
+
37
+ attr_accessor :title, :summary, :hidden, :timezone, :color, :where, :selected
38
+ attr_reader :service, :id, :event_feed, :editable, :edit_feed
39
+
40
+ def initialize(service, attributes = {})
41
+ super()
42
+ @service = service
43
+ attributes.each do |key, value|
44
+ self.send("#{key}=", value)
45
+ end
46
+
47
+ # @xml ||= CALENDAR_XML
48
+ # @exists = false
49
+ # @title ||= ""
50
+ # @summary ||= ""
51
+ # @public ||= false
52
+ # @hidden ||= false
53
+ # @timezone ||= "America/Los_Angeles"
54
+ # @color ||= "#2952A3"
55
+ # @where ||= ""
56
+ # return true
57
+ end
58
+
59
+ def exists?
60
+ @exists
61
+ end
62
+
63
+ def public?
64
+ @public
65
+ end
66
+
67
+ #Returns an array of Event objects corresponding to each event in the calendar.
68
+ def events(query_hash = nil)
69
+ url = @event_feed
70
+ if query_hash
71
+ url += "?#{query_hash.to_query}"
72
+ end
73
+ events = []
74
+ ret = @service.send_get(url)
75
+ REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
76
+ entry.attributes["xmlns:gCal"] = "http://schemas.google.com/gCal/2005"
77
+ entry.attributes["xmlns:gd"] = "http://schemas.google.com/g/2005"
78
+ entry.attributes["xmlns:app"] = "http://www.w3.org/2007/app"
79
+ entry.attributes["xmlns"] = "http://www.w3.org/2005/Atom"
80
+ entry.attributes["xmlns:georss"] = "http://www.georss.org/georss"
81
+ entry.attributes["xmlns:gml"] = "http://www.opengis.net/gml"
82
+ e = Event.new(self)
83
+ if e.load(entry.to_s)
84
+ events << e
85
+ end
86
+ end
87
+ return events
88
+ end
89
+
90
+ def events_since(time)
91
+ events({ 'updated-min' => time.xmlschema })
92
+ end
93
+
94
+ def public=(param)
95
+ permissions = param ? 'http://schemas.google.com/gCal/2005#read' : 'none'
96
+
97
+ path = "http://www.google.com/calendar/feeds/#{@id}/acl/full/default"
98
+ request = REXML::Document.new(ACL_XML) # What/Where is ACL_XML???
99
+ request.root.elements.each() do |ele|
100
+ if ele.name == 'role'
101
+ ele.attributes['value'] = permissions
102
+ end
103
+ end
104
+ @public = @service.send_put(path, request.to_s, {"Content-Type" => "application/atom+xml", "Content-Length" => request.length.to_s})
105
+ end
106
+
107
+ #Deletes a calendar. If successful, returns true, otherwise false. If successful, the
108
+ #calendar object is cleared.
109
+ def delete
110
+ if @exists
111
+ if @service.send_delete(CALENDAR_FEED+"/"+@id)
112
+ @exists = false
113
+ @title = nil
114
+ @summary = nil
115
+ @public = false
116
+ @id = nil
117
+ @hidden = false
118
+ @timezone = nil
119
+ @color = nil
120
+ @where = nil
121
+ return true
122
+ else
123
+ return false
124
+ end
125
+ else
126
+ return false
127
+ end
128
+ end
129
+
130
+ #If the calendar does not exist, creates it, otherwise updates the calendar info. Returns
131
+ #true if the save is successful, otherwise false.
132
+ def save
133
+ if @exists
134
+ ret = service.send_put(@edit_feed, to_xml(), {'Content-Type' => 'application/atom+xml'})
135
+ else
136
+ ret = service.send_post(CALENDAR_FEED, to_xml(), {'Content-Type' => 'application/atom+xml'})
137
+ end
138
+ if !@exists
139
+ if load(ret.read_body)
140
+ return true
141
+ else
142
+ raise CalendarSaveFailed
143
+ end
144
+ end
145
+ return true
146
+ end
147
+
148
+ #Class method for querying the google service for specific calendars. The service parameter
149
+ #should be an appropriately authenticated Service. The term parameter can be any string. The
150
+ #scope parameter may be either :all to return an array of matches, or :first to return
151
+ #the first match as a Calendar object.
152
+ def self.find(service, query_term=nil, params = {})
153
+ t = query_term.downcase if query_term
154
+ cals = service.calendars
155
+ ret = []
156
+ cals.each do |cal|
157
+ title = cal.title || ""
158
+ summary = cal.summary || ""
159
+ id = cal.id || ""
160
+ if id == query_term
161
+ return cal
162
+ end
163
+ if title.downcase.match(t) or summary.downcase.match(t)
164
+ if params[:scope] == :first
165
+ return cal
166
+ else
167
+ ret << cal
168
+ end
169
+ end
170
+ end
171
+ ret
172
+ end
173
+
174
+ def self.get(service, id)
175
+ url = 'http://www.google.com/calendar/feeds/default/allcalendars/full/'+id
176
+ ret = service.send_get(url)
177
+ puts "==return=="
178
+ puts ret.body
179
+ end
180
+
181
+ def self.query(service, query_term)
182
+ url = 'http://www.google.com/calendar/feeds/default/allcalendars/full'+"?q="+CGI.escape(query_term)
183
+ ret = service.send_get(url)
184
+ puts "==return=="
185
+ puts ret.body
186
+ end
187
+
188
+ #Reloads the calendar objects information from the stored server version. Returns true
189
+ #if successful, otherwise returns false. Any information not saved will be overwritten.
190
+ def reload
191
+ if not @exists
192
+ return false
193
+ end
194
+ t = Calendar.find(service, @id, :first)
195
+ if t
196
+ load(t.to_xml)
197
+ else
198
+ return false
199
+ end
200
+ end
201
+
202
+ #Returns the xml representation of the Calenar.
203
+ def to_xml
204
+ xml = REXML::Document.new(@xml)
205
+ xml.root.elements.each(){}.map do |ele|
206
+ case ele.name
207
+ when "title"
208
+ ele.text = @title
209
+ when "summary"
210
+ ele.text = @summary
211
+ when "timezone"
212
+ ele.attributes["value"] = @timezone
213
+ when "hidden"
214
+ ele.attributes["value"] = @hidden.to_s
215
+ when "color"
216
+ ele.attributes["value"] = @color
217
+ when "selected"
218
+ ele.attributes["value"] = @selected.to_s
219
+ end
220
+ end
221
+ xml.to_s
222
+ end
223
+
224
+ #Loads the Calendar with returned data from Google Calendar feed. Returns true if successful.
225
+ def load(string)
226
+ @exists = true
227
+ @xml = string
228
+ xml = REXML::Document.new(string)
229
+ xml.root.elements.each(){}.map do |ele|
230
+ case ele.name
231
+ when "id"
232
+ @id = ele.text.gsub("http://www.google.com/calendar/feeds/default/calendars/", "")
233
+ when 'title'
234
+ @title = ele.text
235
+ when 'summary'
236
+ @summary = ele.text
237
+ when "color"
238
+ @color = ele.attributes['value']
239
+ when 'hidden'
240
+ @hidden = ele.attributes["value"] == "true" ? true : false
241
+ when 'timezone'
242
+ @timezone = ele.attributes["value"]
243
+ when "selected"
244
+ @selected = ele.attributes["value"] == "true" ? true : false
245
+ when "link"
246
+ href = ele.attributes['href']
247
+ case ele.attributes['rel']
248
+ when "edit" then @edit_feed = href
249
+ when "http://schemas.google.com/gCal/2005#eventFeed" then @event_feed = href
250
+ when "http://schemas.google.com/acl/2007#accessControlList" then @acl_feed = href
251
+ end
252
+ end
253
+ end
254
+
255
+ if @service.check_public
256
+ puts "Getting ACL Feed" if @service.debug
257
+
258
+ #rescue error on shared calenar ACL list access
259
+ begin
260
+ ret = @service.send_get(@acl_feed)
261
+ rescue Exception => e
262
+ @public = false
263
+ @editable = false
264
+ return true
265
+ end
266
+ @editable = true
267
+ r = REXML::Document.new(ret.read_body)
268
+ r.root.elements.each("entry") do |ele|
269
+ ele.elements.each do |e|
270
+ #puts "e = "+e.to_s if @service.debug
271
+ #puts "previous element = "+e.previous_element.to_s if @service.debug
272
+ #added per eruder http://github.com/h13ronim/gcal4ruby/commit/3074ebde33bd3970500f6de992a66c0a4578062a
273
+ if e.name == 'role' and e.previous_element and e.previous_element.name == 'scope' and e.previous_element.attributes['type'] == 'default'
274
+ if e.attributes['value'].match('#read')
275
+ @public = true
276
+ else
277
+ @public = false
278
+ end
279
+ end
280
+ end
281
+ end
282
+ else
283
+ @public = false
284
+ @editable = true
285
+ end
286
+ return true
287
+ end
288
+
289
+ def to_iframe(params = {})
290
+ raise "The calendar must exist and be saved before you can use this method." unless self.id
291
+ GCal4Ruby::Calendar.to_iframe(self.id, params)
292
+ end
293
+
294
+ def self.to_iframe(id, params = {})
295
+ raise "Calendar ID is required" unless id
296
+ options = build_options_set(params)
297
+ url_options = options.join("&amp;")
298
+ "<iframe src='http://www.google.com/calendar/embed?src=#{id}&amp;#{output}' width='#{options[:width]}' height='#{options[:height]}' frameborder='0' scrolling='no'></iframe>"
299
+ end
300
+
301
+ def build_options_set(params)
302
+ IFRAME_DEFAULTS.merge(params).collect do |key, value|
303
+ if IFRAME_DEFAULTS.keys.include?(key)
304
+ [GOOGLE_PARAM_NAMES[key], raw_value_to_param_value(value)].join("=")
305
+ end
306
+ end
307
+ end
308
+
309
+ private
310
+
311
+ def raw_value_to_param_value(value)
312
+ case value
313
+ when true then "1"
314
+ when false then "0"
315
+ else value
316
+ end
317
+ end
318
+
319
+ end
320
+ end
@@ -0,0 +1,501 @@
1
+ require 'gcal4ruby/recurrence'
2
+
3
+ module GCal4Ruby
4
+ #The Event Class represents a remote event in calendar.
5
+ #
6
+ #=Usage
7
+ #All usages assume a successfully authenticated Service and valid Calendar.
8
+ #1. Create a new Event
9
+ # event = Event.new(calendar)
10
+ # event.title = "Soccer Game"
11
+ # event.start = Time.parse("12-06-2009 at 12:30 PM")
12
+ # event.end = Time.parse("12-06-2009 at 1:30 PM")
13
+ # event.where = "Merry Playfields"
14
+ # event.save
15
+ #
16
+ #2. Find an existing Event
17
+ # event = Event.find(cal, "Soccer Game", {:scope => :first})
18
+ #
19
+ #3. Find all events containing the search term
20
+ # event = Event.find(cal, "Soccer Game")
21
+ #
22
+ #4. Create a recurring event for every saturday
23
+ # event = Event.new(calendar)
24
+ # event.title = "Baseball Game"
25
+ # event.where = "Municipal Stadium"
26
+ # event.recurrence = Recurrence.new
27
+ # event.recurrence.start = Time.parse("13-06-2009 at 4:30 PM")
28
+ # event.recurrence.end = Time.parse("13-06-2009 at 6:30 PM")
29
+ # event.recurrence.frequency = {"weekly" => ["SA"]}
30
+ # event.save
31
+ #
32
+ #5. Create an event with a 15 minute email reminder
33
+ # event = Event.new(calendar)
34
+ # event.title = "Dinner with Kate"
35
+ # event.start = Time.parse("20-06-2009 at 5 pm")
36
+ # event.end = Time.parse("20-06-209 at 8 pm")
37
+ # event.where = "Luigi's"
38
+ # event.reminder = {:minutes => 15, :method => 'email'}
39
+ # event.save
40
+ #
41
+ #6. Create an event with attendees
42
+ # event = Event.new(calendar)
43
+ # event.title = "Dinner with Kate"
44
+ # event.start = Time.parse("20-06-2009 at 5 pm")
45
+ # event.end = Time.parse("20-06-209 at 8 pm")
46
+ # event.attendees => {:name => "Kate", :email => "kate@gmail.com"}
47
+ # event.save
48
+ #
49
+ #After an event object has been created or loaded, you can change any of the
50
+ #attributes like you would any other object. Be sure to save the event to write changes
51
+ #to the Google Calendar service.
52
+ class Event
53
+ #The event title
54
+ attr_accessor :title
55
+ #The content for the event
56
+ attr_accessor :content
57
+ #The location of the event
58
+ attr_accessor :where
59
+ #A flag for whether the event show as :free or :busy
60
+ attr_accessor :transparency
61
+ #A flag indicating the status of the event. Values can be :confirmed, :tentative or :cancelled
62
+ attr_accessor :status
63
+ #The unique event ID
64
+ attr_accessor :id
65
+ #Flag indicating whether it is an all day event
66
+ attr_accessor :all_day
67
+
68
+ @attendees
69
+
70
+ #The event start time
71
+ attr_reader :start
72
+ #The event end time
73
+ attr_reader :end
74
+ #The reminder settings for the event, returned as a hash
75
+ attr_reader :reminder
76
+ #The date the event was created
77
+ attr_reader :published
78
+ #The date the event was last updated
79
+ attr_reader :updated
80
+ #The date the event was last edited
81
+ attr_reader :edited
82
+
83
+ #Sets the reminder options for the event. Parameter must be a hash containing one of
84
+ #:hours, :minutes and :days, which are simply the number of each before the event start date you'd like to
85
+ #receive the reminder.
86
+ #
87
+ #:method can be one of the following:
88
+ #- <b>'alert'</b>: causes an alert to appear when a user is viewing the calendar in a browser
89
+ #- <b>'email'</b>: sends the user an email message
90
+ def reminder=(r)
91
+ @reminder = r
92
+ end
93
+
94
+ #Returns the current event's Recurrence information
95
+ def recurrence
96
+ @recurrence
97
+ end
98
+
99
+ #Returns an array of the current attendees
100
+ def attendees
101
+ @attendees
102
+ end
103
+
104
+ #Accepts an array of email address/name pairs for attendees.
105
+ # [{:name => 'Mike Reich', :email => 'mike@seabourneconsulting.com'}]
106
+ #The email address is requried, but the name is optional
107
+ def attendees=(a)
108
+ if a.is_a?(Array)
109
+ @attendees = a
110
+ else
111
+ raise "Attendees must be an Array of email/name hash pairs"
112
+ end
113
+ end
114
+
115
+ #Sets the event's recurrence information to a Recurrence object. Returns the recurrence if successful,
116
+ #false otherwise
117
+ def recurrence=(r)
118
+ if r.is_a?(Recurrence) or r.nil?
119
+ r.event = self unless r.nil?
120
+ @recurrence = r
121
+ else
122
+ return false
123
+ end
124
+ end
125
+
126
+ #Returns a duplicate of the current event as a new Event object
127
+ def copy()
128
+ e = Event.new()
129
+ e.load(to_xml)
130
+ e.calendar = @calendar
131
+ return e
132
+ end
133
+
134
+ #Sets the start time of the Event. Must be a Time object or a parsable string representation
135
+ #of a time.
136
+ def start=(str)
137
+ if str.is_a?String
138
+ @start = Time.parse(str)
139
+ elsif str.is_a?Time
140
+ @start = str
141
+ else
142
+ raise "Start Time must be either Time or String"
143
+ end
144
+ end
145
+
146
+ #Sets the end time of the Event. Must be a Time object or a parsable string representation
147
+ #of a time.
148
+ def end=(str)
149
+ if str.is_a?String
150
+ @end = Time.parse(str)
151
+ elsif str.is_a?Time
152
+ @end = str
153
+ else
154
+ raise "End Time must be either Time or String"
155
+ end
156
+ end
157
+
158
+ #Deletes the event from the Google Calendar Service. All values are cleared.
159
+ def delete
160
+ if @exists
161
+ if @calendar.service.send_delete(@edit_feed, {"If-Match" => @etag})
162
+ @exists = false
163
+ @deleted = true
164
+ @title = nil
165
+ @content = nil
166
+ @id = nil
167
+ @start = nil
168
+ @end = nil
169
+ @transparency = nil
170
+ @status = nil
171
+ @where = nil
172
+ return true
173
+ else
174
+ return false
175
+ end
176
+ else
177
+ return false
178
+ end
179
+ end
180
+
181
+ #Creates a new Event. Accepts a valid Calendar object and optional attributes hash.
182
+ def initialize(calendar, attributes = {})
183
+ if not calendar.editable
184
+ raise CalendarNotEditable
185
+ end
186
+ super()
187
+ attributes.each do |key, value|
188
+ self.send("#{key}=", value)
189
+ end
190
+ @xml ||= EVENT_XML
191
+ @calendar ||= calendar
192
+ @transparency ||= "http://schemas.google.com/g/2005#event.opaque"
193
+ @status ||= "http://schemas.google.com/g/2005#event.confirmed"
194
+ @attendees ||= []
195
+ @all_day ||= false
196
+ end
197
+
198
+ #If the event does not exist on the Google Calendar service, save creates it. Otherwise
199
+ #updates the existing event data. Returns true on success, false otherwise.
200
+ def save
201
+ if @deleted
202
+ return false
203
+ end
204
+ if @exists
205
+ ret = @calendar.service.send_put(@edit_feed, to_xml, {'Content-Type' => 'application/atom+xml', "If-Match" => @etag})
206
+ else
207
+ ret = @calendar.service.send_post(@calendar.event_feed, to_xml, {'Content-Type' => 'application/atom+xml'})
208
+ end
209
+ if !@exists
210
+ if load(ret.read_body)
211
+ return true
212
+ else
213
+ raise EventSaveFailed
214
+ end
215
+ end
216
+ reload
217
+ return true
218
+ end
219
+
220
+ #Returns an XML representation of the event.
221
+ def to_xml()
222
+ xml = REXML::Document.new(@xml)
223
+ xml.root.elements.each(){}.map do |ele|
224
+ case ele.name
225
+ when 'id'
226
+ ele.text = @id
227
+ when "title"
228
+ ele.text = @title
229
+ when "content"
230
+ ele.text = @content
231
+ when "when"
232
+ if not @recurrence
233
+ ele.attributes["startTime"] = @all_day ? @start.strftime("%Y-%m-%d") : @start.xmlschema
234
+ ele.attributes["endTime"] = @all_day ? @end.strftime("%Y-%m-%d") : @end.xmlschema
235
+ set_reminder(ele)
236
+ else
237
+ if not @reminder
238
+ xml.root.delete_element("/entry/gd:when")
239
+ xml.root.add_element("gd:recurrence").text = @recurrence.to_s
240
+ else
241
+ ele.delete_attribute('startTime')
242
+ ele.delete_attribute('endTime')
243
+ set_reminder(ele)
244
+ end
245
+ end
246
+ when "eventStatus"
247
+ ele.attributes["value"] = case @status
248
+ when :confirmed
249
+ "http://schemas.google.com/g/2005#event.confirmed"
250
+ when :tentative
251
+ "http://schemas.google.com/g/2005#event.tentative"
252
+ when :cancelled
253
+ "http://schemas.google.com/g/2005#event.canceled"
254
+ else
255
+ "http://schemas.google.com/g/2005#event.confirmed"
256
+ end
257
+ when "transparency"
258
+ ele.attributes["value"] = case @transparency
259
+ when :free
260
+ "http://schemas.google.com/g/2005#event.transparent"
261
+ when :busy
262
+ "http://schemas.google.com/g/2005#event.opaque"
263
+ else
264
+ "http://schemas.google.com/g/2005#event.opaque"
265
+ end
266
+ when "where"
267
+ ele.attributes["valueString"] = @where
268
+ when "recurrence"
269
+ puts 'recurrence element found' if @calendar.service.debug
270
+ if @recurrence
271
+ puts 'setting recurrence' if @calendar.service.debug
272
+ ele.text = @recurrence.to_s
273
+ else
274
+ puts 'no recurrence, adding when' if @calendar.service.debug
275
+ w = xml.root.add_element("gd:when")
276
+ xml.root.delete_element("/entry/gd:recurrence")
277
+ w.attributes["startTime"] = @all_day ? @start.strftime("%Y-%m-%d") : @start.xmlschema
278
+ w.attributes["endTime"] = @all_day ? @end.strftime("%Y-%m-%d") : @end.xmlschema
279
+ set_reminder(w)
280
+ end
281
+ end
282
+ end
283
+ if not @attendees.empty?
284
+ @attendees.each do |a|
285
+ xml.root.add_element("gd:who", {"email" => a[:email], "valueString" => a[:name], "rel" => "http://schemas.google.com/g/2005#event.attendee"})
286
+ end
287
+ end
288
+ xml.to_s
289
+ end
290
+
291
+ #Loads the event info from an XML string.
292
+ def load(string)
293
+ @xml = string
294
+ @exists = true
295
+ xml = REXML::Document.new(string)
296
+ @etag = xml.root.attributes['etag']
297
+ xml.root.elements.each(){}.map do |ele|
298
+ case ele.name
299
+ when 'updated'
300
+ @updated = ele.text
301
+ when 'published'
302
+ @published = ele.text
303
+ when 'edited'
304
+ @edited = ele.text
305
+ when 'id'
306
+ @id, @edit_feed = ele.text
307
+ when 'title'
308
+ @title = ele.text
309
+ when 'content'
310
+ @content = ele.text
311
+ when "when"
312
+ @start = Time.parse(ele.attributes['startTime'])
313
+ @end = Time.parse(ele.attributes['endTime'])
314
+ ele.elements.each("gd:reminder") do |r|
315
+ @reminder = {:minutes => r.attributes['minutes'] ? r.attributes['minutes'] : 0, :hours => r.attributes['hours'] ? r.attributes['hours'] : 0, :days => r.attributes['days'] ? r.attributes['days'] : 0, :method => r.attributes['method'] ? r.attributes['method'] : ''}
316
+ end
317
+ when "where"
318
+ @where = ele.attributes['valueString']
319
+ when "link"
320
+ if ele.attributes['rel'] == 'edit'
321
+ @edit_feed = ele.attributes['href']
322
+ end
323
+ when "who"
324
+ if ele.attributes['rel'] == "http://schemas.google.com/g/2005#event.attendee"
325
+ n = {}
326
+ ele.attributes.each do |name, value|
327
+ case name
328
+ when "email"
329
+ n[:email] = value
330
+ when "valueString"
331
+ n[:name] = value
332
+ end
333
+ end
334
+ @attendees << n
335
+ end
336
+ when "eventStatus"
337
+ case ele.attributes["value"]
338
+ when "http://schemas.google.com/g/2005#event.confirmed"
339
+ @status = :confirmed
340
+ when "http://schemas.google.com/g/2005#event.tentative"
341
+ @status = :tentative
342
+ when "http://schemas.google.com/g/2005#event.cancelled"
343
+ @status = :cancelled
344
+ end
345
+ when 'recurrence'
346
+ @recurrence = ele.text #Recurrence.new(ele.text)
347
+ when "transparency"
348
+ case ele.attributes["value"]
349
+ when "http://schemas.google.com/g/2005#event.transparent"
350
+ @transparency = :free
351
+ when "http://schemas.google.com/g/2005#event.opaque"
352
+ @transparency = :busy
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ #Reloads the event data from the Google Calendar Service. Returns true if successful,
359
+ #false otherwise.
360
+ def reload
361
+ t = Event.find(@calendar, @id)
362
+ if t
363
+ if load(t.to_xml)
364
+ return true
365
+ else
366
+ return false
367
+ end
368
+ else
369
+ return false
370
+ end
371
+ end
372
+
373
+ #Finds the event that matches a query term in the event title or description.
374
+ #
375
+ #'query' is a string to perform the search on or an event id.
376
+ #
377
+ #The params hash can contain the following hash values
378
+ #* *scope*: may be :all or :first, indicating whether to return the first record found or an array of all records that match the query. Default is :all.
379
+ #* *range*: a hash including a :start and :end time to constrain the search by
380
+ #* *max_results*: an integer indicating the number of results to return. Default is 25.
381
+ #* *sort_order*: either 'ascending' or 'descending'.
382
+ #* *single_events*: either 'true' to return all recurring events as a single entry, or 'false' to return all recurring events as a unique event for each recurrence.
383
+ #* *ctz*: the timezone to return the event times in
384
+ def self.find(calendar, query = '', params = {})
385
+ query_string = ''
386
+
387
+ begin
388
+ test = URI.parse(query).scheme
389
+ rescue Exception => e
390
+ test = nil
391
+ end
392
+
393
+ if test
394
+ puts "id passed, finding event by id" if calendar.service.debug
395
+ puts "id = "+query if calendar.service.debug
396
+ event_id = query.gsub("/events/","/private/full/") #fix provided by groesser3
397
+
398
+ es = calendar.service.send_get(event_id)
399
+ puts es.inspect if calendar.service.debug
400
+ if es
401
+ entry = REXML::Document.new(es.read_body).root
402
+ puts 'event found' if calendar.service.debug
403
+ Event.define_xml_namespaces(entry)
404
+ event = Event.new(calendar)
405
+ event.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
406
+ return event
407
+ end
408
+ return nil
409
+ end
410
+
411
+
412
+ #parse params hash for values
413
+ range = params[:range] || nil
414
+ max_results = params[:max_results] || nil
415
+ sort_order = params[:sortorder] || nil
416
+ single_events = params[:singleevents] || nil
417
+ timezone = params[:ctz] || nil
418
+
419
+ #set up query string
420
+ query_string += "q=#{CGI.escape(query)}" if query
421
+ if range
422
+ if not range.is_a? Hash or (range.size > 0 and (not range[:start].is_a? Time or not range[:end].is_a? Time))
423
+ raise "The date range must be a hash including the :start and :end date values as Times"
424
+ else
425
+ date_range = ''
426
+ if range.size > 0
427
+ #Added via patch from Fabio Inguaggiato
428
+ query_string += "&start-min=#{CGI::escape(range[:start].xmlschema)}&start-max=#{CGI::escape(range[:end].xmlschema)}"
429
+ end
430
+ end
431
+ end
432
+ query_string += "&max-results=#{max_results}" if max_results
433
+ query_string += "&sortorder=#{sort_order}" if sort_order
434
+ query_string += "&ctz=#{timezone.gsub(" ", "_")}" if timezone
435
+ query_string += "&singleevents=#{single_events}" if single_events
436
+ if query_string
437
+ events = calendar.service.send_get("http://www.google.com/calendar/feeds/#{calendar.id}/private/full?"+query_string)
438
+ ret = []
439
+ REXML::Document.new(events.read_body).root.elements.each("entry"){}.map do |entry|
440
+ Event.define_xml_namespaces(entry)
441
+ event = Event.new(calendar)
442
+ event.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
443
+ ret << event
444
+ end
445
+ end
446
+ if params[:scope] == :first
447
+ return ret[0]
448
+ else
449
+ return ret
450
+ end
451
+ end
452
+
453
+ #Returns true if the event exists on the Google Calendar Service.
454
+ def exists?
455
+ return @exists
456
+ end
457
+
458
+ private
459
+ @exists = false
460
+ @calendar = nil
461
+ @xml = nil
462
+ @etag = nil
463
+ @recurrence = nil
464
+ @deleted = false
465
+ @edit_feed = ''
466
+
467
+ def self.define_xml_namespaces(entry)
468
+ entry.attributes["xmlns:gCal"] = "http://schemas.google.com/gCal/2005"
469
+ entry.attributes["xmlns:gd"] = "http://schemas.google.com/g/2005"
470
+ entry.attributes["xmlns:app"] = "http://www.w3.org/2007/app"
471
+ entry.attributes["xmlns"] = "http://www.w3.org/2005/Atom"
472
+ entry.attributes["xmlns:georss"] = "http://www.georss.org/georss"
473
+ entry.attributes["xmlns:gml"] = "http://www.opengis.net/gml"
474
+ end
475
+
476
+ def set_reminder(ele)
477
+ ele.delete_element("gd:reminder")
478
+ if @reminder
479
+ e = ele.add_element("gd:reminder")
480
+ used = false
481
+ if @reminder[:minutes]
482
+ e.attributes['minutes'] = @reminder[:minutes]
483
+ used = true
484
+ elsif @reminder[:hours] and not used
485
+ e.attributes['hours'] = @reminder[:hours]
486
+ used = true
487
+ elsif @reminder[:days] and not used
488
+ e.attributes['days'] = @reminder[:days]
489
+ end
490
+ if @reminder[:method]
491
+ e.attributes['method'] = @reminder[:method]
492
+ else
493
+ e.attributes['method'] = 'email'
494
+ end
495
+ else
496
+ ele.delete_element("gd:reminder")
497
+ end
498
+ end
499
+ end
500
+ end
501
+