amr_google_calendar 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +54 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/google_calendar.gemspec +84 -0
- data/lib/google/calendar.rb +223 -0
- data/lib/google/connection.rb +109 -0
- data/lib/google/errors.rb +7 -0
- data/lib/google/event.rb +182 -0
- data/lib/google/net/https.rb +19 -0
- data/lib/google_calendar.rb +6 -0
- data/test/helper.rb +21 -0
- data/test/mocks/create_event.xml +31 -0
- data/test/mocks/create_quickadd_event.xml +31 -0
- data/test/mocks/events.xml +119 -0
- data/test/mocks/find_event_by_id.xml +33 -0
- data/test/mocks/list_calendars.xml +89 -0
- data/test/mocks/query_events.xml +55 -0
- data/test/mocks/successful_login.txt +3 -0
- data/test/test_google_calendar.rb +268 -0
- metadata +194 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
require "addressable/uri"
|
2
|
+
require 'google/net/https'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
|
6
|
+
# This is a utility class that performs all of the
|
7
|
+
# communication with the google calendar api.
|
8
|
+
#
|
9
|
+
class Connection
|
10
|
+
# set the username, password, auth_url, app_name, and login.
|
11
|
+
#
|
12
|
+
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
|
+
|
18
|
+
login()
|
19
|
+
end
|
20
|
+
|
21
|
+
# login to the google calendar and grab an auth token.
|
22
|
+
#
|
23
|
+
def login()
|
24
|
+
content = {
|
25
|
+
'Email' => @username,
|
26
|
+
'Passwd' => @password,
|
27
|
+
'source' => @app_name,
|
28
|
+
'accountType' => 'HOSTED_OR_GOOGLE',
|
29
|
+
'service' => 'cl'}
|
30
|
+
|
31
|
+
response = send(Addressable::URI.parse(@auth_url), :post_form, content)
|
32
|
+
|
33
|
+
raise HTTPRequestFailed unless response.kind_of? Net::HTTPSuccess
|
34
|
+
|
35
|
+
@token = response.body.split('=').last
|
36
|
+
@headers = {
|
37
|
+
'Authorization' => "GoogleLogin auth=#{@token}",
|
38
|
+
'Content-Type' => 'application/atom+xml'
|
39
|
+
}
|
40
|
+
@update_header = @headers.clone
|
41
|
+
@update_header["If-Match"] = "*"
|
42
|
+
end
|
43
|
+
|
44
|
+
# send a request to google.
|
45
|
+
#
|
46
|
+
def send(uri, method, content = '', redirect_count = 10)
|
47
|
+
raise HTTPTooManyRedirections if redirect_count == 0
|
48
|
+
|
49
|
+
set_session_if_necessary(uri)
|
50
|
+
|
51
|
+
http = (uri.scheme == 'https' ? Net::HTTPS.new(uri.host, uri.inferred_port) : Net::HTTP.new(uri.host, uri.inferred_port))
|
52
|
+
|
53
|
+
case method
|
54
|
+
when :delete
|
55
|
+
# puts "in delete: #{uri.to_s}"
|
56
|
+
request = Net::HTTP::Delete.new(uri.to_s, @update_header)
|
57
|
+
when :get
|
58
|
+
# puts "in get: #{uri.to_s}"
|
59
|
+
request = Net::HTTP::Get.new(uri.to_s, @headers)
|
60
|
+
when :post_form
|
61
|
+
# puts "in post_form: #{uri.to_s}"
|
62
|
+
request = Net::HTTP::Post.new(uri.to_s, @headers)
|
63
|
+
request.set_form_data(content)
|
64
|
+
when :post
|
65
|
+
# puts "in post: #{uri.to_s}\n#{content}"
|
66
|
+
request = Net::HTTP::Post.new(uri.to_s, @headers)
|
67
|
+
request.body = content
|
68
|
+
when :put
|
69
|
+
# puts "in put: #{uri.to_s}\n#{content}"
|
70
|
+
request = Net::HTTP::Put.new(uri.to_s, @update_header)
|
71
|
+
request.body = content
|
72
|
+
end
|
73
|
+
|
74
|
+
response = http.request(request)
|
75
|
+
|
76
|
+
# recurse if necessary.
|
77
|
+
if response.kind_of? Net::HTTPRedirection
|
78
|
+
response = send(Addressable::URI.parse(response['location']), method, content, redirect_count - 1)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Raise the appropiate error if necessary.
|
82
|
+
if response.kind_of? Net::HTTPForbidden
|
83
|
+
raise HTTPAuthorizationFailed, response.body
|
84
|
+
|
85
|
+
elsif response.kind_of? Net::HTTPBadRequest
|
86
|
+
raise HTTPRequestFailed, response.body
|
87
|
+
|
88
|
+
elsif response.kind_of? Net::HTTPNotFound
|
89
|
+
raise HTTPNotFound, response.body
|
90
|
+
end
|
91
|
+
|
92
|
+
return response
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
def set_session_if_necessary(uri) #:nodoc:
|
98
|
+
# only extract the session if we don't already have one.
|
99
|
+
@session_id = uri.query_values['gsessionid'] if @session_id == nil && uri.query
|
100
|
+
|
101
|
+
if @session_id
|
102
|
+
uri.query ||= ''
|
103
|
+
uri.query_values = uri.query_values.merge({'gsessionid' => @session_id})
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/lib/google/event.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
|
6
|
+
# Represents a google Event.
|
7
|
+
#
|
8
|
+
# === Attributes
|
9
|
+
#
|
10
|
+
# * +id+ - The google assigned id of the event (nil until saved), read only.
|
11
|
+
# * +title+ - The title of the event, read/write.
|
12
|
+
# * +content+ - The content of the event, read/write.
|
13
|
+
# * +start_time+ - The start time of the event (Time object, defaults to now), read/write.
|
14
|
+
# * +end_time+ - The end time of the event (Time object, defaults to one hour from now), read/write.
|
15
|
+
# * +calendar+ - What calendar the event belongs to, read/write.
|
16
|
+
# * +raw_xml+ - The full google xml representation of the event.
|
17
|
+
#
|
18
|
+
class Event
|
19
|
+
attr_reader :id, :raw_xml
|
20
|
+
attr_accessor :title, :content, :where, :calendar, :quickadd
|
21
|
+
|
22
|
+
# Create a new event, and optionally set it's attributes.
|
23
|
+
#
|
24
|
+
# ==== Example
|
25
|
+
# Event.new(:title => 'Swimming',
|
26
|
+
# :content => 'Do not forget a towel this time',
|
27
|
+
# :where => 'The Ocean',
|
28
|
+
# :start_time => Time.now,
|
29
|
+
# :end_time => Time.now + (60 * 60),
|
30
|
+
# :calendar => calendar_object)
|
31
|
+
#
|
32
|
+
def initialize(params = {})
|
33
|
+
@id = params[:id]
|
34
|
+
@title = params[:title]
|
35
|
+
@content = params[:content]
|
36
|
+
@where = params[:where]
|
37
|
+
@start_time = params[:start_time]
|
38
|
+
@end_time = params[:end_time]
|
39
|
+
self.all_day= params[:all_day] if params[:all_day]
|
40
|
+
@calendar = params[:calendar]
|
41
|
+
@raw_xml = params[:raw_xml]
|
42
|
+
@quickadd = params[:quickadd]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets the start time of the Event. Must be a Time object or a parsable string representation of a time.
|
46
|
+
#
|
47
|
+
def start_time=(time)
|
48
|
+
raise ArgumentError, "Start Time must be either Time or String" unless (time.is_a?(String) || time.is_a?(Time))
|
49
|
+
@start_time = (time.is_a? String) ? Time.parse(time) : time
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get the start_time of the event.
|
53
|
+
#
|
54
|
+
# If no time is set (i.e. new event) it defaults to the current time.
|
55
|
+
#
|
56
|
+
def start_time
|
57
|
+
@start_time ||= Time.now
|
58
|
+
(@start_time.is_a? String) ? @start_time : @start_time.utc.xmlschema
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get the end_time of the event.
|
62
|
+
#
|
63
|
+
# If no time is set (i.e. new event) it defaults to one hour in the future.
|
64
|
+
#
|
65
|
+
def end_time
|
66
|
+
@end_time ||= Time.now + (60 * 60) # seconds * min
|
67
|
+
(@end_time.is_a? String) ? @end_time : @end_time.utc.xmlschema
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sets the end time of the Event. Must be a Time object or a parsable string representation of a time.
|
71
|
+
#
|
72
|
+
def end_time=(time)
|
73
|
+
raise ArgumentError, "End Time must be either Time or String" unless (time.is_a?(String) || time.is_a?(Time))
|
74
|
+
@end_time = ((time.is_a? String) ? Time.parse(time) : time)
|
75
|
+
end
|
76
|
+
|
77
|
+
# 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.
|
78
|
+
#
|
79
|
+
def all_day?
|
80
|
+
duration == 24 * 60 * 60 # Exactly one day
|
81
|
+
end
|
82
|
+
|
83
|
+
def all_day=(time)
|
84
|
+
if time.class == String
|
85
|
+
time = Time.parse(time)
|
86
|
+
end
|
87
|
+
@start_time = time.strftime("%Y-%m-%d")
|
88
|
+
@end_time = (time + 24*60*60).strftime("%Y-%m-%d")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Duration in seconds
|
92
|
+
def duration
|
93
|
+
Time.parse(end_time) - Time.parse(start_time)
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
def self.build_from_google_feed(xml, calendar)
|
98
|
+
Nokogiri::XML(xml).xpath("//xmlns:entry").collect {|e| new_from_xml(e, calendar)}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Google XMl representation of an evetn object.
|
102
|
+
#
|
103
|
+
def to_xml
|
104
|
+
unless quickadd
|
105
|
+
"<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
106
|
+
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category>
|
107
|
+
<title type='text'>#{title}</title>
|
108
|
+
<content type='text'>#{content}</content>
|
109
|
+
<gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency>
|
110
|
+
<gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus>
|
111
|
+
<gd:where valueString=\"#{where}\"></gd:where>
|
112
|
+
<gd:when startTime=\"#{start_time}\" endTime=\"#{end_time}\"></gd:when>
|
113
|
+
</entry>"
|
114
|
+
else
|
115
|
+
%Q{<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gCal='http://schemas.google.com/gCal/2005'>
|
116
|
+
<content type="html">#{content}</content>
|
117
|
+
<gCal:quickadd value="true"/>
|
118
|
+
</entry>}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# String representation of an event object.
|
123
|
+
#
|
124
|
+
def to_s
|
125
|
+
s = "#{title} (#{self.id})\n\t#{start_time}\n\t#{end_time}\n\t#{where}\n\t#{content}"
|
126
|
+
s << "\n\t#{quickadd}" if quickadd
|
127
|
+
s
|
128
|
+
end
|
129
|
+
|
130
|
+
# Saves an event.
|
131
|
+
# Note: If using this on an event you created without using a calendar object,
|
132
|
+
# make sure to set the calendar before calling this method.
|
133
|
+
#
|
134
|
+
def save
|
135
|
+
update_after_save(@calendar.save_event(self))
|
136
|
+
end
|
137
|
+
|
138
|
+
# Deletes an event.
|
139
|
+
# Note: If using this on an event you created without using a calendar object,
|
140
|
+
# make sure to set the calendar before calling this method.
|
141
|
+
#
|
142
|
+
def delete
|
143
|
+
@calendar.delete_event(self)
|
144
|
+
@id = nil
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
# Create a new event from a google 'entry' xml block.
|
150
|
+
#
|
151
|
+
def self.new_from_xml(xml, calendar) #:nodoc:
|
152
|
+
id = xml.at_xpath("gCal:uid")['value'].split('@').first
|
153
|
+
title = xml.at_xpath("xmlns:title").content
|
154
|
+
content = xml.at_xpath("xmlns:content").content
|
155
|
+
where = xml.at_xpath("gd:where")['valueString']
|
156
|
+
start_time = xml.at_xpath("gd:when")['startTime']
|
157
|
+
end_time = xml.at_xpath("gd:when")['endTime']
|
158
|
+
quickadd = xml.at_xpath("gCal:quickadd") ? xml.at_xpath("gCal:quickadd")['quickadd'] : nil
|
159
|
+
|
160
|
+
Event.new(:id => id,
|
161
|
+
:title => title,
|
162
|
+
:content => content,
|
163
|
+
:where => where,
|
164
|
+
:start_time => start_time,
|
165
|
+
:end_time => end_time,
|
166
|
+
:calendar => calendar,
|
167
|
+
:raw_xml => xml,
|
168
|
+
:quickadd => quickadd)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Set the ID after google assigns it (only necessary when we are creating a new event)
|
172
|
+
#
|
173
|
+
def update_after_save(respose) #:nodoc:
|
174
|
+
return if @id && @id != ''
|
175
|
+
|
176
|
+
xml = Nokogiri::XML(respose.body).at_xpath("//xmlns:entry")
|
177
|
+
@id = xml.at_xpath("gCal:uid")['value'].split('@').first
|
178
|
+
@raw_xml = xml
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "net/https"
|
3
|
+
|
4
|
+
module Net
|
5
|
+
|
6
|
+
# Helper Method for using SSL
|
7
|
+
#
|
8
|
+
class HTTPS < HTTP
|
9
|
+
|
10
|
+
# Setup a secure connection with defaults
|
11
|
+
#
|
12
|
+
def initialize(address, port = nil)
|
13
|
+
super(address, port)
|
14
|
+
self.use_ssl = true
|
15
|
+
self.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
require 'mocha'
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
16
|
+
require 'google_calendar'
|
17
|
+
require 'google/net/https'
|
18
|
+
|
19
|
+
class Test::Unit::TestCase
|
20
|
+
@@mock_path = File.expand_path(File.join(File.dirname(__FILE__), 'mocks'))
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gCal="http://schemas.google.com/gCal/2005" xmlns:gd="http://schemas.google.com/g/2005">
|
3
|
+
<id>http://www.google.com/calendar/feeds/default/private/full/b1vq6rj4r4mg85kcickc7iomb0</id>
|
4
|
+
<published>2010-12-13T07:34:25.000Z</published>
|
5
|
+
<updated>2010-12-13T07:34:25.000Z</updated>
|
6
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
|
7
|
+
<title type="text">New Event</title>
|
8
|
+
<content type="text">A new event</content>
|
9
|
+
<link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=YjF2cTZyajRyNG1nODVrY2lja2M3aW9tYjAgc3RldmUuemljaEBt" title="alternate"/>
|
10
|
+
<link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/b1vq6rj4r4mg85kcickc7iomb0"/>
|
11
|
+
<link rel="edit" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/b1vq6rj4r4mg85kcickc7iomb0/63427908865"/>
|
12
|
+
<author>
|
13
|
+
<name>Some Guy</name>
|
14
|
+
<email>some.guy@gmail.com</email>
|
15
|
+
</author>
|
16
|
+
<gd:comments>
|
17
|
+
<gd:feedLink href="https://www.google.com/calendar/feeds/default/private/full/b1vq6rj4r4mg85kcickc7iomb0/comments"/>
|
18
|
+
</gd:comments>
|
19
|
+
<gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
|
20
|
+
<gd:where valueString="Joe's House"/>
|
21
|
+
<gd:who email="some.guy@gmail.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="some.guy@gmail.com"/>
|
22
|
+
<gd:when endTime="2010-12-13T01:34:20.000-08:00" startTime="2010-12-13T00:34:20.000-08:00"/>
|
23
|
+
<gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
|
24
|
+
<gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
|
25
|
+
<gCal:anyoneCanAddSelf value="false"/>
|
26
|
+
<gCal:guestsCanInviteOthers value="true"/>
|
27
|
+
<gCal:guestsCanModify value="false"/>
|
28
|
+
<gCal:guestsCanSeeGuests value="true"/>
|
29
|
+
<gCal:sequence value="0"/>
|
30
|
+
<gCal:uid value="b1vq6rj4r4mg85kcickc7iomb0@google.com"/>
|
31
|
+
</entry>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gCal="http://schemas.google.com/gCal/2005" xmlns:gd="http://schemas.google.com/g/2005">
|
3
|
+
<id>http://www.google.com/calendar/feeds/default/private/full/b1vq6rj4r4mg85kcickc7iomb0</id>
|
4
|
+
<published>2011-05-04T00:59:03.000Z</published>
|
5
|
+
<updated>2011-05-04T00:59:03.000Z</updated>
|
6
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
|
7
|
+
<title type="text">movie at AMC Van Ness</title>
|
8
|
+
<content type="text"/>
|
9
|
+
<link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=aW1vcnE4cHY5YWZlZ3R0ZDVlN3Fkc2ZidmcgYXluQGFuZHJld25nLmNvbQ" title="alternate"/>
|
10
|
+
<link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/imorq8pv9afegttd5e7qdsfbvg"/>
|
11
|
+
<link rel="edit" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/imorq8pv9afegttd5e7qdsfbvg/63440153943"/>
|
12
|
+
<author>
|
13
|
+
<name>Some Guy</name>
|
14
|
+
<email>some.guy@gmail.com</email>
|
15
|
+
</author>
|
16
|
+
<gd:comments>
|
17
|
+
<gd:feedLink href="https://www.google.com/calendar/feeds/default/private/full/b1vq6rj4r4mg85kcickc7iomb0/comments"/>
|
18
|
+
</gd:comments>
|
19
|
+
<gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
|
20
|
+
<gd:where valueString="AMC Van Ness"/>
|
21
|
+
<gd:who email="some.guy@gmail.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="some.guy@gmail.com"/>
|
22
|
+
<gd:when endTime="2011-05-05T00:00:00.000-07:00" startTime="2011-05-04T23:00:00.000-07:00"/>
|
23
|
+
<gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
|
24
|
+
<gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
|
25
|
+
<gCal:anyoneCanAddSelf value="false"/>
|
26
|
+
<gCal:guestsCanInviteOthers value="true"/>
|
27
|
+
<gCal:guestsCanModify value="false"/>
|
28
|
+
<gCal:guestsCanSeeGuests value="true"/>
|
29
|
+
<gCal:sequence value="0"/>
|
30
|
+
<gCal:uid value="b1vq6rj4r4mg85kcickc7iomb0@google.com"/>
|
31
|
+
</entry>
|
@@ -0,0 +1,119 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:gCal="http://schemas.google.com/gCal/2005" xmlns:gd="http://schemas.google.com/g/2005">
|
3
|
+
<id>http://www.google.com/calendar/feeds/default/private/full</id>
|
4
|
+
<updated>2010-12-10T07:09:25.000Z</updated>
|
5
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
|
6
|
+
<title type="text">Some Guy</title>
|
7
|
+
<subtitle type="text">Some Guy</subtitle>
|
8
|
+
<link rel="alternate" type="text/html" href="https://www.google.com/calendar/embed?src=some.guy@gmail.com"/>
|
9
|
+
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full"/>
|
10
|
+
<link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full"/>
|
11
|
+
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/batch"/>
|
12
|
+
<link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full?q=Test&max-results=25"/>
|
13
|
+
<author>
|
14
|
+
<name>Some Guy</name>
|
15
|
+
<email>some.guy@gmail.com</email>
|
16
|
+
</author>
|
17
|
+
<generator version="1.0" uri="http://www.google.com/calendar">Google Calendar</generator>
|
18
|
+
<openSearch:totalResults>1</openSearch:totalResults>
|
19
|
+
<openSearch:startIndex>1</openSearch:startIndex>
|
20
|
+
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
|
21
|
+
<gCal:timezone value="America/Los_Angeles"/>
|
22
|
+
<gCal:timesCleaned value="0"/>
|
23
|
+
<entry>
|
24
|
+
<id>http://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio</id>
|
25
|
+
<published>2010-04-22T16:05:29.000Z</published>
|
26
|
+
<updated>2010-05-01T05:14:18.000Z</updated>
|
27
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
|
28
|
+
<title type="text">Test</title>
|
29
|
+
<content type="text"/>
|
30
|
+
<link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=b2o2Zm1wYXVsYnZrOW91b2owbGo0djZoaW8gc3RldmUuemljaEBt" title="alternate"/>
|
31
|
+
<link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio"/>
|
32
|
+
<link rel="edit" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio/63408374058"/>
|
33
|
+
<author>
|
34
|
+
<name>Some Guy</name>
|
35
|
+
<email>some.guy@gmail.com</email>
|
36
|
+
</author>
|
37
|
+
<gd:comments>
|
38
|
+
<gd:feedLink href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio/comments"/>
|
39
|
+
</gd:comments>
|
40
|
+
<gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
|
41
|
+
<gd:where valueString=""/>
|
42
|
+
<gd:who email="some.guy@gmail.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="some.guy@gmail.com"/>
|
43
|
+
<gd:when endTime="2010-04-09" startTime="2010-04-08">
|
44
|
+
<gd:reminder method="alert" minutes="10"/>
|
45
|
+
</gd:when>
|
46
|
+
<gd:transparency value="http://schemas.google.com/g/2005#event.transparent"/>
|
47
|
+
<gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
|
48
|
+
<gCal:anyoneCanAddSelf value="false"/>
|
49
|
+
<gCal:guestsCanInviteOthers value="true"/>
|
50
|
+
<gCal:guestsCanModify value="false"/>
|
51
|
+
<gCal:guestsCanSeeGuests value="true"/>
|
52
|
+
<gCal:sequence value="0"/>
|
53
|
+
<gCal:uid value="oj6fmpaulbvk9ouoj0lj4v6hio@google.com"/>
|
54
|
+
</entry>
|
55
|
+
<entry>
|
56
|
+
<id>http://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio</id>
|
57
|
+
<published>2010-04-22T16:05:29.000Z</published>
|
58
|
+
<updated>2010-05-01T05:14:18.000Z</updated>
|
59
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
|
60
|
+
<title type="text">Test</title>
|
61
|
+
<content type="text"/>
|
62
|
+
<link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=b2o2Zm1wYXVsYnZrOW91b2owbGo0djZoaW8gc3RldmUuemljaEBt" title="alternate"/>
|
63
|
+
<link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio"/>
|
64
|
+
<link rel="edit" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio/63408374058"/>
|
65
|
+
<author>
|
66
|
+
<name>Some Guy</name>
|
67
|
+
<email>some.guy@gmail.com</email>
|
68
|
+
</author>
|
69
|
+
<gd:comments>
|
70
|
+
<gd:feedLink href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio/comments"/>
|
71
|
+
</gd:comments>
|
72
|
+
<gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
|
73
|
+
<gd:where valueString=""/>
|
74
|
+
<gd:who email="some.guy@gmail.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="some.guy@gmail.com"/>
|
75
|
+
<gd:when endTime="2010-04-09" startTime="2010-04-08">
|
76
|
+
<gd:reminder method="alert" minutes="10"/>
|
77
|
+
</gd:when>
|
78
|
+
<gd:transparency value="http://schemas.google.com/g/2005#event.transparent"/>
|
79
|
+
<gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
|
80
|
+
<gCal:anyoneCanAddSelf value="false"/>
|
81
|
+
<gCal:guestsCanInviteOthers value="true"/>
|
82
|
+
<gCal:guestsCanModify value="false"/>
|
83
|
+
<gCal:guestsCanSeeGuests value="true"/>
|
84
|
+
<gCal:sequence value="0"/>
|
85
|
+
<gCal:uid value="oj6fmpaulbvk9ouoj0lj4v6hio@google.com"/>
|
86
|
+
</entry>
|
87
|
+
<entry>
|
88
|
+
<id>http://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio</id>
|
89
|
+
<published>2010-04-22T16:05:29.000Z</published>
|
90
|
+
<updated>2010-05-01T05:14:18.000Z</updated>
|
91
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
|
92
|
+
<title type="text">Test</title>
|
93
|
+
<content type="text"/>
|
94
|
+
<link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=b2o2Zm1wYXVsYnZrOW91b2owbGo0djZoaW8gc3RldmUuemljaEBt" title="alternate"/>
|
95
|
+
<link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio"/>
|
96
|
+
<link rel="edit" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio/63408374058"/>
|
97
|
+
<author>
|
98
|
+
<name>Some Guy</name>
|
99
|
+
<email>some.guy@gmail.com</email>
|
100
|
+
</author>
|
101
|
+
<gd:comments>
|
102
|
+
<gd:feedLink href="https://www.google.com/calendar/feeds/default/private/full/oj6fmpaulbvk9ouoj0lj4v6hio/comments"/>
|
103
|
+
</gd:comments>
|
104
|
+
<gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
|
105
|
+
<gd:where valueString=""/>
|
106
|
+
<gd:who email="some.guy@gmail.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="some.guy@gmail.com"/>
|
107
|
+
<gd:when endTime="2010-04-09" startTime="2010-04-08">
|
108
|
+
<gd:reminder method="alert" minutes="10"/>
|
109
|
+
</gd:when>
|
110
|
+
<gd:transparency value="http://schemas.google.com/g/2005#event.transparent"/>
|
111
|
+
<gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
|
112
|
+
<gCal:anyoneCanAddSelf value="false"/>
|
113
|
+
<gCal:guestsCanInviteOthers value="true"/>
|
114
|
+
<gCal:guestsCanModify value="false"/>
|
115
|
+
<gCal:guestsCanSeeGuests value="true"/>
|
116
|
+
<gCal:sequence value="0"/>
|
117
|
+
<gCal:uid value="oj6fmpaulbvk9ouoj0lj4v6hio@google.com"/>
|
118
|
+
</entry>
|
119
|
+
</feed>
|