h13ronim-gcal4ruby 0.2.6

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 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