google_calendar 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -10
- data/.travis.yml +1 -1
- data/Gemfile +2 -12
- data/Gemfile.lock +81 -24
- data/Guardfile +7 -0
- data/README.rdoc +60 -8
- data/VERSION +1 -1
- data/google_calendar.gemspec +19 -29
- data/lib/google/calendar.rb +149 -118
- data/lib/google/connection.rb +114 -79
- data/lib/google/errors.rb +2 -1
- data/lib/google/event.rb +191 -94
- data/lib/google_calendar.rb +5 -5
- data/readme_code.rb +72 -0
- data/test/helper.rb +12 -5
- data/test/mocks/401.json +15 -0
- data/test/mocks/403.json +12 -0
- data/test/mocks/404.json +13 -0
- data/test/mocks/create_event.json +31 -0
- data/test/mocks/create_quickadd_event.json +30 -0
- data/test/mocks/empty_events.json +12 -0
- data/test/mocks/events.json +117 -0
- data/test/mocks/find_event_by_id.json +31 -0
- data/test/mocks/login_with_auth_code_fail.json +4 -0
- data/test/mocks/login_with_auth_code_success.json +6 -0
- data/test/mocks/login_with_refresh_token_success.json +5 -0
- data/test/mocks/query_events.json +44 -0
- data/test/mocks/repeating_events.json +48 -0
- data/test/mocks/successful_login.json +6 -0
- data/test/test_google_calendar.rb +167 -139
- metadata +167 -53
- data/lib/google/net/https.rb +0 -19
- data/test/mocks/create_event.xml +0 -31
- data/test/mocks/create_quickadd_event.xml +0 -31
- data/test/mocks/events.xml +0 -119
- data/test/mocks/find_event_by_id.xml +0 -33
- data/test/mocks/list_calendars.xml +0 -89
- data/test/mocks/query_events.xml +0 -55
- data/test/mocks/successful_login.txt +0 -3
data/lib/google/connection.rb
CHANGED
@@ -1,120 +1,155 @@
|
|
1
|
+
require 'signet/oauth_2/client'
|
1
2
|
require "addressable/uri"
|
2
|
-
require 'google/net/https'
|
3
3
|
|
4
4
|
module Google
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
6
|
+
#
|
7
|
+
# This is a utility class that communicates with the google calendar api.
|
8
8
|
#
|
9
9
|
class Connection
|
10
|
-
|
10
|
+
BASE_URI = "https://www.googleapis.com/calendar/v3"
|
11
|
+
|
12
|
+
attr_accessor :client
|
13
|
+
|
14
|
+
#
|
15
|
+
# Prepare a connection to google for fetching a calendar events
|
16
|
+
#
|
17
|
+
# the +params+ paramater accepts
|
18
|
+
# * :client_id => the client ID that you received from Google after registering your application with them (https://console.developers.google.com/)
|
19
|
+
# * :client_secret => the client secret you received from Google after registering your application with them.
|
20
|
+
# * :redirect_uri => the url where your users will be redirected to after they have successfully permitted access to their calendars. Use 'urn:ietf:wg:oauth:2.0:oob' if you are using an 'application'"
|
21
|
+
# * :refresh_token => if a user has already given you access to their calendars, you can specify their refresh token here and you will be 'logged on' automatically (i.e. they don't need to authorize access again)
|
11
22
|
#
|
12
23
|
def initialize(params)
|
13
|
-
@username = params[:username]
|
14
|
-
@password = params[:password]
|
15
|
-
@auth_url = params[:auth_url] || "https://www.google.com/accounts/ClientLogin"
|
16
|
-
@app_name = params[:app_name] || "northworld.com-googlecalendar-integration"
|
17
24
|
|
18
|
-
|
25
|
+
raise ArgumentError unless Connection.credentials_provided?(params)
|
26
|
+
|
27
|
+
@client = Signet::OAuth2::Client.new(
|
28
|
+
:client_id => params[:client_id],
|
29
|
+
:client_secret => params[:client_secret],
|
30
|
+
:redirect_uri => params[:redirect_url],
|
31
|
+
:refresh_token => params[:refresh_token],
|
32
|
+
:authorization_uri => 'https://accounts.google.com/o/oauth2/auth',
|
33
|
+
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
|
34
|
+
:scope => "https://www.googleapis.com/auth/calendar"
|
35
|
+
)
|
36
|
+
|
37
|
+
calendar_id = params[:calendar_id]
|
38
|
+
|
39
|
+
# raise CalenarIDMissing unless calendar_id
|
40
|
+
@events_url = "#{BASE_URI}/calendars/#{CGI::escape calendar_id}/events"
|
41
|
+
|
42
|
+
# try to get an access token if possible.
|
43
|
+
if params[:refresh_token]
|
44
|
+
@client.refresh_token = params[:refresh_token]
|
45
|
+
@client.grant_type = 'refresh_token'
|
46
|
+
Connection.get_new_access_token(@client)
|
47
|
+
end
|
48
|
+
|
19
49
|
end
|
20
50
|
|
21
|
-
# login to the google calendar and grab an auth token.
|
22
51
|
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
'accountType' => 'HOSTED_OR_GOOGLE',
|
29
|
-
'service' => 'cl'}
|
52
|
+
# The URL you need to send a user in order to let them grant you access to their calendars.
|
53
|
+
#
|
54
|
+
def authorize_url
|
55
|
+
@client.authorization_uri
|
56
|
+
end
|
30
57
|
|
31
|
-
|
58
|
+
#
|
59
|
+
# The single use auth code that google uses during the auth process.
|
60
|
+
#
|
61
|
+
def auth_code
|
62
|
+
@client.code
|
63
|
+
end
|
32
64
|
|
33
|
-
|
65
|
+
#
|
66
|
+
# The current access token. Used during a session, typically expires in a hour.
|
67
|
+
#
|
68
|
+
def access_token
|
69
|
+
@client.access_token
|
70
|
+
end
|
34
71
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@update_header = @headers.clone
|
41
|
-
@update_header["If-Match"] = "*"
|
72
|
+
#
|
73
|
+
# The refresh token is used to obtain a new access token. It remains valid until a user revokes access.
|
74
|
+
#
|
75
|
+
def refresh_token
|
76
|
+
@client.refresh_token
|
42
77
|
end
|
43
78
|
|
44
|
-
# send a request to google.
|
45
79
|
#
|
46
|
-
|
47
|
-
|
80
|
+
# Convenience method used to streamline the process of logging in with a auth code.
|
81
|
+
#
|
82
|
+
def login_with_auth_code(auth_code)
|
83
|
+
@client.code = auth_code
|
84
|
+
Connection.get_new_access_token(@client)
|
85
|
+
@client.refresh_token
|
86
|
+
end
|
48
87
|
|
49
|
-
|
88
|
+
#
|
89
|
+
# Convenience method used to streamline the process of logging in with a refresh token.
|
90
|
+
#
|
91
|
+
def login_with_refresh_token(refresh_token)
|
92
|
+
@client.refresh_token = refresh_token
|
93
|
+
@client.grant_type = 'refresh_token'
|
94
|
+
Connection.get_new_access_token(@client)
|
95
|
+
end
|
50
96
|
|
51
|
-
|
52
|
-
|
97
|
+
#
|
98
|
+
# Send a request to google.
|
99
|
+
#
|
100
|
+
def send(uri, method, content = '')
|
53
101
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
102
|
+
response = @client.fetch_protected_resource(
|
103
|
+
:uri => uri,
|
104
|
+
:method => method,
|
105
|
+
:body => content,
|
106
|
+
:headers => {'Content-type' => 'application/json'}
|
107
|
+
)
|
58
108
|
|
59
109
|
check_for_errors(response)
|
60
110
|
|
61
111
|
return response
|
62
112
|
end
|
63
113
|
|
64
|
-
|
114
|
+
#
|
115
|
+
# Wraps the `send` method. Send an event related request to Google.
|
116
|
+
#
|
117
|
+
def send_events_request(path_and_query_string, method, content = '')
|
118
|
+
send(Addressable::URI.parse(@events_url + path_and_query_string), method, content)
|
119
|
+
end
|
65
120
|
|
66
|
-
|
67
|
-
#
|
68
|
-
def set_session_if_necessary(uri) #:nodoc:
|
69
|
-
# only extract the session if we don't already have one.
|
70
|
-
@session_id = uri.query_values['gsessionid'] if @session_id == nil && uri.query
|
121
|
+
protected
|
71
122
|
|
72
|
-
|
73
|
-
|
74
|
-
|
123
|
+
#
|
124
|
+
# Utility method to centralize the process of getting an access token.
|
125
|
+
#
|
126
|
+
def self.get_new_access_token(client) #:nodoc:
|
127
|
+
begin
|
128
|
+
client.fetch_access_token!
|
129
|
+
rescue Signet::AuthorizationError
|
130
|
+
raise HTTPAuthorizationFailed
|
75
131
|
end
|
76
132
|
end
|
77
133
|
|
78
|
-
# Construct the appropriate request object.
|
79
134
|
#
|
80
|
-
def build_request(uri, method, content) #:nodoc
|
81
|
-
case method
|
82
|
-
when :delete
|
83
|
-
request = Net::HTTP::Delete.new(uri.to_s, @update_header)
|
84
|
-
|
85
|
-
when :get
|
86
|
-
request = Net::HTTP::Get.new(uri.to_s, @headers)
|
87
|
-
|
88
|
-
when :post_form
|
89
|
-
request = Net::HTTP::Post.new(uri.to_s, @headers)
|
90
|
-
request.set_form_data(content)
|
91
|
-
|
92
|
-
when :post
|
93
|
-
request = Net::HTTP::Post.new(uri.to_s, @headers)
|
94
|
-
request.body = content
|
95
|
-
|
96
|
-
when :put
|
97
|
-
request = Net::HTTP::Put.new(uri.to_s, @update_header)
|
98
|
-
request.body = content
|
99
|
-
end # case
|
100
|
-
|
101
|
-
return request
|
102
|
-
end
|
103
|
-
|
104
135
|
# Check for common HTTP Errors and raise the appropriate response.
|
105
136
|
#
|
106
137
|
def check_for_errors(response) #:nodoc
|
107
|
-
|
108
|
-
raise
|
138
|
+
case response.status
|
139
|
+
when 400 then raise HTTPRequestFailed, response.body
|
140
|
+
when 404 then raise HTTPNotFound, response.body
|
141
|
+
end
|
142
|
+
end
|
109
143
|
|
110
|
-
|
111
|
-
raise HTTPRequestFailed, response.body
|
144
|
+
private
|
112
145
|
|
113
|
-
|
114
|
-
|
115
|
-
|
146
|
+
#
|
147
|
+
#
|
148
|
+
#
|
149
|
+
def self.credentials_provided?(params) #:nodoc:
|
150
|
+
blank = /[^[:space:]]/
|
151
|
+
!(params[:client_id] !~ blank) && !(params[:client_secret] !~ blank)
|
116
152
|
end
|
117
153
|
|
118
154
|
end
|
119
|
-
|
120
|
-
end
|
155
|
+
end
|
data/lib/google/errors.rb
CHANGED
data/lib/google/event.rb
CHANGED
@@ -1,60 +1,69 @@
|
|
1
|
-
require 'nokogiri'
|
2
1
|
require 'time'
|
3
2
|
|
4
3
|
module Google
|
5
4
|
|
5
|
+
#
|
6
6
|
# Represents a Google Event.
|
7
7
|
#
|
8
8
|
# === Attributes
|
9
9
|
#
|
10
|
-
# * +id+ - The google assigned id of the event (nil until saved)
|
11
|
-
# * +title+ - The title of the event
|
12
|
-
# * +
|
13
|
-
# * +
|
14
|
-
# * +
|
15
|
-
# * +
|
16
|
-
# * +
|
17
|
-
# * +
|
18
|
-
# * +
|
19
|
-
# * +
|
10
|
+
# * +id+ - The google assigned id of the event (nil until saved). Read only.
|
11
|
+
# * +title+ - The title of the event. Read Write.
|
12
|
+
# * +description+ - The content of the event. Read Write.
|
13
|
+
# * +location+ - The location of the event. Read Write.
|
14
|
+
# * +start_time+ - The start time of the event (Time object, defaults to now). Read Write.
|
15
|
+
# * +end_time+ - The end time of the event (Time object, defaults to one hour from now). Read Write.
|
16
|
+
# * +calendar+ - What calendar the event belongs to. Read Write.
|
17
|
+
# * +all_day + - Does the event run all day. Read Write.
|
18
|
+
# * +quickadd+ - A string that Google parses when setting up a new event. If set and then saved it will take priority over any attributes you have set. Read Write.
|
19
|
+
# * +reminders+ - A hash containing reminders. Read Write.
|
20
|
+
# * +attendees+ - An array of hashes containing information about attendees. Read Write
|
21
|
+
# * +transparency+ - Does the event 'block out space' on the calendar. Valid values are true, false or 'transparent', 'opaque'. Read Write.
|
22
|
+
# * +duration+ - The duration of the event in seconds. Read only.
|
23
|
+
# * +html_link+ - An absolute link to this event in the Google Calendar Web UI. Read only.
|
24
|
+
# * +raw+ - The full google json representation of the event. Read only.
|
20
25
|
#
|
21
26
|
class Event
|
22
|
-
attr_reader :id, :
|
23
|
-
attr_accessor :title, :
|
27
|
+
attr_reader :id, :raw, :html_link
|
28
|
+
attr_accessor :title, :location, :calendar, :quickadd, :transparency, :attendees, :description, :reminders
|
24
29
|
|
30
|
+
#
|
25
31
|
# Create a new event, and optionally set it's attributes.
|
26
32
|
#
|
27
33
|
# ==== Example
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
+
#
|
35
|
+
# event = Google::Event.new
|
36
|
+
# event.calendar = AnInstanceOfGoogleCalendaer
|
37
|
+
# event.start_time = Time.now
|
38
|
+
# event.end_time = Time.now + (60 * 60)
|
39
|
+
# event.title = "Go Swimming"
|
40
|
+
# event.description = "The polar bear plunge"
|
41
|
+
# event.location = "In the arctic ocean"
|
42
|
+
# event.transparency = "opaque"
|
43
|
+
# event.reminders = { 'useDefault' => false, 'overrides' => ['minutes' => 10, 'method' => "popup"]}
|
44
|
+
# event.attendees = [
|
45
|
+
# {'email' => 'some.a.one@gmail.com', 'displayName' => 'Some A One', 'responseStatus' => 'tentative'},
|
46
|
+
# {'email' => 'some.b.one@gmail.com', 'displayName' => 'Some B One', 'responseStatus' => 'tentative'}
|
47
|
+
# ]
|
34
48
|
#
|
35
49
|
def initialize(params = {})
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@updated_time = params[:updated]
|
48
|
-
@transparency = params[:transparency]
|
49
|
-
@published_time = params[:published]
|
50
|
-
end
|
51
|
-
|
52
|
-
# Sets the start time of the Event. Must be a Time object or a parsable string representation of a time.
|
50
|
+
[:id, :raw, :html_link,
|
51
|
+
:title, :location, :calendar, :quickadd, :attendees, :description, :reminders, :start_time, :end_time, ].each do |attribute|
|
52
|
+
instance_variable_set("@#{attribute}", params[attribute])
|
53
|
+
end
|
54
|
+
|
55
|
+
self.transparency = params[:transparency]
|
56
|
+
self.all_day = params[:all_day] if params[:all_day]
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Sets the start time of the Event. Must be a Time object or a parse-able string representation of a time.
|
53
61
|
#
|
54
62
|
def start_time=(time)
|
55
63
|
@start_time = parse_time(time)
|
56
64
|
end
|
57
65
|
|
66
|
+
#
|
58
67
|
# Get the start_time of the event.
|
59
68
|
#
|
60
69
|
# If no time is set (i.e. new event) it defaults to the current time.
|
@@ -64,6 +73,7 @@ module Google
|
|
64
73
|
(@start_time.is_a? String) ? @start_time : @start_time.xmlschema
|
65
74
|
end
|
66
75
|
|
76
|
+
#
|
67
77
|
# Get the end_time of the event.
|
68
78
|
#
|
69
79
|
# If no time is set (i.e. new event) it defaults to one hour in the future.
|
@@ -73,7 +83,8 @@ module Google
|
|
73
83
|
(@end_time.is_a? String) ? @end_time : @end_time.xmlschema
|
74
84
|
end
|
75
85
|
|
76
|
-
#
|
86
|
+
#
|
87
|
+
# Sets the end time of the Event. Must be a Time object or a parse-able string representation of a time.
|
77
88
|
#
|
78
89
|
def end_time=(time)
|
79
90
|
@end_time = parse_time(time)
|
@@ -81,13 +92,18 @@ module Google
|
|
81
92
|
@end_time = (time.is_a? String) ? Time.parse(time) : time.dup.utc
|
82
93
|
end
|
83
94
|
|
95
|
+
#
|
84
96
|
# Returns whether the Event is an all-day event, based on whether the event starts at the beginning and ends at the end of the day.
|
85
97
|
#
|
86
98
|
def all_day?
|
87
|
-
time = Time.parse(@start_time)
|
99
|
+
time = (@start_time.is_a? String) ? Time.parse(@start_time) : @start_time.dup.utc
|
88
100
|
duration % (24 * 60 * 60) == 0 && time == Time.local(time.year,time.month,time.day)
|
89
101
|
end
|
90
102
|
|
103
|
+
#
|
104
|
+
# Makes an event all day, by setting it's start time to the passed in time and it's end time 24 hours later.
|
105
|
+
# Note: this will clobber both the start and end times currently set.
|
106
|
+
#
|
91
107
|
def all_day=(time)
|
92
108
|
if time.class == String
|
93
109
|
time = Time.parse(time)
|
@@ -96,61 +112,138 @@ module Google
|
|
96
112
|
@end_time = (time + 24*60*60).strftime("%Y-%m-%d")
|
97
113
|
end
|
98
114
|
|
99
|
-
#
|
115
|
+
#
|
116
|
+
# Duration of the event in seconds
|
117
|
+
#
|
100
118
|
def duration
|
101
119
|
Time.parse(end_time) - Time.parse(start_time)
|
102
120
|
end
|
103
121
|
|
122
|
+
#
|
123
|
+
# Stores reminders for this event. Multiple reminders are allowed.
|
124
|
+
#
|
125
|
+
# Examples
|
126
|
+
#
|
127
|
+
# event = cal.create_event do |e|
|
128
|
+
# e.title = 'Some Event'
|
129
|
+
# e.start_time = Time.now + (60 * 10)
|
130
|
+
# e.end_time = Time.now + (60 * 60) # seconds * min
|
131
|
+
# e.reminders = { 'useDefault' => false, 'overrides' => [{method: 'email', minutes: 4}, {method: 'popup', minutes: 60}, {method: 'sms', minutes: 30}]}
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# event = Event.new :start_time => "2012-03-31", :end_time => "2012-04-03", :reminders => { 'useDefault' => false, 'overrides' => [{'minutes' => 10, 'method' => "popup"}]}
|
135
|
+
#
|
136
|
+
def reminders
|
137
|
+
@reminders ||= {}
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Utility method that simplifies setting the transparency of an event.
|
142
|
+
# You can pass true or false. Defaults to transparent.
|
143
|
+
#
|
144
|
+
def transparency=(val)
|
145
|
+
if val == false || val.to_s.downcase == 'opaque'
|
146
|
+
@transparency = 'opaque'
|
147
|
+
else
|
148
|
+
@transparency = 'transparent'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Returns true if the event is transparent otherwise returns false.
|
154
|
+
# Transparent events do not block time on a calendar.
|
155
|
+
#
|
104
156
|
def transparent?
|
105
|
-
transparency == "transparent"
|
157
|
+
@transparency == "transparent"
|
106
158
|
end
|
107
159
|
|
160
|
+
#
|
161
|
+
# Returns true if the event is opaque otherwise returns false.
|
162
|
+
# Opaque events block time on a calendar.
|
163
|
+
#
|
108
164
|
def opaque?
|
109
|
-
transparency == "opaque"
|
165
|
+
@transparency == "opaque"
|
166
|
+
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Convenience method used to build an array of events from a Google feed.
|
170
|
+
#
|
171
|
+
def self.build_from_google_feed(response, calendar)
|
172
|
+
events = response['items'] ? response['items'] : [response]
|
173
|
+
events.collect {|e| new_from_feed(e, calendar)}.flatten
|
110
174
|
end
|
111
175
|
|
112
176
|
#
|
113
|
-
|
114
|
-
|
177
|
+
# Google JSON representation of an event object.
|
178
|
+
#
|
179
|
+
def to_json
|
180
|
+
"{
|
181
|
+
\"summary\": \"#{title}\",
|
182
|
+
\"description\": \"#{description}\",
|
183
|
+
\"location\": \"#{location}\",
|
184
|
+
\"start\": {
|
185
|
+
\"dateTime\": \"#{start_time}\"
|
186
|
+
},
|
187
|
+
\"end\": {
|
188
|
+
\"dateTime\": \"#{end_time}\"
|
189
|
+
},
|
190
|
+
#{attendees_json}
|
191
|
+
\"reminders\": {
|
192
|
+
#{reminders_json}
|
193
|
+
}
|
194
|
+
}"
|
115
195
|
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# JSON representation of attendees
|
199
|
+
#
|
200
|
+
def attendees_json
|
201
|
+
return unless @attendees
|
116
202
|
|
117
|
-
|
203
|
+
attendees = @attendees.map do |attendee|
|
204
|
+
"{
|
205
|
+
\"displayName\": \"#{attendee['displayName']}\",
|
206
|
+
\"email\": \"#{attendee['email']}\",
|
207
|
+
\"responseStatus\": \"#{attendee['responseStatus']}\"
|
208
|
+
}"
|
209
|
+
end.join(",\n")
|
210
|
+
|
211
|
+
"\"attendees\": [\n#{attendees}],"
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# JSON representation of a reminder
|
118
216
|
#
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
<gd:when startTime=\"#{start_time}\" endTime=\"#{end_time}\"></gd:when>
|
129
|
-
</entry>"
|
217
|
+
def reminders_json
|
218
|
+
if reminders && reminders.is_a?(Hash) && reminders['overrides']
|
219
|
+
overrides = reminders['overrides'].map do |reminder|
|
220
|
+
"{
|
221
|
+
\"method\": \"#{reminder['method']}\",
|
222
|
+
\"minutes\": #{reminder['minutes']}
|
223
|
+
}"
|
224
|
+
end.join(",\n")
|
225
|
+
"\n\"useDefault\": false,\n\"overrides\": [\n#{overrides}]"
|
130
226
|
else
|
131
|
-
|
132
|
-
<content type="html">#{content}</content>
|
133
|
-
<gCal:quickadd value="true"/>
|
134
|
-
</entry>}
|
227
|
+
"\"useDefault\": true"
|
135
228
|
end
|
136
229
|
end
|
137
230
|
|
231
|
+
#
|
138
232
|
# String representation of an event object.
|
139
233
|
#
|
140
234
|
def to_s
|
141
|
-
|
142
|
-
s << "\n\t#{quickadd}" if quickadd
|
143
|
-
s
|
235
|
+
"Event Id '#{self.id}'\n\tTitle: #{title}\n\tStarts: #{start_time}\n\tEnds: #{end_time}\n\tLocation: #{location}\n\tDescription: #{description}\n\n"
|
144
236
|
end
|
145
237
|
|
238
|
+
#
|
146
239
|
# Saves an event.
|
147
|
-
# Note:
|
148
|
-
# make sure to set the calendar before calling this method.
|
240
|
+
# Note: make sure to set the calendar before calling this method.
|
149
241
|
#
|
150
242
|
def save
|
151
243
|
update_after_save(@calendar.save_event(self))
|
152
244
|
end
|
153
245
|
|
246
|
+
#
|
154
247
|
# Deletes an event.
|
155
248
|
# Note: If using this on an event you created without using a calendar object,
|
156
249
|
# make sure to set the calendar before calling this method.
|
@@ -160,49 +253,53 @@ module Google
|
|
160
253
|
@id = nil
|
161
254
|
end
|
162
255
|
|
163
|
-
protected
|
164
|
-
|
165
|
-
# Create a new event from a google 'entry' xml block.
|
166
256
|
#
|
167
|
-
|
168
|
-
|
257
|
+
# Returns true if the event will use quickadd when it is saved.
|
258
|
+
#
|
259
|
+
def use_quickadd?
|
260
|
+
quickadd && id == nil
|
261
|
+
end
|
169
262
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
end
|
263
|
+
#
|
264
|
+
# Returns true if this a new event.
|
265
|
+
#
|
266
|
+
def new_event?
|
267
|
+
id == nil || id == ''
|
268
|
+
end
|
177
269
|
|
178
|
-
|
270
|
+
protected
|
179
271
|
|
180
|
-
|
272
|
+
#
|
273
|
+
# Create a new event from a google 'entry'
|
274
|
+
#
|
275
|
+
def self.new_from_feed(e, calendar) #:nodoc:
|
276
|
+
Event.new(:id => e['id'],
|
181
277
|
:calendar => calendar,
|
182
|
-
:
|
183
|
-
:title =>
|
184
|
-
:
|
185
|
-
:
|
186
|
-
:start_time => (
|
187
|
-
:end_time => (
|
188
|
-
:transparency =>
|
189
|
-
:
|
190
|
-
:
|
191
|
-
:
|
192
|
-
:
|
278
|
+
:raw => e,
|
279
|
+
:title => e['summary'],
|
280
|
+
:description => e['description'],
|
281
|
+
:location => e['location'],
|
282
|
+
:start_time => (e['start'] ? e['start']['dateTime'] : ''),
|
283
|
+
:end_time => (e['end'] ? e['end']['dateTime'] : ''),
|
284
|
+
:transparency => e['transparency'],
|
285
|
+
:html_link => e['htmlLink'],
|
286
|
+
:updated => e['updated'],
|
287
|
+
:reminders => e['reminders'],
|
288
|
+
:attendees => e['attendees'] )
|
289
|
+
|
193
290
|
end
|
194
291
|
|
292
|
+
#
|
195
293
|
# Set the ID after google assigns it (only necessary when we are creating a new event)
|
196
294
|
#
|
197
295
|
def update_after_save(respose) #:nodoc:
|
198
296
|
return if @id && @id != ''
|
199
|
-
|
200
|
-
|
201
|
-
@
|
202
|
-
@html_link = xml.at_xpath('//xmlns:link[@title="alternate" and @rel="alternate" and @type="text/html"]')['href']
|
203
|
-
@raw_xml = xml
|
297
|
+
@raw = JSON.parse(respose.body)
|
298
|
+
@id = @raw['id']
|
299
|
+
@html_link = @raw['htmlLink']
|
204
300
|
end
|
205
301
|
|
302
|
+
#
|
206
303
|
# A utility method used centralize time parsing.
|
207
304
|
#
|
208
305
|
def parse_time(time) #:nodoc
|