gcal4ruby 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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