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,3 +1,21 @@
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
  class Time
2
20
  #Returns a ISO 8601 complete formatted string of the time
3
21
  def complete
@@ -15,9 +33,9 @@ module GCal4Ruby
15
33
  #the RFC 2445 iCalendar recurrence description.
16
34
  class Recurrence
17
35
  #The event start date/time
18
- attr_reader :start
36
+ attr_reader :start_time
19
37
  #The event end date/time
20
- attr_reader :end
38
+ attr_reader :end_time
21
39
  #the event reference
22
40
  attr_reader :event
23
41
  #The date until which the event will be repeated
@@ -46,18 +64,18 @@ module GCal4Ruby
46
64
  key, value = val.split(":")
47
65
  case key
48
66
  when 'DTSTART'
49
- @start = Time.parse_complete(value)
67
+ @start_time = Time.parse_complete(value)
50
68
  when 'DTSTART;VALUE=DATE'
51
- @start = Time.parse(value)
69
+ @start_time = Time.parse(value)
52
70
  @all_day = true
53
71
  when 'DTSTART;VALUE=DATE-TIME'
54
- @start = Time.parse_complete(value)
72
+ @start_time = Time.parse_complete(value)
55
73
  when 'DTEND'
56
- @end = Time.parse_complete(value)
74
+ @end_time = Time.parse_complete(value)
57
75
  when 'DTEND;VALUE=DATE'
58
- @end = Time.parse(value)
76
+ @end_time = Time.parse(value)
59
77
  when 'DTEND;VALUE=DATE-TIME'
60
- @end = Time.parse_complete(value)
78
+ @end_time = Time.parse_complete(value)
61
79
  when 'RRULE'
62
80
  vals = value.split(";")
63
81
  key = ''
@@ -82,19 +100,61 @@ module GCal4Ruby
82
100
  end
83
101
  end
84
102
 
85
- #Returns a string with the correctly formatted ISO 8601 recurrence rule
86
103
  def to_s
104
+ output = ''
105
+ if @frequency
106
+ f = ''
107
+ i = ''
108
+ by = ''
109
+ @frequency.each do |key, v|
110
+ if v.is_a?(Array)
111
+ if v.size > 0
112
+ value = v.join(",")
113
+ else
114
+ value = nil
115
+ end
116
+ else
117
+ value = v
118
+ end
119
+ f += "#{key.downcase} " if key != 'interval'
120
+ case key.downcase
121
+ when "secondly"
122
+ by += "every #{value} second"
123
+ when "minutely"
124
+ by += "every #{value} minute"
125
+ when "hourly"
126
+ by += "every #{value} hour"
127
+ when "weekly"
128
+ by += "on #{value}" if value
129
+ when "monthly"
130
+ by += "on #{value}"
131
+ when "yearly"
132
+ by += "on the #{value} day of the year"
133
+ when 'interval'
134
+ i += "for #{value} times"
135
+ end
136
+ end
137
+ output += f+i+by
138
+ end
139
+ if @repeat_until
140
+ output += " and repeats until #{@repeat_until.strftime("%m/%d/%Y")}"
141
+ end
142
+ output
143
+ end
144
+
145
+ #Returns a string with the correctly formatted ISO 8601 recurrence rule
146
+ def to_recurrence_string
87
147
 
88
148
  output = ''
89
149
  if @all_day
90
- output += "DTSTART;VALUE=DATE:#{@start.utc.strftime("%Y%m%d")}\n"
150
+ output += "DTSTART;VALUE=DATE:#{@start_time.utc.strftime("%Y%m%d")}\n"
91
151
  else
92
- output += "DTSTART;VALUE=DATE-TIME:#{@start.complete}\n"
152
+ output += "DTSTART;VALUE=DATE-TIME:#{@start_time.complete}\n"
93
153
  end
94
154
  if @all_day
95
- output += "DTEND;VALUE=DATE:#{@end.utc.strftime("%Y%m%d")}\n"
155
+ output += "DTEND;VALUE=DATE:#{@end_time.utc.strftime("%Y%m%d")}\n"
96
156
  else
97
- output += "DTEND;VALUE=DATE-TIME:#{@end.complete}\n"
157
+ output += "DTEND;VALUE=DATE-TIME:#{@end_time.complete}\n"
98
158
  end
99
159
  output += "RRULE:"
100
160
  if @frequency
@@ -139,20 +199,20 @@ module GCal4Ruby
139
199
  end
140
200
 
141
201
  #Sets the start date/time. Must be a Time object.
142
- def start=(s)
202
+ def start_time=(s)
143
203
  if not s.is_a?(Time)
144
204
  raise RecurrenceValueError, "Start must be a date or a time"
145
205
  else
146
- @start = s
206
+ @start_time = s
147
207
  end
148
208
  end
149
209
 
150
210
  #Sets the end Date/Time. Must be a Time object.
151
- def end=(e)
211
+ def end_time=(e)
152
212
  if not e.is_a?(Time)
153
213
  raise RecurrenceValueError, "End must be a date or a time"
154
214
  else
155
- @end = e
215
+ @end_time = e
156
216
  end
157
217
  end
158
218
 
@@ -1,155 +1,163 @@
1
- require 'gcal4ruby/base'
2
- require 'gcal4ruby/calendar'
3
-
4
- module GCal4Ruby
5
-
6
- #The service class is the main handler for all direct interactions with the
7
- #Google Calendar API. A service represents a single user account. Each user
8
- #account can have multiple calendars, so you'll need to find the calendar you
9
- #want from the service, using the Calendar#find class method.
10
- #=Usage
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
11
8
  #
12
- #1. Authenticate
13
- # service = Service.new
14
- # service.authenticate("user@gmail.com", "password")
9
+ # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
15
10
  #
16
- #2. Get Calendar List
17
- # calendars = service.calendars
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.
18
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
+ require 'gdata4ruby'
19
+ require 'gdata4ruby/gdata_object'
20
+ require 'gdata4ruby/utils/utils'
21
+ require 'gdata4ruby/acl/access_rule'
22
+ require 'gcal4ruby/calendar'
23
+ require 'gcal4ruby/event'
24
+ require 'gcal4ruby/recurrence'
25
+ require 'rexml/document'
19
26
 
20
- class Service < Base
21
- #Convenience attribute contains the currently authenticated account name
22
- attr_reader :account
23
-
24
- # The token returned by the Google servers, used to authorize all subsequent messages
25
- attr_reader :auth_token
26
-
27
- # Determines whether GCal4Ruby ensures a calendar is public. Setting this to false can increase speeds by
28
- # 50% but can cause errors if you try to do something to a calendar that is not public and you don't have
29
- # adequate permissions
30
- attr_accessor :check_public
31
-
32
- #Accepts an optional attributes hash for initialization values
33
- def initialize(attributes = {})
34
- super()
35
- attributes.each do |key, value|
36
- self.send("#{key}=", value)
37
- end
38
- @check_public ||= true
39
- end
40
-
41
- # The authenticate method passes the username and password to google servers.
42
- # If authentication succeeds, returns true, otherwise raises the AuthenticationFailed error.
43
- def authenticate(username, password)
44
- ret = nil
45
- ret = send_post(AUTH_URL, "Email=#{username}&Passwd=#{password}&source=GCal4Ruby&service=cl&accountType=HOSTED_OR_GOOGLE")
46
- if ret.class == Net::HTTPOK
47
- @auth_token = ret.read_body.to_a[2].gsub("Auth=", "").strip
48
- @account = username
49
- return true
50
- else
51
- raise AuthenticationFailed
27
+ module GCal4Ruby
28
+ #The service class is the main handler for all direct interactions with the
29
+ #Google Calendar API. A service represents a single user account. Each user
30
+ #account can have multiple calendars, so you'll need to find the calendar you
31
+ #want from the service, using the Calendar#find class method.
32
+ #=Usage
33
+ #
34
+ #1. Authenticate
35
+ # service = Service.new
36
+ # service.authenticate("user@gmail.com", "password")
37
+ #
38
+ #2. Get Calendar List
39
+ # calendars = service.calendars
40
+ #
41
+ class Service < GData4Ruby::Service
42
+ CALENDAR_LIST_FEED = 'http://www.google.com/calendar/feeds/default/allcalendars/full'
43
+
44
+ #Convenience attribute contains the currently authenticated account name
45
+ attr_reader :account
46
+
47
+ # The token returned by the Google servers, used to authorize all subsequent messages
48
+ attr_reader :auth_token
49
+
50
+ # Determines whether GCal4Ruby ensures a calendar is public. Setting this to false can increase speeds by
51
+ # 50% but can cause errors if you try to do something to a calendar that is not public and you don't have
52
+ # adequate permissions
53
+ attr_accessor :check_public
54
+
55
+ #Accepts an optional attributes hash for initialization values
56
+ def initialize(attributes = {})
57
+ super(attributes)
58
+ attributes.each do |key, value|
59
+ self.send("#{key}=", value)
60
+ end
61
+ @check_public ||= true
52
62
  end
53
- end
54
-
55
- #Returns an array of Calendar objects for each calendar associated with
56
- #the authenticated account.
57
- def calendars
58
- if not @auth_token
59
- raise NotAuthenticated
63
+
64
+ def default_event_feed
65
+ return "http://www.google.com/calendar/feeds/#{@account}/private/full"
60
66
  end
61
- ret = send_get(CALENDAR_LIST_FEED+"?max-results=10000")
62
- cals = []
63
- REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
64
- entry.attributes["xmlns:gCal"] = "http://schemas.google.com/gCal/2005"
65
- entry.attributes["xmlns:gd"] = "http://schemas.google.com/g/2005"
66
- entry.attributes["xmlns:app"] = "http://www.w3.org/2007/app"
67
- entry.attributes["xmlns"] = "http://www.w3.org/2005/Atom"
68
- cal = Calendar.new(self)
69
- cal.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
70
- cals << cal
67
+
68
+ # The authenticate method passes the username and password to google servers.
69
+ # If authentication succeeds, returns true, otherwise raises the AuthenticationFailed error.
70
+ def authenticate(username, password, service='cl')
71
+ super(username, password, service)
72
+ end
73
+
74
+ #Helper function to reauthenticate to a new Google service without having to re-set credentials.
75
+ def reauthenticate(service='cl')
76
+ authenticate(@account, @password, service)
71
77
  end
72
- return cals
73
- end
74
78
 
75
- #Helper function to return a formatted iframe embedded google calendar. Parameters are:
76
- #1. *cals*: either an array of calendar ids, or <em>:all</em> for all calendars, or <em>:first</em> for the first (usally default) calendar
77
- #2. *params*: a hash of parameters that affect the display of the embedded calendar:
78
- # height:: the height of the embedded calendar in pixels
79
- # width:: the width of the embedded calendar in pixels
80
- # title:: the title to display
81
- # bgcolor:: the background color. Limited choices, see google docs for allowable values.
82
- # color:: the color of the calendar elements. Limited choices, see google docs for allowable values.
83
- # showTitle:: set to 'false' to hide the title
84
- # showDate:: set to 'false' to hide the current date
85
- # showNav:: set to 'false to hide the navigation tools
86
- # showPrint:: set to 'false' to hide the print icon
87
- # showTabs:: set to 'false' to hide the tabs
88
- # showCalendars:: set to 'false' to hide the calendars selection drop down
89
- # showTimezone:: set to 'false' to hide the timezone selection
90
- # border:: the border width in pixels
91
- # dates:: a range of dates to display in the format of 'yyyymmdd/yyyymmdd'. Example: 20090820/20091001
92
- # privateKey:: use to display a private calendar. You can find this key under the calendar settings pane of the Google Calendar website.
93
- # colors:: a hash of calendar ids as key and color values as associated hash values. Example: {'test@gmail.com' => '#7A367A'}
94
- def to_iframe(cals, params = {})
95
- params[:height] ||= "600"
96
- params[:width] ||= "600"
97
- params[:title] ||= (self.account ? self.account : '')
98
- params[:bgcolor] ||= "#FFFFFF"
99
- params[:color] ||= "#2952A3"
100
- params[:showTitle] = params[:showTitle] == false ? "showTitle=0" : ''
101
- params[:showNav] = params[:showNav] == false ? "showNav=0" : ''
102
- params[:showDate] = params[:showDate] == false ? "showDate=0" : ''
103
- params[:showPrint] = params[:showPrint] == false ? "showPrint=0" : ''
104
- params[:showTabs] = params[:showTabs] == false ? "showTabs=0" : ''
105
- params[:showCalendars] = params[:showCalendars] == false ? "showCalendars=0" : ''
106
- params[:showTimezone] = params[:showTimezone] == false ? 'showTz=0' : ''
107
- params[:border] ||= "0"
108
- output = ''
109
- puts "params = #{params.inspect}" if self.debug
110
- params.each do |key, value|
111
- puts "key = #{key} and value = #{value}" if self.debug
112
- case key
113
- when :height then output += "height=#{value}"
114
- when :width then output += "width=#{value}"
115
- when :title then output += "title=#{CGI.escape(value)}"
116
- when :bgcolor then output += "bgcolor=#{CGI.escape(value)}"
117
- when :color then output += "color=#{CGI.escape(value)}"
118
- when :showTitle then output += value
119
- when :showDate then output += value
120
- when :showNav then output += value
121
- when :showPrint then output += value
122
- when :showTabs then output += value
123
- when :showCalendars then output += value
124
- when :showTimezone then output += value
125
- when :viewMode then output += "mode=#{value}"
126
- when :dates then output += "dates=#{CGI.escape(value)}"
127
- when :privateKey then output += "pvttk=#{value}"
79
+ #Returns an array of Calendar objects for each calendar associated with
80
+ #the authenticated account.
81
+ def calendars
82
+ if not @auth_token
83
+ raise NotAuthenticated
128
84
  end
129
- output += "&amp;"
85
+ ret = send_request(GData4Ruby::Request.new(:get, CALENDAR_LIST_FEED, nil, {"max-results" => "10000"}))
86
+ cals = []
87
+ REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
88
+ entry = GData4Ruby::Utils.add_namespaces(entry)
89
+ cal = Calendar.new(self)
90
+ cal.load(entry.to_s)
91
+ cals << cal
92
+ end
93
+ return cals
130
94
  end
131
95
 
132
- puts "output = #{output}" if self.debug
96
+ #Returns an array of Event objects for each event in this account
97
+ def events
98
+ if not @auth_token
99
+ raise NotAuthenticated
100
+ end
101
+ ret = send_request(GData4Ruby::Request.new(:get, default_event_feed, nil, {"max-results" => "10000"}))
102
+ events = []
103
+ REXML::Document.new(ret.body).root.elements.each("entry"){}.map do |entry|
104
+ entry = GData4Ruby::Utils.add_namespaces(entry)
105
+ event = Event.new(self)
106
+ event.load(entry.to_s)
107
+ events << event
108
+ end
109
+ return events
110
+ end
133
111
 
134
- if cals.is_a?(Array)
135
- for c in cals
136
- output += "src=#{c}&amp;"
137
- if params[:colors] and params[:colors][c]
138
- output += "color=#{CGI.escape(params[:colors][c])}&amp;"
112
+ #Helper function to return a formatted iframe embedded google calendar. Parameters are:
113
+ #1. *cals*: either an array of calendar ids, or <em>:all</em> for all calendars, or <em>:first</em> for the first (usally default) calendar
114
+ #2. *params*: a hash of parameters that affect the display of the embedded calendar. Accepts any parameter that the google iframe recognizes. Here are the most common:
115
+ # height:: the height of the embedded calendar in pixels
116
+ # width:: the width of the embedded calendar in pixels
117
+ # title:: the title to display
118
+ # bgcolor:: the background color. Limited choices, see google docs for allowable values.
119
+ # color:: the color of the calendar elements. Limited choices, see google docs for allowable values.
120
+ # showTitle:: set to '0' to hide the title
121
+ # showDate:: set to '0' to hide the current date
122
+ # showNav:: set to '0 to hide the navigation tools
123
+ # showPrint:: set to '0' to hide the print icon
124
+ # showTabs:: set to '0' to hide the tabs
125
+ # showCalendars:: set to '0' to hide the calendars selection drop down
126
+ # showTz:: set to '0' to hide the timezone selection
127
+ # border:: the border width in pixels
128
+ # dates:: a range of dates to display in the format of 'yyyymmdd/yyyymmdd'. Example: 20090820/20091001
129
+ # privateKey:: use to display a private calendar. You can find this key under the calendar settings pane of the Google Calendar website.
130
+ # ctz:: The timezone to convert event times to
131
+ #3. *colors*: a hash of calendar ids as key and color values as associated hash values. Example: {'test@gmail.com' => '#7A367A'}
132
+ def to_iframe(cals, params = {}, colors = {})
133
+ params[:height] ||= "600"
134
+ params[:width] ||= "600"
135
+ params[:title] ||= (self.account ? self.account : '')
136
+ params[:bgcolor] ||= "#FFFFFF"
137
+ params[:color] ||= "#2952A3"
138
+ params[:border] ||= "0"
139
+ puts "params = #{params.inspect}" if self.debug
140
+ output = "?#{params.to_a.collect{|a| a.join("=")}.join("&")}&"
141
+ puts "param_string = #{output}" if self.debug
142
+
143
+ if cals.is_a?(Array)
144
+ for c in cals
145
+ output += "src=#{c}&"
146
+ if colors and colors[c]
147
+ output += "color=#{colors[c]}&"
148
+ end
139
149
  end
150
+ elsif cals == :all
151
+ cal_list = calendars()
152
+ for c in cal_list
153
+ output += "src=#{c.id}&"
154
+ end
155
+ elsif cals == :first
156
+ cal_list = calendars()
157
+ output += "src=#{cal_list[0].id}&"
140
158
  end
141
- elsif cals == :all
142
- cal_list = calendars()
143
- for c in cal_list
144
- output += "src=#{c.id}&amp;"
145
- end
146
- elsif cals == :first
147
- cal_list = calendars()
148
- output += "src=#{cal_list[0].id}&amp;"
159
+
160
+ "<iframe src='http://www.google.com/calendar/embed?#{CGI::escape(output)}' style='#{params[:border]} px solid;' width='#{params[:width]}' height='#{params[:height]}' frameborder='#{params[:border]}' scrolling='no'></iframe>"
149
161
  end
150
-
151
- "<iframe src='http://www.google.com/calendar/embed?#{output}' style='#{params[:border]} px solid;' width='#{params[:width]}' height='#{params[:height]}' frameborder='#{params[:border]}' scrolling='no'></iframe>"
152
162
  end
153
- end
154
-
155
163
  end
data/test/unit.rb CHANGED
@@ -69,7 +69,7 @@ def calendar_test
69
69
  end
70
70
 
71
71
  puts "3. Find Calendar by ID"
72
- c = Calendar.find(@service, cal.id)
72
+ c = Calendar.find(@service, {:id => cal.id})
73
73
  if c.title == cal.title
74
74
  successful
75
75
  else
@@ -77,7 +77,7 @@ def calendar_test
77
77
  end
78
78
 
79
79
  puts "4. Delete Calendar"
80
- if cal.delete and not cal.title
80
+ if cal.delete and not cal.exists?
81
81
  successful
82
82
  else
83
83
  failed
@@ -88,11 +88,12 @@ def event_test
88
88
  puts "---Starting Event Test---"
89
89
 
90
90
  puts "1. Create Event"
91
- event = Event.new(@service.calendars[0])
91
+ event = Event.new(@service)
92
+ event.calendar = @service.calendars[0]
92
93
  event.title = "Test Event"
93
94
  event.content = "Test event content"
94
- event.start = Time.now+1800
95
- event.end = Time.now+5400
95
+ event.start_time = Time.now+1800
96
+ event.end_time = Time.now+5400
96
97
  if event.save
97
98
  successful event.to_xml
98
99
  else
@@ -113,7 +114,7 @@ def event_test
113
114
  end
114
115
 
115
116
  puts "4. Find Event by id"
116
- e = Event.find(@service.calendars[0], event.id)
117
+ e = Event.find(@service, {:id => event.id})
117
118
  if e.title == event.title
118
119
  successful
119
120
  else
@@ -139,10 +140,11 @@ def event_recurrence_test
139
140
  @second_freq = {'weekly' => ['SA']}
140
141
 
141
142
  puts "1. Create Recurring Event"
142
- event = Event.new(@service.calendars[0])
143
+ event = Event.new(@service)
144
+ event.calendar = @service.calendars[0]
143
145
  event.title = "Test Recurring Event"
144
146
  event.content = "Test event content"
145
- event.recurrence = Recurrence.new({:start => @first_start, :end => @first_end, :frequency => @first_freq})
147
+ event.recurrence = Recurrence.new({:start_time => @first_start, :end_time => @first_end, :frequency => @first_freq})
146
148
  if event.save
147
149
  successful event.to_xml
148
150
  else
@@ -151,7 +153,7 @@ def event_recurrence_test
151
153
 
152
154
  puts "2. Edit Recurrence"
153
155
  event.title = "Edited recurring title"
154
- event.recurrence = Recurrence.new({:start => @second_start, :end => @second_end, :frequency => @second_freq})
156
+ event.recurrence = Recurrence.new({:start_time => @second_start, :end_time => @second_end, :frequency => @second_freq})
155
157
  if event.save
156
158
  successful event.to_xml
157
159
  else