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