gcal4ruby 0.3.1 → 0.5.0

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.
@@ -1,57 +1,106 @@
1
+ # Author:: Mike Reich (mike@seabourneconsulting.com)
2
+ # Copyright:: Copyright (C) 2010 Mike Reich
3
+ # License:: GPL v2
4
+ #--
5
+ # Licensed under the General Public License (GPL), Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ #
15
+ # Feel free to use and update, but be sure to contribute your
16
+ # code back to the project and attribute as required by the license.
17
+ #++
18
+
1
19
  require 'gcal4ruby/recurrence'
2
20
 
3
21
  module GCal4Ruby
4
- #The Event Class represents a remote event in calendar.
22
+ #The Event Class represents a remote event in calendar
5
23
  #
6
24
  #=Usage
7
25
  #All usages assume a successfully authenticated Service and valid Calendar.
8
26
  #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"
27
+ # event = Event.new(service, {:calendar => cal, :title => "Soccer Game", :start => Time.parse("12-06-2009 at 12:30 PM"), :end => Time.parse("12-06-2009 at 1:30 PM"), :where => "Merry Playfields"})
14
28
  # event.save
15
29
  #
16
- #2. Find an existing Event
17
- # event = Event.find(cal, "Soccer Game", {:scope => :first})
30
+ #2. Find an existing Event by title
31
+ # event = Event.find(service, {:title => "Soccer Game"})
32
+ #
33
+ #3. Find an existing Event by ID
34
+ # event = Event.find(service, {:id => event.id})
35
+ #
36
+ #4. Find all events containing the search term
37
+ # event = Event.find(service, "Soccer Game")
18
38
  #
19
- #3. Find all events containing the search term
20
- # event = Event.find(cal, "Soccer Game")
39
+ #5. Find all events on a calendar containing the search term
40
+ # event = Event.find(service, "Soccer Game", {:calendar => cal.id})
21
41
  #
22
- #4. Create a recurring event for every saturday
23
- # event = Event.new(calendar)
42
+ #6. Find events within a date range
43
+ # event = Event.find(service, "Soccer Game", {'start-min' => Time.parse("01/01/2010").utc.xmlschema, 'start-max' => Time.parse("06/01/2010").utc.xmlschema})
44
+ #
45
+ #7. Create a recurring event for every saturday
46
+ # event = Event.new(service)
24
47
  # event.title = "Baseball Game"
48
+ # event.calendar = cal
25
49
  # event.where = "Municipal Stadium"
26
50
  # 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")
51
+ # event.recurrence.start_time = Time.parse("06/20/2009 at 4:30 PM")
52
+ # event.recurrence.end_time = Time.parse("06/20/2009 at 6:30 PM")
29
53
  # event.recurrence.frequency = {"weekly" => ["SA"]}
30
54
  # event.save
31
55
  #
32
- #5. Create an event with a 15 minute email reminder
33
- # event = Event.new(calendar)
56
+ #8. Create an event with a 15 minute email reminder
57
+ # event = Event.new(service)
58
+ # event.calendar = cal
34
59
  # 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")
60
+ # event.start_time = Time.parse("06/20/2009 at 5 pm")
61
+ # event.end_time = Time.parse("06/20/2009 at 8 pm")
37
62
  # event.where = "Luigi's"
38
63
  # event.reminder = {:minutes => 15, :method => 'email'}
39
64
  # event.save
40
65
  #
41
- #6. Create an event with attendees
42
- # event = Event.new(calendar)
66
+ #9. Create an event with attendees
67
+ # event = Event.new(service)
68
+ # event.calendar = cal
43
69
  # 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")
70
+ # event.start_time = Time.parse("06/20/2009 at 5 pm")
71
+ # event.end_time = Time.parse("06/20/2009 at 8 pm")
46
72
  # event.attendees => {:name => "Kate", :email => "kate@gmail.com"}
47
73
  # event.save
48
74
  #
49
75
  #After an event object has been created or loaded, you can change any of the
50
76
  #attributes like you would any other object. Be sure to save the event to write changes
51
77
  #to the Google Calendar service.
52
- class Event
53
- #The event title
54
- attr_accessor :title
78
+
79
+ class Event < GData4Ruby::GDataObject
80
+ EVENT_QUERY_FEED = "http://www.google.com/calendar/feeds/default/private/full/"
81
+ EVENT_XML = "<entry xmlns='http://www.w3.org/2005/Atom'
82
+ xmlns:gd='http://schemas.google.com/g/2005'>
83
+ <category scheme='http://schemas.google.com/g/2005#kind'
84
+ term='http://schemas.google.com/g/2005#event'></category>
85
+ <title type='text'></title>
86
+ <content type='text'></content>
87
+ <gd:transparency
88
+ value='http://schemas.google.com/g/2005#event.opaque'>
89
+ </gd:transparency>
90
+ <gd:eventStatus
91
+ value='http://schemas.google.com/g/2005#event.confirmed'>
92
+ </gd:eventStatus>
93
+ <gd:where valueString=''></gd:where>
94
+ <gd:when startTime=''
95
+ endTime=''></gd:when>
96
+ </entry>"
97
+ STATUS = {:confirmed => "http://schemas.google.com/g/2005#event.confirmed",
98
+ :tentative => "http://schemas.google.com/g/2005#event.tentative",
99
+ :cancelled => "http://schemas.google.com/g/2005#event.canceled"}
100
+
101
+ TRANSPARENCY = {:free => "http://schemas.google.com/g/2005#event.transparent",
102
+ :busy => "http://schemas.google.com/g/2005#event.opaque"}
103
+
55
104
  #The content for the event
56
105
  attr_accessor :content
57
106
  #The location of the event
@@ -60,33 +109,34 @@ module GCal4Ruby
60
109
  attr_accessor :transparency
61
110
  #A flag indicating the status of the event. Values can be :confirmed, :tentative or :cancelled
62
111
  attr_accessor :status
63
- #The unique event ID
64
- attr_accessor :id
65
112
  #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
113
+ attr_reader :all_day
74
114
  #The reminder settings for the event, returned as a hash
75
115
  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
116
  #The date the event was last edited
81
117
  attr_reader :edited
118
+ #Id of the parent calendar
119
+ attr_reader :calendar_id
120
+
121
+ #Creates a new Event. Accepts a valid Service object and optional attributes hash.
122
+ def initialize(service, attributes = {})
123
+ super(service, attributes)
124
+ attributes.each do |key, value|
125
+ self.send("#{key}=", value)
126
+ end
127
+ @xml = EVENT_XML
128
+ @transparency ||= "http://schemas.google.com/g/2005#event.opaque"
129
+ @status ||= "http://schemas.google.com/g/2005#event.confirmed"
130
+ @attendees ||= []
131
+ @all_day ||= false
132
+ @reminder = []
133
+ @start_time = @end_time = @calendar_id = nil
134
+ end
82
135
 
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
136
+ #Sets the reminder options for the event. Parameter must be a hash a :minutes key with a value of 5 up to 40320 (4 weeks)
137
+ #and a :method key of with a value of one the following:
138
+ #alert:: causes an alert to appear when a user is viewing the calendar in a browser
139
+ #email:: sends the user an email message
90
140
  def reminder=(r)
91
141
  @reminder = r
92
142
  end
@@ -101,31 +151,36 @@ module GCal4Ruby
101
151
  @attendees
102
152
  end
103
153
 
154
+ def all_day=(value)
155
+ puts 'all_day value = '+value.to_s if service.debug
156
+ if value.is_a? String
157
+ @all_day = true if value.downcase == 'true'
158
+ @all_day = false if value.downcase == 'false'
159
+ else
160
+ @all_day = value
161
+ end
162
+ puts 'after all_day value = '+@all_day.to_s if service.debug
163
+ @all_day
164
+ end
165
+
104
166
  #Accepts an array of email address/name pairs for attendees.
105
167
  # [{:name => 'Mike Reich', :email => 'mike@seabourneconsulting.com'}]
106
168
  #The email address is requried, but the name is optional
107
169
  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
170
+ raise ArgumentError, "Attendees must be an Array of email/name hash pairs" if not a.is_a?(Array)
171
+ @attendees = a
113
172
  end
114
173
 
115
174
  #Sets the event's recurrence information to a Recurrence object. Returns the recurrence if successful,
116
175
  #false otherwise
117
176
  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
177
+ raise ArgumentError, 'Recurrence must be a Recurrence object' if not r.is_a?(Recurrence)
178
+ @recurrence = r
124
179
  end
125
180
 
126
181
  #Returns a duplicate of the current event as a new Event object
127
182
  def copy()
128
- e = Event.new()
183
+ e = Event.new(service)
129
184
  e.load(to_xml)
130
185
  e.calendar = @calendar
131
186
  return e
@@ -133,154 +188,96 @@ module GCal4Ruby
133
188
 
134
189
  #Sets the start time of the Event. Must be a Time object or a parsable string representation
135
190
  #of a time.
136
- def start=(str)
137
- if str.is_a?String
138
- @start = Time.parse(str)
191
+ def start_time=(str)
192
+ raise ArgumentError, "Start Time must be either Time or String" if not str.is_a?String and not str.is_a?Time
193
+ @start_time = if str.is_a?String
194
+ Time.parse(str)
139
195
  elsif str.is_a?Time
140
- @start = str
141
- else
142
- raise "Start Time must be either Time or String"
196
+ str
143
197
  end
144
198
  end
145
199
 
146
200
  #Sets the end time of the Event. Must be a Time object or a parsable string representation
147
201
  #of a time.
148
- def end=(str)
149
- if str.is_a?String
150
- @end = Time.parse(str)
202
+ def end_time=(str)
203
+ raise ArgumentError, "End Time must be either Time or String" if not str.is_a?String and not str.is_a?Time
204
+ @end_time = if str.is_a?String
205
+ Time.parse(str)
151
206
  elsif str.is_a?Time
152
- @end = str
153
- else
154
- raise "End Time must be either Time or String"
207
+ str
155
208
  end
156
209
  end
157
210
 
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
211
+ #The event start time. If a recurring event, the recurrence start time.
212
+ def start_time
213
+ return @start_time ? @start_time : @recurrence ? @recurrence .start_time : nil
179
214
  end
180
215
 
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
216
+ #The event end time. If a recurring event, the recurrence end time.
217
+ def end_time
218
+ return @end_time ? @end_time : @recurrence ? @recurrence.end_time : nil
196
219
  end
220
+
197
221
 
198
222
  #If the event does not exist on the Google Calendar service, save creates it. Otherwise
199
223
  #updates the existing event data. Returns true on success, false otherwise.
200
224
  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
225
+ raise CalendarNotEditable if not calendar.editable
226
+ super
227
+ end
228
+
229
+ #Creates a new event
230
+ def create
231
+ service.send_request(GData4Ruby::Request.new(:post, @parent_calendar.content_uri, to_xml))
218
232
  end
219
233
 
220
234
  #Returns an XML representation of the event.
221
235
  def to_xml()
222
- xml = REXML::Document.new(@xml)
236
+ xml = REXML::Document.new(super)
223
237
  xml.root.elements.each(){}.map do |ele|
224
238
  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
239
+ when "content"
240
+ ele.text = @content
241
+ when "when"
242
+ if not @recurrence
243
+ puts 'all_day = '+@all_day.to_s if service.debug
244
+ if @all_day
245
+ puts 'saving as all-day event' if service.debug
246
+ else
247
+ puts 'saving as timed event' if service.debug
248
+ end
249
+ ele.attributes["startTime"] = @all_day ? @start_time.strftime("%Y-%m-%d") : @start_time.utc.xmlschema
250
+ ele.attributes["endTime"] = @all_day ? @end_time.strftime("%Y-%m-%d") : @end_time.utc.xmlschema
251
+ set_reminder(ele)
240
252
  else
241
- ele.delete_attribute('startTime')
242
- ele.delete_attribute('endTime')
243
- set_reminder(ele)
253
+ xml.root.delete_element("/entry/gd:when")
254
+ ele = xml.root.add_element("gd:recurrence")
255
+ ele.text = @recurrence.to_recurrence_string
256
+ set_reminder(ele) if @reminder
244
257
  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"
258
+ when "eventStatus"
259
+ ele.attributes["value"] = STATUS[@status]
260
+ when "transparency"
261
+ ele.attributes["value"] = TRANSPARENCY[@transparency]
262
+ when "where"
263
+ ele.attributes["valueString"] = @where
264
+ when "recurrence"
265
+ puts 'recurrence element found' if service.debug
266
+ if @recurrence
267
+ puts 'setting recurrence' if service.debug
268
+ ele.text = @recurrence.to_recurrence_string
254
269
  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"
270
+ puts 'no recurrence, adding when' if service.debug
271
+ w = xml.root.add_element("gd:when")
272
+ xml.root.delete_element("/entry/gd:recurrence")
273
+ w.attributes["startTime"] = @all_day ? @start_time.strftime("%Y-%m-%d") : @start_time.xmlschema
274
+ w.attributes["endTime"] = @all_day ? @end_time.strftime("%Y-%m-%d") : @end_time.xmlschema
275
+ set_reminder(w)
265
276
  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
277
  end
282
278
  end
283
279
  if not @attendees.empty?
280
+ xml.root.elements.delete_all "gd:who"
284
281
  @attendees.each do |a|
285
282
  xml.root.add_element("gd:who", {"email" => a[:email], "valueString" => a[:name], "rel" => "http://schemas.google.com/g/2005#event.attendee"})
286
283
  end
@@ -288,166 +285,124 @@ module GCal4Ruby
288
285
  xml.to_s
289
286
  end
290
287
 
288
+ #The event's parent calendar
289
+ def calendar
290
+ @parent_calendar = Calendar.find(service, {:id => @calendar_id}) if not @parent_calendar and @calendar_id
291
+ return @parent_calendar
292
+ end
293
+
294
+ #Sets the event's calendar
295
+ def calendar=(p)
296
+ raise ArgumentError, 'Value must be a valid Calendar object' if not p.is_a? Calendar
297
+ @parent_calendar = p
298
+ end
299
+
291
300
  #Loads the event info from an XML string.
292
301
  def load(string)
302
+ super(string)
293
303
  @xml = string
294
304
  @exists = true
295
305
  xml = REXML::Document.new(string)
296
306
  @etag = xml.root.attributes['etag']
297
307
  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 = 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
308
+ case ele.name
309
+ when 'id'
310
+ @calendar_id, @id = @feed_uri.gsub("http://www.google.com/calendar/feeds/", "").split("/events/")
311
+ @id = "#{@calendar_id}/private/full/#{@id}"
312
+ when 'edited'
313
+ @edited = Time.parse(ele.text)
314
+ when 'content'
315
+ @content = ele.text
316
+ when "when"
317
+ @start_time = Time.parse(ele.attributes['startTime'])
318
+ @end_time = Time.parse(ele.attributes['endTime'])
319
+ @all_day = !ele.attributes['startTime'].include?('T')
320
+ @reminder = []
321
+ ele.elements.each("gd:reminder") do |r|
322
+ rem = {}
323
+ rem[:minutes] = r.attributes['minutes'] if r.attributes['minutes']
324
+ rem[:method] = r.attributes['method'] if r.attributes['method']
325
+ @reminder << rem
326
+ end
327
+ when "where"
328
+ @where = ele.attributes['valueString']
329
+ when "link"
330
+ if ele.attributes['rel'] == 'edit'
331
+ @edit_feed = ele.attributes['href']
332
+ end
333
+ when "who"
334
+ @attendees << {:email => ele.attributes['email'], :name => ele.attributes['valueString'], :role => ele.attributes['rel'].gsub("http://schemas.google.com/g/2005#event.", ""), :status => ele.elements["gd:attendeeStatus"] ? ele.elements["gd:attendeeStatus"].attributes['value'].gsub("http://schemas.google.com/g/2005#event.", "") : ""}
335
+ when "eventStatus"
336
+ @status = ele.attributes["value"].gsub("http://schemas.google.com/g/2005#event.", "").to_sym
337
+ when 'recurrence'
338
+ @recurrence = Recurrence.new(ele.text)
339
+ when "transparency"
340
+ @transparency = case ele.attributes["value"]
341
+ when "http://schemas.google.com/g/2005#event.transparent" then :free
342
+ when "http://schemas.google.com/g/2005#event.opaque" then :busy
343
+ end
344
+ end
345
+ end
356
346
  end
357
347
 
358
348
  #Reloads the event data from the Google Calendar Service. Returns true if successful,
359
349
  #false otherwise.
360
350
  def reload
361
- t = Event.find(@calendar, @id)
362
- if t
363
- if load(t.to_xml)
351
+ return false if not @exists
352
+ t = Event.find(service, {:id => @id})
353
+ if t and load(t.to_xml)
364
354
  return true
365
- else
366
- return false
367
- end
368
- else
369
- return false
370
355
  end
356
+ return false
371
357
  end
372
358
 
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
359
+ #Finds an Event based on a text query or by an id. Parameters are:
360
+ #*service*:: A valid Service object to search.
361
+ #*query*:: either a string containing a text query to search by, or a hash containing an +id+ key with an associated id to find, or a +query+ key containint a text query to search for, or a +title+ key containing a title to search. All searches are case insensitive.
362
+ #*args*:: a hash containing optional additional query paramters to use. Limit a search to a single calendar by passing the calendar id as {:calendar => calendar.id}. See here[http://code.google.com/apis/calendar/data/2.0/developers_guide_protocol.html#RetrievingEvents] and here[http://code.google.com/apis/gdata/docs/2.0/reference.html#Queries] for a full list of possible values. Example:
363
+ # {'max-results' => '100'}
364
+ #If an ID is specified, a single instance of the event is returned if found, otherwise false.
365
+ #If a query term or title text is specified, and array of matching results is returned, or an empty array if nothing
366
+ #was found.
367
+ def self.find(service, query, args = {})
368
+ raise ArgumentError, 'query must be a hash or string' if not query.is_a? Hash and not query.is_a? String
369
+ if query.is_a? Hash and query[:id]
370
+ id = query[:id]
371
+ puts "id passed, finding event by id" if service.debug
372
+ puts "id = "+id if service.debug
373
+ d = service.send_request(GData4Ruby::Request.new(:get, "http://www.google.com/calendar/feeds/"+id, {"If-Not-Match" => "*"}))
374
+ puts d.inspect if service.debug
375
+ if d
376
+ return get_instance(service, d)
407
377
  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"
378
+ else
379
+ results = []
380
+ if query.is_a?(Hash)
381
+ args["q"] = query[:query] if query[:query]
382
+ args['title'] = query[:title] if query[:title]
424
383
  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
384
+ args["q"] = CGI::escape(query) if query != ''
430
385
  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
386
+ if args[:calendar]
387
+ cal = Calendar.find(service, {:id => args[:calendar]})
388
+ args.delete(:calendar)
389
+ ret = service.send_request(GData4Ruby::Request.new(:get, cal.content_uri, nil, nil, args))
390
+ xml = REXML::Document.new(ret.body).root
391
+ xml.elements.each("entry") do |e|
392
+ results << get_instance(service, e)
393
+ end
394
+ else
395
+ service.calendars.each do |cal|
396
+ ret = service.send_request(GData4Ruby::Request.new(:get, cal.content_uri, nil, nil, args))
397
+ xml = REXML::Document.new(ret.body).root
398
+ xml.elements.each("entry") do |e|
399
+ results << get_instance(service, e)
400
+ end
401
+ end
444
402
  end
403
+ return results
445
404
  end
446
- if params[:scope] == :first
447
- return ret[0]
448
- else
449
- return ret
450
- end
405
+ return false
451
406
  end
452
407
 
453
408
  #Returns true if the event exists on the Google Calendar Service.
@@ -455,46 +410,37 @@ module GCal4Ruby
455
410
  return @exists
456
411
  end
457
412
 
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
-
413
+ private
476
414
  def set_reminder(ele)
477
- ele.delete_element("gd:reminder")
415
+ num = ele.elements.delete_all "gd:reminder"
416
+ puts 'num = '+num.size.to_s if service.debug
478
417
  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]
418
+ @reminder.each do |reminder|
419
+ puts 'reminder added' if service.debug
420
+ e = ele.add_element("gd:reminder")
421
+ e.attributes['minutes'] = reminder[:minutes].to_s if reminder[:minutes]
422
+ if reminder[:method]
423
+ e.attributes['method'] = reminder[:method]
424
+ else
425
+ e.attributes['method'] = 'email'
426
+ end
489
427
  end
490
- if @reminder[:method]
491
- e.attributes['method'] = @reminder[:method]
492
- else
493
- e.attributes['method'] = 'email'
428
+ end
429
+ end
430
+
431
+ def self.get_instance(service, d)
432
+ if d.is_a? Net::HTTPOK
433
+ xml = REXML::Document.new(d.read_body).root
434
+ if xml.name == 'feed'
435
+ xml = xml.elements.each("entry"){}[0]
494
436
  end
495
437
  else
496
- ele.delete_element("gd:reminder")
438
+ xml = d
497
439
  end
440
+ ele = GData4Ruby::Utils::add_namespaces(xml)
441
+ e = Event.new(service)
442
+ e.load(ele.to_s)
443
+ e
498
444
  end
499
445
  end
500
446
  end