amr_google_calendar 0.2.3
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/.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>
|