h13ronim-gcal4ruby 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,32 @@
1
+ #=CHANGELOG
2
+ #==version 0.2.6
3
+ #* Added fix for updated google calendar XML per http://cookingandcoding.wordpress.com/2009/06/08/new-ruby-google-calendar-api-gem-gcal4ruby/#comment-183
4
+ #==version 0.2.5
5
+ #* Added calendar color support to to_iframe methods in Calendar and Service.
6
+ #==version 0.2.4
7
+ #* Fixed bug with ACL check in Calendar#load
8
+ #==version 0.2.3
9
+ #* Implemented to_iframe method for calendars and services to output embeddable iframe text.
10
+ #* Added switch to turn off ACL check for public calendars. Can increase effeciency if turned off.
11
+ #==version 0.2.2
12
+ #* Fixed URL encoding problem in Event.find method.
13
+ #* cleaned up Event.find method to allow for finding events by id
14
+ #* updated Calendar.find method to add params hash
15
+ #* added 'published', 'updated', and 'edited' attributes
16
+ #==version 0.2.1
17
+ #* fixed Event.find calendar specification
18
+ #==version 0.2.0
19
+ #* Fixed redirect URI query params problem
20
+ #* Updated syntax for finding events to include most google api parameters, Non-backwards compatible.
21
+ #==version 0.1.4
22
+ #* Added additional search criteria for Event.find
23
+ #==version 0.1.3
24
+ #* Added support for authenticating with Google Hosted Apps accounts
25
+ #* Added flag to indicate whether a calendar is editable
26
+ #* Added handling to gracefully throw error when trying to create event on a non-editable (shared) calendar
27
+ #==version 0.1.2
28
+ #* Fixed to_xml dump problem with hidden and selected attributes
29
+ #==version 0.1.1
30
+ #* Added all_day indicator to event to indicate an all day event
31
+ #==version 0.1.0
32
+ #* Initial Version
data/README ADDED
@@ -0,0 +1,85 @@
1
+ #=GCal4Ruby
2
+ #
3
+ #==Introduction
4
+ #GCal4Ruby is a full featured wrapper for the google calendar API. GCal4Ruby implements
5
+ #all of the functionality available through the Google Calnedar API, including permissions,
6
+ #attendees, reminders and event recurrence.
7
+ #
8
+ #==Author and Contact Information
9
+ #GCal4Ruby was created and is maintained by {Mike Reich}[mailto:mike@seabourneconsulting.com]
10
+ #and is licenses under the GPL v2. Feel free to use and update, but be sure to contribute your
11
+ #code back to the project and attribute as required by the license.
12
+ #===Website
13
+ #http://rubyforge.org/projects/gcal4ruby/
14
+ #
15
+ #==Description
16
+ #GCal4Ruby has three major components: the service, calendar and event objects. Each service
17
+ #has many calendars, which in turn have many events. Each service is the representation of a
18
+ #google account, and thus must be successfully authenticated using valid Google Calendar
19
+ #account credentials.
20
+ #
21
+ #==Examples
22
+ #Below are some common usage examples. For more examples, check the documentation.
23
+ #===Service
24
+ #1. Authenticate
25
+ # service = Service.new
26
+ # service.authenticate("user@gmail.com", "password")
27
+ #
28
+ #2. Get Calendar List
29
+ # calendars = service.calendars
30
+ #
31
+ #===Calendar
32
+ #All usages assume a successfully authenticated Service.
33
+ #1. Create a new Calendar
34
+ # cal = Calendar.new(service)
35
+ #
36
+ #2. Find an existing Calendar
37
+ # cal = Calendar.find(service, "New Calendar", :first)
38
+ #
39
+ #3. Find all calendars containing the search term
40
+ # cal = Calendar.find(service, "Soccer Team")
41
+ #
42
+ #4. Find a calendar by ID
43
+ # cal = Calendar.find(service, id, :first)
44
+ #===Event
45
+ #All usages assume a successfully authenticated Service and valid Calendar.
46
+ #1. Create a new Event
47
+ # event = Event.new(calendar)
48
+ # event.title = "Soccer Game"
49
+ # event.start = Time.parse("12-06-2009 at 12:30 PM")
50
+ # event.end = Time.parse("12-06-2009 at 1:30 PM")
51
+ # event.where = "Merry Playfields"
52
+ # event.save
53
+ #
54
+ #2. Find an existing Event
55
+ # event = Event.find(cal, "Soccer Game", {:scope => :first})
56
+ #
57
+ #3. Find all events containing the search term
58
+ # event = Event.find(cal, "Soccer Game")
59
+ #
60
+ #4. Create a recurring event for every saturday
61
+ # event = Event.new(calendar)
62
+ # event.title = "Baseball Game"
63
+ # event.where = "Municipal Stadium"
64
+ # event.recurrence = Recurrence.new
65
+ # event.recurrence.start = Time.parse("13-06-2009 at 4:30 PM")
66
+ # event.recurrence.end = Time.parse("13-06-2009 at 6:30 PM")
67
+ # event.recurrence.frequency = {"weekly" => ["SA"]}
68
+ # event.save
69
+ #
70
+ #5. Create an event with a 15 minute email reminder
71
+ # event = Event.new(calendar)
72
+ # event.title = "Dinner with Kate"
73
+ # event.start = Time.parse("20-06-2009 at 5 pm")
74
+ # event.end = Time.parse("20-06-209 at 8 pm")
75
+ # event.where = "Luigi's"
76
+ # event.reminder = {:minutes => 15, :method => 'email'}
77
+ # event.save
78
+ #
79
+ #6. Create an event with attendees
80
+ # event = Event.new(calendar)
81
+ # event.title = "Dinner with Kate"
82
+ # event.start = Time.parse("20-06-2009 at 5 pm")
83
+ # event.end = Time.parse("20-06-209 at 8 pm")
84
+ # event.attendees => {:name => "Kate", :email => "kate@gmail.com"}
85
+ # event.save
@@ -0,0 +1,260 @@
1
+ require "rexml/document"
2
+ require "cgi"
3
+ require "uri"
4
+ require "net/http"
5
+ require "net/https"
6
+ require "open-uri"
7
+ require "nkf"
8
+ require "time"
9
+
10
+ Net::HTTP.version_1_2
11
+
12
+ # GCal4Ruby is a full featured wrapper for the google calendar API
13
+
14
+ # =Usage:
15
+
16
+ module GCal4Ruby
17
+
18
+ CALENDAR_XML = "<entry xmlns='http://www.w3.org/2005/Atom'
19
+ xmlns:gd='http://schemas.google.com/g/2005'
20
+ xmlns:gCal='http://schemas.google.com/gCal/2005'>
21
+ <title type='text'></title>
22
+ <summary type='text'></summary>
23
+ <gCal:timezone value=''></gCal:timezone>
24
+ <gCal:hidden value=''></gCal:hidden>
25
+ <gCal:color value=''></gCal:color>
26
+ <gd:where rel='' label='' valueString=''></gd:where>
27
+ </entry>"
28
+
29
+ ACL_XML = "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'>
30
+ <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
31
+ <gAcl:scope type='default'></gAcl:scope>
32
+ <gAcl:role value=''></gAcl:role>
33
+ </entry>"
34
+
35
+ EVENT_XML = "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
36
+ <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category>
37
+ <title type='text'></title>
38
+ <content type='text'></content>
39
+ <gd:transparency value=''></gd:transparency>
40
+ <gd:eventStatus value=''></gd:eventStatus>
41
+ <gd:where valueString=''></gd:where>
42
+ <gd:when startTime='' endTime=''></gd:when>
43
+ </entry>
44
+ "
45
+
46
+ class AuthenticationFailed < StandardError; end #:nodoc: all
47
+
48
+ class NotAuthenticated < StandardError; end
49
+
50
+ class InvalidService < StandardError; end
51
+
52
+ class HTTPPostFailed < StandardError; end
53
+
54
+ class HTTPPutFailed < StandardError; end
55
+
56
+ class HTTPGetFailed < StandardError; end
57
+
58
+ class HTTPDeleteFailed < StandardError; end
59
+
60
+ class CalendarSaveFailed < StandardError; end
61
+
62
+ class EventSaveFailed < StandardError; end
63
+
64
+ class RecurrenceValueError < StandardError; end
65
+
66
+ class CalendarNotEditable < StandardError; end
67
+
68
+ class QueryParameterError < StandardError; end
69
+
70
+ #The ProxyInfo class contains information for configuring a proxy connection
71
+
72
+ class ProxyInfo
73
+ attr_accessor :address, :port, :username, :password
74
+ @address = nil
75
+ @port = nil
76
+ @username = nil
77
+ @password = nil
78
+
79
+ #The initialize function accepts four variables for configuring the ProxyInfo object.
80
+ #The proxy connection is initiated using the builtin Net::HTTP proxy support.
81
+
82
+ def initialize(address, port, username=nil, password=nil)
83
+ @address = address
84
+ @port = port
85
+ @username = username
86
+ @password = password
87
+ end
88
+ end
89
+
90
+ #The Base class includes the basic HTTP methods for sending and receiving
91
+ #messages from the Google Calendar API. You shouldn't have to use this class
92
+ #directly, rather access the functionality through the Service subclass.
93
+
94
+ class Base
95
+ AUTH_URL = "https://www.google.com/accounts/ClientLogin"
96
+ CALENDAR_LIST_FEED = "http://www.google.com/calendar/feeds/default/allcalendars/full"
97
+ @proxy_info = nil
98
+ @auth_token = nil
99
+ @debug = false
100
+
101
+ #Contains the ProxyInfo object for using a proxy server
102
+ attr_accessor :proxy_info
103
+
104
+ #If set to true, debug will dump all raw HTTP requests and responses
105
+ attr_accessor :debug
106
+
107
+ # Sends an HTTP POST request. The header should be a hash of name/value pairs.
108
+ # Returns the Net::HTTPResponse object on succces, or raises the appropriate
109
+ # error if a non 20x response code is received.
110
+ def send_post(url, content, header=nil)
111
+ header = auth_header(header)
112
+ ret = nil
113
+ location = URI.parse(url)
114
+ https = get_http_object(location)
115
+ puts "url = "+url if @debug
116
+ if location.scheme == 'https'
117
+ puts "SSL True" if @debug
118
+ https.use_ssl = true
119
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
120
+ end
121
+ puts "Starting post\nHeader: #{header}\nContent: #{content}" if @debug
122
+ https.start do |http|
123
+ ret = http.post(location.to_s, content, header)
124
+ end
125
+ while ret.is_a?(Net::HTTPRedirection)
126
+ puts "Redirect recieved, resending post" if @debug
127
+ https.start do |http|
128
+ ret = http.post(ret['location'], content, header)
129
+ end
130
+ end
131
+ if ret.is_a?(Net::HTTPSuccess)
132
+ puts "20x response recieved\nResponse: \n"+ret.read_body if @debug
133
+ return ret
134
+ else
135
+ puts "invalid response received: "+ret.code if @debug
136
+ raise HTTPPostFailed, ret.body
137
+ end
138
+ end
139
+
140
+ # Sends an HTTP PUT request. The header should be a hash of name/value pairs.
141
+ # Returns the Net::HTTPResponse object on succces, or raises the appropriate
142
+ # error if a non 20x response code is received.
143
+ def send_put(url, content, header=nil)
144
+ header = auth_header(header)
145
+ ret = nil
146
+ location = URI.parse(url)
147
+ https = get_http_object(location)
148
+ puts "url = "+url if @debug
149
+ if location.scheme == 'https'
150
+ puts "SSL True" if @debug
151
+ https.use_ssl = true
152
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
153
+ end
154
+ puts "Starting post\nHeader: #{header}\nContent: #{content}" if @debug
155
+ https.start do |http|
156
+ ret = http.put(location.to_s, content, header)
157
+ end
158
+ while ret.is_a?(Net::HTTPRedirection)
159
+ puts "Redirect recieved, resending post" if @debug
160
+ https.start do |http|
161
+ ret = http.put(ret['location'], content, header)
162
+ end
163
+ end
164
+ if ret.is_a?(Net::HTTPSuccess)
165
+ puts "20x response recieved\nResponse: \n"+ret.read_body if @debug
166
+ return ret
167
+ else
168
+ puts "invalid response received: "+ret.code if @debug
169
+ raise HTTPPutFailed, ret.body
170
+ end
171
+ end
172
+
173
+ # Sends an HTTP GET request. The header should be a hash of name/value pairs.
174
+ # Returns the Net::HTTPResponse object on succces, or raises the appropriate
175
+ # error if a non 20x response code is received.
176
+ def send_get(url, header = nil)
177
+ header = auth_header(header)
178
+ ret = nil
179
+ location = URI.parse(url)
180
+ http = get_http_object(location)
181
+ puts "url = "+url if @debug
182
+ if location.scheme == 'https'
183
+ puts "SSL True" if @debug
184
+ https.use_ssl = true
185
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
186
+ end
187
+ puts "Starting post\nHeader: #{header}\n" if @debug
188
+ http.start do |http|
189
+ ret = http.get(location.to_s, header)
190
+ end
191
+ while ret.is_a?(Net::HTTPRedirection)
192
+ puts "Redirect recieved, resending get to #{ret['location']}" if @debug
193
+ http.start do |http|
194
+ ret = http.get(ret['location'], header)
195
+ end
196
+ end
197
+ if ret.is_a?(Net::HTTPSuccess)
198
+ puts "20x response recieved\nResponse: \n"+ret.read_body if @debug
199
+ return ret
200
+ else
201
+ puts "Error recieved, resending get" if @debug
202
+ raise HTTPGetFailed, ret.body
203
+ end
204
+ end
205
+
206
+ # Sends an HTTP DELETE request. The header should be a hash of name/value pairs.
207
+ # Returns the Net::HTTPResponse object on succces, or raises the appropriate
208
+ # error if a non 20x response code is received.
209
+ def send_delete(url, header = nil)
210
+ header = auth_header(header)
211
+ ret = nil
212
+ location = URI.parse(url)
213
+ https = get_http_object(location)
214
+ puts "url = "+url if @debug
215
+ if location.scheme == 'https'
216
+ puts "SSL True" if @debug
217
+ https.use_ssl = true
218
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
219
+ end
220
+ puts "Starting post\nHeader: #{header}\n" if @debug
221
+ https.start do |http|
222
+ ret = http.delete(location.to_s, header)
223
+ end
224
+ while ret.is_a?(Net::HTTPRedirection)
225
+ puts "Redirect recieved, resending post" if @debug
226
+ https.start do |http|
227
+ ret = http.delete(ret['location'], header)
228
+ end
229
+ end
230
+ if ret.is_a?(Net::HTTPSuccess)
231
+ puts "20x response recieved\nResponse: \n"+ret.read_body if @debug
232
+ return true
233
+ else
234
+ puts "invalid response received: "+ret.code if @debug
235
+ raise HTTPDeleteFailed, ret.body
236
+ end
237
+ end
238
+
239
+ private
240
+
241
+ def get_http_object(location)
242
+ if @proxy_info and @proxy_info.address
243
+ return Net::HTTP.new(location.host, location.port, @proxy_info.address, @proxy_info.port, @proxy_info.username, @proxy_info.password)
244
+ else
245
+ return Net::HTTP.new(location.host, location.port)
246
+ end
247
+ end
248
+
249
+ def auth_header(header)
250
+ if @auth_token
251
+ if header
252
+ header.merge!({'Authorization' => "GoogleLogin auth=#{@auth_token}", "GData-Version" => "2.1"})
253
+ else
254
+ header = {'Authorization' => "GoogleLogin auth=#{@auth_token}", "GData-Version" => "2.1"}
255
+ end
256
+ end
257
+ return header
258
+ end
259
+ end
260
+ end