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.
- data/CHANGELOG +17 -0
- data/README +41 -29
- data/lib/gcal4ruby/calendar.rb +321 -416
- data/lib/gcal4ruby/event.rb +295 -349
- data/lib/gcal4ruby/recurrence.rb +77 -17
- data/lib/gcal4ruby/service.rb +146 -138
- data/test/unit.rb +11 -9
- metadata +15 -7
- data/lib/gcal4ruby/base.rb +0 -283
data/lib/gcal4ruby/event.rb
CHANGED
@@ -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(
|
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
|
-
#
|
20
|
-
# event = Event.find(
|
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
|
-
#
|
23
|
-
# event = Event.
|
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.
|
28
|
-
# event.recurrence.
|
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
|
-
#
|
33
|
-
# event = Event.new(
|
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.
|
36
|
-
# event.
|
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
|
-
#
|
42
|
-
# event = Event.new(
|
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.
|
45
|
-
# event.
|
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
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
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
|
84
|
-
|
85
|
-
#
|
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
|
-
|
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)
|
119
|
-
|
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
|
137
|
-
if str.is_a?String
|
138
|
-
|
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
|
-
|
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
|
149
|
-
if str.is_a?String
|
150
|
-
|
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
|
-
|
153
|
-
else
|
154
|
-
raise "End Time must be either Time or String"
|
207
|
+
str
|
155
208
|
end
|
156
209
|
end
|
157
210
|
|
158
|
-
#
|
159
|
-
def
|
160
|
-
|
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
|
-
#
|
182
|
-
def
|
183
|
-
|
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
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
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(
|
236
|
+
xml = REXML::Document.new(super)
|
223
237
|
xml.root.elements.each(){}.map do |ele|
|
224
238
|
case ele.name
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
242
|
-
ele.
|
243
|
-
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
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
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
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
|
-
|
362
|
-
|
363
|
-
|
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
|
374
|
-
|
375
|
-
|
376
|
-
#
|
377
|
-
#
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
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
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
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
|
-
|
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
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
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
|
-
|
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.
|
415
|
+
num = ele.elements.delete_all "gd:reminder"
|
416
|
+
puts 'num = '+num.size.to_s if service.debug
|
478
417
|
if @reminder
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
e.attributes['minutes'] =
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
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
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
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
|
-
|
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
|