gaah 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTZkNjZhYTVmMjJiMjBiNzMzYWRiOTZjNDFlOTQ0MjQ2OTE5ZDg0YQ==
5
+ data.tar.gz: !binary |-
6
+ ZTUwMmEwN2E1MDVjNzNlMTdiOTNiZDA3YTdmOWZiOTAxMTAwNWFhYQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTc5OTQwNGY3MzU0MzVjYzljY2E1ZDNiZWIyOGU3ZGI4ZGU1ZDhiZmRjMTdl
10
+ ZmJmNGY2ZDI2ZDRjNDU1YjAyMTIzM2M2ZDY0NTg1ZjMyMTQzZTI2MzY1NmUx
11
+ M2I5NmQ3MmFmZmJhOTY1MmI3NTQ5MTA4MjY4MmUyZDI2MzY3ODM=
12
+ data.tar.gz: !binary |-
13
+ MDNlYzRjYWI0ZWU1M2U3YjU5NjdhOTA5ZGQwNzI3ZGNiNjk1Y2IwODc3NDEz
14
+ YzI0YWMxOTIxZDZmMTQ4ZTYxZmI0ODIzODlmNjlmYWYxNWNiYjJiNWJkOGJi
15
+ ZTg3ZDk3MTZmOGI5NjM0YmMwMDU4NjVlMmRlOGUyNTk2OTFiYTk=
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'nokogiri', "~> 1.5"
4
+ gem 'oauth', "~> 0.4"
5
+ gem 'queryparams', "0.0.3"
6
+ gem 'rspec', "~> 2.5"
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.2.2)
5
+ nokogiri (1.5.9)
6
+ oauth (0.4.7)
7
+ queryparams (0.0.3)
8
+ rspec (2.13.0)
9
+ rspec-core (~> 2.13.0)
10
+ rspec-expectations (~> 2.13.0)
11
+ rspec-mocks (~> 2.13.0)
12
+ rspec-core (2.13.1)
13
+ rspec-expectations (2.13.0)
14
+ diff-lcs (>= 1.1.3, < 2.0)
15
+ rspec-mocks (2.13.0)
16
+
17
+ PLATFORMS
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ nokogiri (~> 1.5)
22
+ oauth (~> 0.4)
23
+ queryparams (= 0.0.3)
24
+ rspec (~> 2.5)
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # GAAH - Google Apps API Helper
2
+
3
+ ### API Wrapper for Google Apps Marketplace
4
+
5
+ Currently supports:
6
+
7
+ ![](https://developers.google.com/gdata/images/service_icons/gdata-contacts.png) Provisioning API (read-only)
8
+
9
+ ![](https://developers.google.com/gdata/images/service_icons/gdata-calendar.png) Calendar API
10
+
11
+ ### Example Code
12
+
13
+ ```ruby
14
+ CLIENT_KEY = '000000000000.apps.googleusercontent.com'
15
+ CLIENT_SECRET = 'abcdefghijklmnopqrstuvwx'
16
+ DOMAIN = 'example.com'
17
+
18
+ # Setup
19
+ require 'gaah'
20
+ Gaah.setup_oauth(CLIENT_KEY, CLIENT_SECRET)
21
+ Gaah.domain = DOMAIN
22
+
23
+ # Get users
24
+ users = Gaah::Provisioning::Api.users
25
+ user = users.first
26
+ user.id # "https://apps-apis.google.com/a/feeds/example.com/user/2.0/bobert"
27
+ user.name # "Bobert Jones"
28
+ user.title # "bobert"
29
+
30
+ # Get calendar events
31
+ xoauth_requestor_id = 'me@example.com'
32
+ events = user.events(xoauth_requestor_id)
33
+ event = events.first
34
+ event.title # "Meeting with Joe"
35
+ event.when.start_time # 2013-04-16 13:00:00 -0400
36
+ ```
37
+
38
+ ### Resources
39
+
40
+ Warning: Google documentation links sometimes move without good redirection.
41
+
42
+ * [Google Data APIs](https://developers.google.com/gdata/)
43
+ * [Google Apps Application APIs](https://developers.google.com/google-apps/app-apis)
44
+ * [Google Apps Administrative APIs](https://developers.google.com/google-apps/admin-apis)
45
+ * [Google Calendar API v2](https://developers.google.com/google-apps/calendar/v2/developers_guide_protocol)
46
+ * [Google Apps Provisioning API v2](https://developers.google.com/google-apps/provisioning/)
47
+
48
+ ### Todo
49
+ * Look into data api v3 when Provisioning API is updated
50
+ * Possibly integrate [Google Apps Calendar Resource API](https://developers.google.com/google-apps/calendar-resource/)
51
+ * Error handling
data/gaah.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "gaah/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gaah"
7
+ s.version = Gaah::VERSION
8
+ s.date = "2013-04-03"
9
+ s.authors = ["Hwan-Joon Choi"]
10
+ s.email = ["hc5duke@gmail.com"]
11
+ s.homepage = "https://github.com/distill-inc/gaah"
12
+
13
+ s.summary = "Limited API Wrapper for Google Apps API."
14
+ s.description = "Google Apps Marketplace API wrapper in ruby for Distill."
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "nokogiri", "~> 1.5"
22
+ s.add_dependency 'oauth', "~> 0.4"
23
+ s.add_dependency 'queryparams', "0.0.3"
24
+ s.add_development_dependency "rspec", "~> 2.5"
25
+ end
data/lib/gaah.rb ADDED
@@ -0,0 +1 @@
1
+ require 'gaah/base'
@@ -0,0 +1,49 @@
1
+ module Gaah
2
+ class ApiClient
3
+ class << self
4
+ attr_accessor :consumer_key, :consumer_secret, :instance
5
+
6
+ def setup_oauth(key, secret)
7
+ @@consumer_key = key
8
+ @@consumer_secret = secret
9
+ true
10
+ end
11
+
12
+ def not_setup?
13
+ @@consumer_key.nil? || @@consumer_secret.nil?
14
+ end
15
+
16
+ def instance
17
+ @@instance ||= new
18
+ end
19
+ end
20
+
21
+ def initialize
22
+ raise 'consumer_key and consumer_secret not set' if ApiClient.not_setup?
23
+ oauth_consumer = OAuth::Consumer.new(@@consumer_key, @@consumer_secret)
24
+ @token = OAuth::AccessToken.new(oauth_consumer)
25
+ end
26
+
27
+ def get(base, query_params={})
28
+ url = base
29
+ url = "#{base}?#{QueryParams.encode(query_params)}" if query_params.keys.length > 0
30
+ make_request(:get, url)
31
+ end
32
+
33
+ private
34
+
35
+ def make_request(method, url)
36
+ response = @token.request(method, url, 'GData-Version' => '2.0')
37
+
38
+ if response.is_a? Net::HTTPSuccess
39
+ response.body
40
+ elsif response.is_a? Net::HTTPFound
41
+ url = response['Location']
42
+ make_request(method, response['Location'])
43
+ else
44
+ # TODO: error handling
45
+ response
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,40 @@
1
+ module Gaah
2
+ class ApiModel
3
+ attr_reader :id
4
+
5
+ def self.batch_create(xml)
6
+ (xml/:entry).map(&method(:new))
7
+ end
8
+
9
+ protected
10
+
11
+ def ==(other)
12
+ @id == other.id
13
+ end
14
+
15
+ private
16
+
17
+ def store_xml(xml)
18
+ @xml = xml.is_a?(String) ? Nokogiri::XML(xml) : xml
19
+ end
20
+
21
+ def inner_text(tag)
22
+ (@xml/tag).inner_text
23
+ end
24
+
25
+ def attr_value(tag, attribute = 'value')
26
+ node = (@xml/tag).first
27
+ return nil if node.nil?
28
+ attr = node.attr(attribute)
29
+ attr.respond_to?(:value) ? attr.value : attr
30
+ end
31
+
32
+ def tag_value(tag)
33
+ attr_value(tag).split('.').last
34
+ end
35
+
36
+ def inspect
37
+ "#<#{self.class}:#{object_id}>"
38
+ end
39
+ end
40
+ end
data/lib/gaah/base.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'cgi'
2
+ require 'time'
3
+ require 'date'
4
+ require 'json'
5
+
6
+ require 'oauth'
7
+ require 'nokogiri'
8
+ require 'queryparams'
9
+
10
+ require 'gaah/api_client'
11
+ require 'gaah/api_model'
12
+ require 'gaah/calendar/api'
13
+ require 'gaah/provisioning/api'
14
+
15
+ module Gaah
16
+ class << self
17
+ attr_accessor :domain
18
+ def setup_oauth(key, secret)
19
+ ApiClient.setup_oauth(key, secret)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ require 'gaah/calendar/event'
2
+ require 'gaah/calendar/when'
3
+ require 'gaah/calendar/who'
4
+
5
+ module Gaah
6
+ module Calendar
7
+ class Api
8
+ class << self
9
+ def events(xoauth_requestor_id, options)
10
+ url = build_api_url(options[:email])
11
+ params = build_api_params(xoauth_requestor_id, options)
12
+ xml = ApiClient.instance.get(url, params)
13
+ events = Nokogiri::XML(xml)/:entry
14
+ Event.batch_create(events)
15
+ end
16
+
17
+ private
18
+
19
+ def build_api_url(email)
20
+ API_URL.sub('EMAIL', email || 'default')
21
+ end
22
+
23
+ def build_api_params(xoauth_requestor_id, options)
24
+ api_params = { xoauth_requestor_id: xoauth_requestor_id }
25
+ api_params[:orderby] = options.delete(:order_by) || 'starttime'
26
+ api_params[:singleevents] = options.delete(:single_events) || true
27
+ api_params[:sortorder] = options.delete(:sort_order) || 'a'
28
+ api_params['start-min'] = stringify(options.delete(:start_min))
29
+ api_params['start-max'] = stringify(options.delete(:start_max))
30
+ api_params
31
+ end
32
+
33
+ def stringify(time)
34
+ time.nil? ? nil : time.strftime('%Y-%m-%dT17:00:00')
35
+ end
36
+
37
+ API_URL = 'https://www.google.com/calendar/feeds/EMAIL/private/full'
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ module Gaah
2
+ module Calendar
3
+ class Event < Gaah::ApiModel
4
+ attr_reader :published, :updated, :title, :content, :status, :who, :when, :where, :author, :transparency, :visibility
5
+
6
+ def initialize(xml)
7
+ store_xml(xml)
8
+
9
+ @id = inner_text(:id)
10
+ @published = Time.parse(inner_text(:published))
11
+ @updated = Time.parse(inner_text(:updated))
12
+ @title = inner_text(:title)
13
+ @content = inner_text(:content)
14
+ @status = tag_value('gd|eventStatus')
15
+ @where = attr_value('gd|where', 'valueString')
16
+ @author = Who.new((@xml/:author).first)
17
+ @when = parse_when
18
+ @who = parse_who
19
+ @transparency = tag_value('gd|transparency')
20
+ @visibility = tag_value('gd|visibility')
21
+ end
22
+
23
+ def to_json(*args)
24
+ {
25
+ id: @id,
26
+ published: @published,
27
+ updated: @updated,
28
+ title: @title,
29
+ content: @content,
30
+ status: @status,
31
+ where: @where,
32
+ author: @author,
33
+ when: @when,
34
+ who: @who,
35
+ transparency: @transparency,
36
+ visibility: @visibility,
37
+ }.to_json
38
+ end
39
+
40
+ private
41
+
42
+ def store_xml(xml)
43
+ super
44
+ unless @xml.attr('gd:kind') == "calendar#event"
45
+ puts "Possible invalid event xml - gd:kind is #{ @xml.attr('gd:kind') }"
46
+ end
47
+ end
48
+
49
+ def parse_when
50
+ When.new(attr_value('> gd|when', 'startTime'), attr_value('> gd|when', 'endTime'))
51
+ end
52
+
53
+ def parse_who
54
+ (@xml/'gd|who').map {|attendee| Who.new(attendee) }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,18 @@
1
+ module Gaah
2
+ module Calendar
3
+ class When
4
+ attr_accessor :start_time, :end_time
5
+ def initialize(start_time, end_time)
6
+ @start_time = Time.parse(start_time)
7
+ @end_time = Time.parse(end_time)
8
+ end
9
+
10
+ def to_json(*args)
11
+ {
12
+ start_time: @start_time,
13
+ end_time: @end_time,
14
+ }.to_json
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ module Gaah
2
+ module Calendar
3
+ class Who
4
+ attr_reader :name, :email, :aliases
5
+ def initialize(xml)
6
+ @aliases = []
7
+
8
+ case xml.name
9
+ when 'author'
10
+ @name = (xml/:name).inner_text
11
+ @email = (xml/:email).inner_text
12
+ when 'who'
13
+ @name = xml.attr(:valueString)
14
+ @email = xml.attr(:email)
15
+ when 'entry'
16
+ @name = (xml/:title).inner_text
17
+ (xml/'gd|email').each do |gd_email|
18
+ email = gd_email.attr('address')
19
+ @aliases << email
20
+ @email = email if gd_email.attr('primary') == 'true'
21
+ end
22
+ else
23
+ raise "Invalid person record #{xml.name}"
24
+ end
25
+ end
26
+
27
+ def catch_all_user?
28
+ self.email.to_s =~ /^\.@/
29
+ end
30
+
31
+ def to_json(*args)
32
+ {
33
+ name: name,
34
+ email: email,
35
+ aliases: aliases,
36
+ }.to_json
37
+ end
38
+
39
+ def self.batch_process(xml, exclude_catch_all_user = true)
40
+ (xml/:entry).map do |entry|
41
+ who = new(entry)
42
+ if exclude_catch_all_user && who.catch_all_user?
43
+ nil
44
+ else
45
+ who
46
+ end
47
+ end.compact
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ require 'gaah/provisioning/user'
2
+
3
+ module Gaah
4
+ module Provisioning
5
+ class Api
6
+ class << self
7
+ def users
8
+ url = "https://apps-apis.google.com/a/feeds/#{Gaah.domain}/user/2.0"
9
+ xml = ApiClient.instance.get(url)
10
+ users = Nokogiri::XML(xml)/:entry
11
+ User.batch_create(users)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,53 @@
1
+ module Gaah
2
+ module Provisioning
3
+ class User < Gaah::ApiModel
4
+ attr_reader :suspended, :admin, :title, :user_name, :family_name, :given_name, :name, :email
5
+
6
+ def initialize(entry)
7
+ store_xml(entry)
8
+
9
+ # Meta
10
+ @id = inner_text(:id)
11
+ @email = parse_email
12
+ @suspended = attr_value('apps|login', 'suspended') == 'true'
13
+ @admin = attr_value('apps|login', 'admin') == 'true'
14
+
15
+ # Name
16
+ @title = inner_text(:title)
17
+ @user_name = attr_value('apps|login', 'userName')
18
+ @family_name = attr_value('apps|name', 'familyName')
19
+ @given_name = attr_value('apps|name', 'givenName')
20
+ end
21
+
22
+ def parse_email
23
+ email_link = (@xml/'gd|feedLink').select { |link|
24
+ link.attr('rel').end_with?('user.emailLists')
25
+ }.first
26
+ return nil if email_link.nil?
27
+ CGI::unescape(email_link.attr('href').split('recipient=').last)
28
+ end
29
+
30
+ def name
31
+ "#{@given_name} #{@family_name}"
32
+ end
33
+
34
+ def events(xoauth_requestor_id, options = {})
35
+ options[:email] = @email
36
+ Gaah::Calendar::Api.events(xoauth_requestor_id, options)
37
+ end
38
+
39
+ def to_json(*args)
40
+ {
41
+ id: @id,
42
+ suspended: @suspended,
43
+ admin: @admin,
44
+ title: @title,
45
+ user_name: @user_name,
46
+ family_name: @family_name,
47
+ given_name: @given_name,
48
+ name: @name,
49
+ }.to_json
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module Gaah
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,369 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:gCal="http://schemas.google.com/gCal/2005" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/&quot;CU4CQn47eCp7JGA9WhBXGUg.&quot;" gd:kind="calendar#eventFeed">
3
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/private/full</id>
4
+ <updated>2013-04-03T01:52:43.000Z</updated>
5
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
6
+ <title>bobert@example.com</title>
7
+ <subtitle>bobert@example.com</subtitle>
8
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/embed?src=bobert%40example.com"/>
9
+ <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full?xoauth_requestor_id=bobert@example.com"/>
10
+ <link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/batch?xoauth_requestor_id=bobert@example.com"/>
11
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full?max-results=25&amp;start-min=2013-03-31T17%3A00%3A00&amp;singleevents=true&amp;start-max=2013-04-07T17%3A00%3A00&amp;sortorder=a&amp;orderby=starttime&amp;xoauth_requestor_id=bobert@example.com"/>
12
+ <author>
13
+ <name>Bobert Jones</name>
14
+ <email>bobert@example.com</email>
15
+ </author>
16
+ <generator version="1.0" uri="http://www.google.com/calendar">Google Calendar</generator>
17
+ <openSearch:totalResults>10</openSearch:totalResults>
18
+ <openSearch:startIndex>1</openSearch:startIndex>
19
+ <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
20
+ <gCal:timezone value="America/Los_Angeles"/>
21
+ <gCal:timesCleaned value="0"/>
22
+ <entry gd:etag="&quot;GUQLQwVIfip7JGA6WhJa&quot;" gd:kind="calendar#event">
23
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/n9ommrehhjm5dc6q89ofkm3f8g</id>
24
+ <published>2013-03-25T16:49:48.000Z</published>
25
+ <updated>2013-03-25T17:03:10.000Z</updated>
26
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
27
+ <title>MomCorp</title>
28
+ <content/>
29
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=bjlvbW1yZWhoam01ZGM2cTg5b2ZrbTNmOGcga2FpQGRpc3RpbGwuY2M" title="alternate"/>
30
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/n9ommrehhjm5dc6q89ofkm3f8g?xoauth_requestor_id=bobert@example.com"/>
31
+ <author>
32
+ <name>Bobert Jones</name>
33
+ <email>bobert@example.com</email>
34
+ </author>
35
+ <gd:comments>
36
+ <gd:feedLink href="https://www.google.com"/>
37
+ </gd:comments>
38
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
39
+ <gd:where valueString=""/>
40
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="Bobert Jones">
41
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
42
+ </gd:who>
43
+ <gd:who email="fry@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Philip Fry">
44
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
45
+ </gd:who>
46
+ <gd:when endTime="2013-04-01T11:00:00.000-07:00" startTime="2013-04-01T10:00:00.000-07:00"/>
47
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
48
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
49
+ <gCal:anyoneCanAddSelf value="false"/>
50
+ <gCal:guestsCanInviteOthers value="true"/>
51
+ <gCal:guestsCanModify value="false"/>
52
+ <gCal:guestsCanSeeGuests value="true"/>
53
+ <gCal:sequence value="0"/>
54
+ <gCal:uid value="n9ommrehhjm5dc6q89ofkm3f8g@google.com"/>
55
+ </entry>
56
+ <entry gd:etag="&quot;EEgITgRIdip7JGA6WhNT&quot;" gd:kind="calendar#event">
57
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/b2if8georrqg4ie9p04t3jdvd0_20130401T233000Z</id>
58
+ <published>2013-03-04T16:52:10.000Z</published>
59
+ <updated>2013-04-01T19:51:38.000Z</updated>
60
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
61
+ <title>Weekly Sync</title>
62
+ <content/>
63
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=YjJpZjhnZW9ycnFnNGllOXAwNHQzamR2ZDBfMjAxMzA0MDFUMjMzMDAwWiBrYWlAZGlzdGlsbC5jYw" title="alternate"/>
64
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/b2if8georrqg4ie9p04t3jdvd0_20130401T233000Z?xoauth_requestor_id=bobert@example.com"/>
65
+ <author>
66
+ <name>Bobert Jones</name>
67
+ <email>bobert@example.com</email>
68
+ </author>
69
+ <gd:comments>
70
+ <gd:feedLink href="https://www.google.com"/>
71
+ </gd:comments>
72
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
73
+ <gd:where valueString=""/>
74
+ <gd:originalEvent href="http://www.google.com/calendar/feeds/bobert%40example.com/private/full/b2if8georrqg4ie9p04t3jdvd0" id="b2if8georrqg4ie9p04t3jdvd0">
75
+ <gd:when startTime="2013-04-01T16:30:00.000-07:00"/>
76
+ </gd:originalEvent>
77
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="Bobert Jones">
78
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
79
+ </gd:who>
80
+ <gd:who email="fry@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Philip Fry">
81
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
82
+ </gd:who>
83
+ <gd:who email="leela@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Turanga Leela">
84
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
85
+ </gd:who>
86
+ <gd:who email="bender@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Bender Rodriguez">
87
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.invited"/>
88
+ </gd:who>
89
+ <gd:who email="farnsworth@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Hubert Farnsworth">
90
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
91
+ </gd:who>
92
+ <gd:who email="zoidberg@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="John Zoidberg">
93
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.invited"/>
94
+ </gd:who>
95
+ <gd:when endTime="2013-04-01T13:00:00.000-07:00" startTime="2013-04-01T12:00:00.000-07:00"/>
96
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
97
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
98
+ <gCal:anyoneCanAddSelf value="false"/>
99
+ <gCal:guestsCanInviteOthers value="true"/>
100
+ <gCal:guestsCanModify value="true"/>
101
+ <gCal:guestsCanSeeGuests value="true"/>
102
+ <gCal:sequence value="1"/>
103
+ <gCal:uid value="b2if8georrqg4ie9p04t3jdvd0@google.com"/>
104
+ </entry>
105
+ <entry gd:etag="&quot;EE8IQQdHfyp7JGA6WhNT&quot;" gd:kind="calendar#event">
106
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/8ac5lhpq27gockkrh8ncsjbrq8</id>
107
+ <published>2013-03-29T00:33:26.000Z</published>
108
+ <updated>2013-03-29T07:46:01.000Z</updated>
109
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
110
+ <title>Mars University</title>
111
+ <content/>
112
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=OGFjNWxocHEyN2dvY2trcmg4bmNzamJycTgga2FpQGRpc3RpbGwuY2M" title="alternate"/>
113
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/8ac5lhpq27gockkrh8ncsjbrq8?xoauth_requestor_id=bobert@example.com"/>
114
+ <author>
115
+ <name>Bobert Jones</name>
116
+ <email>bobert@example.com</email>
117
+ </author>
118
+ <gd:comments>
119
+ <gd:feedLink href="https://www.google.com"/>
120
+ </gd:comments>
121
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
122
+ <gd:where valueString=""/>
123
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="Bobert Jones">
124
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
125
+ </gd:who>
126
+ <gd:who email="fry@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Philip Fry">
127
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
128
+ </gd:who>
129
+ <gd:when endTime="2013-04-01T15:00:00.000-07:00" startTime="2013-04-01T14:00:00.000-07:00"/>
130
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
131
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
132
+ <gCal:anyoneCanAddSelf value="false"/>
133
+ <gCal:guestsCanInviteOthers value="true"/>
134
+ <gCal:guestsCanModify value="false"/>
135
+ <gCal:guestsCanSeeGuests value="true"/>
136
+ <gCal:sequence value="0"/>
137
+ <gCal:uid value="8ac5lhpq27gockkrh8ncsjbrq8@google.com"/>
138
+ </entry>
139
+ <entry gd:etag="&quot;GU4DTgRGdyp7JGA6WhJa&quot;" gd:kind="calendar#event">
140
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/_6t332c2464ojeb9m6p23gb9k8krjcb9o6ko3iba668q38cpm64s46ga68c</id>
141
+ <published>2013-03-19T17:57:11.000Z</published>
142
+ <updated>2013-03-19T17:57:59.000Z</updated>
143
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
144
+ <title>Block for strategy session</title>
145
+ <content>Palo Alto</content>
146
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=XzZ0MzMyYzI0NjRvamViOW02cDIzZ2I5azhrcmpjYjlvNmtvM2liYTY2OHEzOGNwbTY0czQ2Z2E2OGMga2FpQGRpc3RpbGwuY2M" title="alternate"/>
147
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/_6t332c2464ojeb9m6p23gb9k8krjcb9o6ko3iba668q38cpm64s46ga68c?xoauth_requestor_id=bobert@example.com"/>
148
+ <author>
149
+ <name>Bobert Jones</name>
150
+ <email>bobert@example.com</email>
151
+ </author>
152
+ <gd:comments>
153
+ <gd:feedLink href="https://www.google.com"/>
154
+ </gd:comments>
155
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
156
+ <gd:where valueString="530 Lytton Ave Suite 305 Palo Alto"/>
157
+ <gd:who email="amy@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Amy Wong">
158
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.invited"/>
159
+ </gd:who>
160
+ <gd:who email="bender@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Bender Rodriguez">
161
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.invited"/>
162
+ </gd:who>
163
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Bobert Jones">
164
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
165
+ </gd:who>
166
+ <gd:who email="hermes@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="hermes@examle.com"/>
167
+ <gd:when endTime="2013-04-02T12:30:00.000-07:00" startTime="2013-04-02T11:00:00.000-07:00"/>
168
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
169
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
170
+ <gCal:anyoneCanAddSelf value="false"/>
171
+ <gCal:guestsCanInviteOthers value="false"/>
172
+ <gCal:guestsCanModify value="false"/>
173
+ <gCal:guestsCanSeeGuests value="true"/>
174
+ <gCal:privateCopy value="true"/>
175
+ <gCal:sequence value="0"/>
176
+ <gCal:uid value="7F10D117-66D8-4E76-8509-F2443618CAFC"/>
177
+ </entry>
178
+ <entry gd:etag="&quot;EEsLTg1Fdyp7JGA6WhNT&quot;" gd:kind="calendar#event">
179
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/c55b0pe0odp94803fgv803c22c</id>
180
+ <published>2013-04-02T21:05:49.000Z</published>
181
+ <updated>2013-04-02T21:05:49.000Z</updated>
182
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
183
+ <title>D.O.O.P.</title>
184
+ <content/>
185
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=YzU1YjBwZTBvZHA5NDgwM2ZndjgwM2MyMmMga2FpQGRpc3RpbGwuY2M" title="alternate"/>
186
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/c55b0pe0odp94803fgv803c22c?xoauth_requestor_id=bobert@example.com"/>
187
+ <author>
188
+ <name>Bobert Jones</name>
189
+ <email>bobert@example.com</email>
190
+ </author>
191
+ <gd:comments>
192
+ <gd:feedLink href="https://www.google.com"/>
193
+ </gd:comments>
194
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
195
+ <gd:where valueString=""/>
196
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="bobert@example.com"/>
197
+ <gd:when endTime="2013-04-02T15:00:00.000-07:00" startTime="2013-04-02T14:30:00.000-07:00"/>
198
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
199
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
200
+ <gCal:anyoneCanAddSelf value="false"/>
201
+ <gCal:guestsCanInviteOthers value="true"/>
202
+ <gCal:guestsCanModify value="false"/>
203
+ <gCal:guestsCanSeeGuests value="true"/>
204
+ <gCal:sequence value="0"/>
205
+ <gCal:uid value="c55b0pe0odp94803fgv803c22c@google.com"/>
206
+ </entry>
207
+ <entry gd:etag="&quot;EEgJQQFJeCp7JGA6WhNT&quot;" gd:kind="calendar#event">
208
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/d0fq0gul9ml5t7i6oeiii37ql4</id>
209
+ <published>2013-04-01T21:53:55.000Z</published>
210
+ <updated>2013-04-01T21:56:26.000Z</updated>
211
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
212
+ <title>Head Museum</title>
213
+ <content/>
214
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=ZDBmcTBndWw5bWw1dDdpNm9laWlpMzdxbDQga2FpQGRpc3RpbGwuY2M" title="alternate"/>
215
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/d0fq0gul9ml5t7i6oeiii37ql4?xoauth_requestor_id=bobert@example.com"/>
216
+ <author>
217
+ <name>Bobert Jones</name>
218
+ <email>bobert@example.com</email>
219
+ </author>
220
+ <gd:comments>
221
+ <gd:feedLink href="https://www.google.com"/>
222
+ </gd:comments>
223
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
224
+ <gd:where valueString=""/>
225
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="Bobert Jones">
226
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
227
+ </gd:who>
228
+ <gd:who email="fry@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Philip Fry">
229
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
230
+ </gd:who>
231
+ <gd:when endTime="2013-04-03T14:00:00.000-07:00" startTime="2013-04-03T13:00:00.000-07:00"/>
232
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
233
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
234
+ <gCal:anyoneCanAddSelf value="false"/>
235
+ <gCal:guestsCanInviteOthers value="true"/>
236
+ <gCal:guestsCanModify value="false"/>
237
+ <gCal:guestsCanSeeGuests value="true"/>
238
+ <gCal:sequence value="0"/>
239
+ <gCal:uid value="d0fq0gul9ml5t7i6oeiii37ql4@google.com"/>
240
+ </entry>
241
+ <entry gd:etag="&quot;EEgJQQJIeCp7JGA6WhNT&quot;" gd:kind="calendar#event">
242
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/m0g74buir5cj3004qc0l393lto</id>
243
+ <published>2013-03-14T23:12:43.000Z</published>
244
+ <updated>2013-04-01T21:58:16.000Z</updated>
245
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
246
+ <title>Omicron Persei 8</title>
247
+ <content/>
248
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=bTBnNzRidWlyNWNqMzAwNHFjMGwzOTNsdG8ga2FpQGRpc3RpbGwuY2M" title="alternate"/>
249
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/m0g74buir5cj3004qc0l393lto?xoauth_requestor_id=bobert@example.com"/>
250
+ <author>
251
+ <name>Bobert Jones</name>
252
+ <email>bobert@example.com</email>
253
+ </author>
254
+ <gd:comments>
255
+ <gd:feedLink href="https://www.google.com"/>
256
+ </gd:comments>
257
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
258
+ <gd:where valueString="Planet Omicron Persei 8 "/>
259
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="Bobert Jones">
260
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
261
+ </gd:who>
262
+ <gd:who email="fry@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Philip Fry">
263
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
264
+ </gd:who>
265
+ <gd:when endTime="2013-04-03T16:00:00.000-07:00" startTime="2013-04-03T15:00:00.000-07:00"/>
266
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
267
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
268
+ <gCal:anyoneCanAddSelf value="false"/>
269
+ <gCal:guestsCanInviteOthers value="true"/>
270
+ <gCal:guestsCanModify value="false"/>
271
+ <gCal:guestsCanSeeGuests value="true"/>
272
+ <gCal:sequence value="1"/>
273
+ <gCal:uid value="m0g74buir5cj3004qc0l393lto@google.com"/>
274
+ </entry>
275
+ <entry gd:etag="&quot;GU4LRABJfCp7JGA6WhJa&quot;" gd:kind="calendar#event">
276
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/_60q30c1g60o30e1i60o4ac1g60rj8gpl88rj2c1h84s34h9g60s30c1g60o30c1g6so32ghp8h33egi568pk6h9g64o30c1g60o30c1g60o30c1g60o32c1g60o30c1g8h23cc2388ojida36t2jgg9k610k6ga48p2j6cho6grkcdhm84qg</id>
277
+ <published>2013-03-18T16:57:14.000Z</published>
278
+ <updated>2013-03-18T18:11:22.000Z</updated>
279
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
280
+ <title>Meeting with Lrrr</title>
281
+ <content>password: example</content>
282
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=XzYwcTMwYzFnNjBvMzBlMWk2MG80YWMxZzYwcmo4Z3BsODhyajJjMWg4NHMzNGg5ZzYwczMwYzFnNjBvMzBjMWc2c28zMmdocDhoMzNlZ2k1NjhwazZoOWc2NG8zMGMxZzYwbzMwYzFnNjBvMzBjMWc2MG8zMmMxZzYwbzMwYzFnOGgyM2NjMjM4OG9qaWRhMzZ0MmpnZzlrNjEwazZnYTQ4cDJqNmNobzZncmtjZGhtODRxZyBrYWlAZGlzdGlsbC5jYw" title="alternate"/>
283
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/_60q30c1g60o30e1i60o4ac1g60rj8gpl88rj2c1h84s34h9g60s30c1g60o30c1g6so32ghp8h33egi568pk6h9g64o30c1g60o30c1g60o30c1g60o32c1g60o30c1g8h23cc2388ojida36t2jgg9k610k6ga48p2j6cho6grkcdhm84qg?xoauth_requestor_id=bobert@example.com"/>
284
+ <author>
285
+ <name>Bobert Jones</name>
286
+ <email>bobert@example.com</email>
287
+ </author>
288
+ <gd:comments>
289
+ <gd:feedLink href="https://www.google.com"/>
290
+ </gd:comments>
291
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
292
+ <gd:where valueString="Omicron Persei 8 "/>
293
+ <gd:who email="planet.express@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Planet Express">
294
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.invited"/>
295
+ </gd:who>
296
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.attendee" valueString="Bobert Jones">
297
+ <gd:attendeeStatus value="http://schemas.google.com/g/2005#event.accepted"/>
298
+ </gd:who>
299
+ <gd:who email="zapp@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="Zapp Brannigan"/>
300
+ <gd:when endTime="2013-04-03T16:00:00.000-07:00" startTime="2013-04-03T15:00:00.000-07:00"/>
301
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
302
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
303
+ <gCal:anyoneCanAddSelf value="false"/>
304
+ <gCal:guestsCanInviteOthers value="false"/>
305
+ <gCal:guestsCanModify value="false"/>
306
+ <gCal:guestsCanSeeGuests value="true"/>
307
+ <gCal:privateCopy value="true"/>
308
+ <gCal:sequence value="0"/>
309
+ <gCal:uid value="040000008200E00074C5B7101A82E00800000000701B9DF7BE23CE01000000000000000010000000DD60CB195C7E8A40ACADFE32847F66A5"/>
310
+ </entry>
311
+ <entry gd:etag="&quot;GE4CRgFGeip7JGA6WhJa&quot;" gd:kind="calendar#event">
312
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/qhehinrhaaqi7lsc1p8ukn1k1k</id>
313
+ <published>2013-03-07T23:19:14.000Z</published>
314
+ <updated>2013-03-07T23:19:34.000Z</updated>
315
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
316
+ <title>Alumni Event</title>
317
+ <content/>
318
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=cWhlaGlucmhhYXFpN2xzYzFwOHVrbjFrMWsga2FpQGRpc3RpbGwuY2M" title="alternate"/>
319
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/qhehinrhaaqi7lsc1p8ukn1k1k?xoauth_requestor_id=bobert@example.com"/>
320
+ <author>
321
+ <name>Bobert Jones</name>
322
+ <email>bobert@example.com</email>
323
+ </author>
324
+ <gd:comments>
325
+ <gd:feedLink href="https://www.google.com"/>
326
+ </gd:comments>
327
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
328
+ <gd:where valueString="Mars University"/>
329
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="bobert@example.com"/>
330
+ <gd:when endTime="2013-04-04T19:00:00.000-07:00" startTime="2013-04-04T18:00:00.000-07:00"/>
331
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
332
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
333
+ <gCal:anyoneCanAddSelf value="false"/>
334
+ <gCal:guestsCanInviteOthers value="true"/>
335
+ <gCal:guestsCanModify value="false"/>
336
+ <gCal:guestsCanSeeGuests value="true"/>
337
+ <gCal:sequence value="0"/>
338
+ <gCal:uid value="qhehinrhaaqi7lsc1p8ukn1k1k@google.com"/>
339
+ </entry>
340
+ <entry gd:etag="&quot;EEsITwBGeSp7JGA6WhNT&quot;" gd:kind="calendar#event">
341
+ <id>http://www.google.com/calendar/feeds/bobert%40example.com/events/bqup9tohkrmo7685ks63jrkokc</id>
342
+ <published>2013-04-02T23:26:58.000Z</published>
343
+ <updated>2013-04-02T23:27:57.000Z</updated>
344
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
345
+ <title>The Donbot</title>
346
+ <content/>
347
+ <link rel="alternate" type="text/html" href="https://www.google.com/calendar/event?eid=YnF1cDl0b2hrcm1vNzY4NWtzNjNqcmtva2Mga2FpQGRpc3RpbGwuY2M" title="alternate"/>
348
+ <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/bobert%40example.com/private/full/bqup9tohkrmo7685ks63jrkokc?xoauth_requestor_id=bobert@example.com"/>
349
+ <author>
350
+ <name>Bobert Jones</name>
351
+ <email>bobert@example.com</email>
352
+ </author>
353
+ <gd:comments>
354
+ <gd:feedLink href="https://www.google.com"/>
355
+ </gd:comments>
356
+ <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
357
+ <gd:where valueString="Elzar's"/>
358
+ <gd:who email="bobert@example.com" rel="http://schemas.google.com/g/2005#event.organizer" valueString="bobert@example.com"/>
359
+ <gd:when endTime="2013-04-05T11:00:00.000-07:00" startTime="2013-04-05T10:00:00.000-07:00"/>
360
+ <gd:transparency value="http://schemas.google.com/g/2005#event.opaque"/>
361
+ <gd:visibility value="http://schemas.google.com/g/2005#event.default"/>
362
+ <gCal:anyoneCanAddSelf value="false"/>
363
+ <gCal:guestsCanInviteOthers value="true"/>
364
+ <gCal:guestsCanModify value="false"/>
365
+ <gCal:guestsCanSeeGuests value="true"/>
366
+ <gCal:sequence value="0"/>
367
+ <gCal:uid value="bqup9tohkrmo7685ks63jrkokc@google.com"/>
368
+ </entry>
369
+ </feed>
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:apps="http://schemas.google.com/apps/2006" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/&quot;YDwqeyI.&quot;">
3
+ <id>https://apps-apis.google.com/a/feeds/example.com/user/2.0</id>
4
+ <updated>1970-01-01T00:00:00.000Z</updated>
5
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/apps/2006#user"/>
6
+ <title>Users</title>
7
+ <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0"/>
8
+ <link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0"/>
9
+ <link rel="self" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0"/>
10
+ <openSearch:startIndex>1</openSearch:startIndex>
11
+ <entry gd:etag="W/&quot;YDwqeyI.&quot;">
12
+ <id>https://apps-apis.google.com/a/feeds/example.com/user/2.0/fry</id>
13
+ <updated>1970-01-01T00:00:00.000Z</updated>
14
+ <app:edited xmlns:app="http://www.w3.org/2007/app">1970-01-01T00:00:00.000Z</app:edited>
15
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/apps/2006#user"/>
16
+ <title>fry</title>
17
+ <link rel="self" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0/fry"/>
18
+ <link rel="edit" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0/fry"/>
19
+ <apps:login userName="fry" suspended="false" ipWhitelisted="false" admin="false" changePasswordAtNextLogin="false" agreedToTerms="true"/>
20
+ <apps:quota limit="25600"/>
21
+ <apps:name familyName="Fry" givenName="Philip"/>
22
+ <gd:feedLink rel="http://schemas.google.com/apps/2006#user.nicknames" href="https://apps-apis.google.com/a/feeds/example.com/nickname/2.0?username=fry"/>
23
+ <gd:feedLink rel="http://schemas.google.com/apps/2006#user.emailLists" href="https://apps-apis.google.com/a/feeds/example.com/emailList/2.0?recipient=fry%40example.com"/>
24
+ </entry>
25
+ <entry gd:etag="W/&quot;YDwqeyI.&quot;">
26
+ <id>https://apps-apis.google.com/a/feeds/example.com/user/2.0/bender</id>
27
+ <updated>1970-01-01T00:00:00.000Z</updated>
28
+ <app:edited xmlns:app="http://www.w3.org/2007/app">1970-01-01T00:00:00.000Z</app:edited>
29
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/apps/2006#user"/>
30
+ <title>bender</title>
31
+ <link rel="self" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0/bender"/>
32
+ <link rel="edit" type="application/atom+xml" href="https://apps-apis.google.com/a/feeds/example.com/user/2.0/bender"/>
33
+ <apps:login userName="bender" suspended="true" ipWhitelisted="false" admin="true" changePasswordAtNextLogin="false" agreedToTerms="true"/>
34
+ <apps:quota limit="25600"/>
35
+ <apps:name familyName="Rodriguez" givenName="Bender"/>
36
+ <gd:feedLink rel="http://schemas.google.com/apps/2006#user.nicknames" href="https://apps-apis.google.com/a/feeds/example.com/nickname/2.0?username=bender"/>
37
+ <gd:feedLink rel="http://schemas.google.com/apps/2006#user.emailLists" href="https://apps-apis.google.com/a/feeds/example.com/emailList/2.0?recipient=bender%40example.com"/>
38
+ </entry>
39
+ </feed>
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ include Gaah::Calendar
3
+
4
+ describe Event do
5
+ let(:xml) { fixture('calendar.xml') }
6
+ let(:events) { Nokogiri::XML(xml)/:entry }
7
+ let(:event) { Event.new(events.first) }
8
+
9
+ describe '#initialize' do
10
+ it 'parses ID' do
11
+ event.id.should == 'http://www.google.com/calendar/feeds/bobert%40example.com/events/n9ommrehhjm5dc6q89ofkm3f8g'
12
+ end
13
+
14
+ it 'parses published time' do
15
+ event.published.should == Time.parse('2013-03-25T16:49:48.000Z')
16
+ end
17
+
18
+ it 'parses updated time' do
19
+ event.updated.should == Time.parse('2013-03-25T17:03:10.000Z')
20
+ end
21
+
22
+ it 'parses title' do
23
+ event.title.should == 'MomCorp'
24
+ end
25
+
26
+ it 'parses content' do
27
+ event.content.should == ''
28
+ end
29
+
30
+ it 'parses status' do
31
+ event.status.should == 'confirmed'
32
+ end
33
+
34
+ describe :who do
35
+ let(:who) { event.who }
36
+
37
+ it 'parses who' do
38
+ who.length.should == 2
39
+ who.first.should be_an_instance_of(Gaah::Calendar::Who)
40
+ end
41
+
42
+ it 'parses name' do
43
+ who.first.name.should == 'Bobert Jones'
44
+ end
45
+
46
+ it 'parses email' do
47
+ who.first.email.should == 'bobert@example.com'
48
+ end
49
+ end
50
+
51
+ describe :when do
52
+ let(:_when) { event.when }
53
+
54
+ it 'parses when' do
55
+ _when.should be_an_instance_of(When)
56
+ end
57
+
58
+ it 'parses start_time' do
59
+ _when.start_time.should == Time.parse('2013-04-01 10:00:00 -0700')
60
+ end
61
+
62
+ it 'parses end_time' do
63
+ _when.end_time.should == Time.parse('2013-04-01 11:00:00 -0700')
64
+ end
65
+ end
66
+
67
+ it 'parses where' do
68
+ event.where.should == ''
69
+ end
70
+
71
+ describe :author do
72
+ let(:author) { event.author }
73
+
74
+ it 'parses email' do
75
+ author.email.should == "bobert@example.com"
76
+ end
77
+
78
+ it 'parses name' do
79
+ author.name.should == "Bobert Jones"
80
+ end
81
+ end
82
+
83
+ it 'parses transparency' do
84
+ event.transparency.should == 'opaque'
85
+ end
86
+
87
+ it 'parses visibility' do
88
+ event.visibility.should == 'default'
89
+ end
90
+ end
91
+
92
+ describe '.batch_create' do
93
+ let(:processed_events) { Event.batch_create(events) }
94
+
95
+ it 'parses events' do
96
+ processed_events.count.should == 10
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ include Gaah::Provisioning
3
+
4
+ describe User do
5
+ let(:xml) { fixture('provisioning.xml') }
6
+ let(:users) { Nokogiri::XML(xml)/:entry }
7
+ let(:user) { User.new(users.first) }
8
+
9
+ describe '#initialize' do
10
+ it 'parses ID' do
11
+ user.id.should == 'https://apps-apis.google.com/a/feeds/example.com/user/2.0/fry'
12
+ end
13
+
14
+ it 'parses suspended' do
15
+ user.suspended.should == false
16
+ end
17
+
18
+ it 'parses admin' do
19
+ user.admin.should == false
20
+ end
21
+
22
+ it 'parses title' do
23
+ user.title.should == 'fry'
24
+ end
25
+
26
+ it 'parses user_name' do
27
+ user.user_name.should == 'fry'
28
+ end
29
+
30
+ it 'parses name' do
31
+ user.name.should == 'Philip Fry'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,8 @@
1
+ require 'gaah'
2
+ include Gaah
3
+
4
+ SPEC_ROOT = File.dirname(__FILE__)
5
+
6
+ def fixture(name)
7
+ File.open(File.join(SPEC_ROOT, '/fixtures/', name)).read
8
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gaah
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hwan-Joon Choi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: oauth
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: queryparams
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.5'
69
+ description: Google Apps Marketplace API wrapper in ruby for Distill.
70
+ email:
71
+ - hc5duke@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .rspec
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - README.md
81
+ - gaah.gemspec
82
+ - lib/gaah.rb
83
+ - lib/gaah/api_client.rb
84
+ - lib/gaah/api_model.rb
85
+ - lib/gaah/base.rb
86
+ - lib/gaah/calendar/api.rb
87
+ - lib/gaah/calendar/event.rb
88
+ - lib/gaah/calendar/when.rb
89
+ - lib/gaah/calendar/who.rb
90
+ - lib/gaah/provisioning/api.rb
91
+ - lib/gaah/provisioning/user.rb
92
+ - lib/gaah/version.rb
93
+ - spec/fixtures/calendar.xml
94
+ - spec/fixtures/provisioning.xml
95
+ - spec/models/event_spec.rb
96
+ - spec/models/user_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: https://github.com/distill-inc/gaah
99
+ licenses: []
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.0.3
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Limited API Wrapper for Google Apps API.
121
+ test_files:
122
+ - spec/fixtures/calendar.xml
123
+ - spec/fixtures/provisioning.xml
124
+ - spec/models/event_spec.rb
125
+ - spec/models/user_spec.rb
126
+ - spec/spec_helper.rb