google_calendar 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0abc20ca5bb465a9042cad4e9941fbaa0397888
4
+ data.tar.gz: 21d702bee56ff9ae28582efc993f9765015b6ee7
5
+ SHA512:
6
+ metadata.gz: 1c881f0d97bab2f853c863f7e58b1d1385001b2b1b2bd101cb91f113d3ef5d599dc80b5bc53fd453b566e147ba24b14681364c405fe9a927e3fa25cc052dac68
7
+ data.tar.gz: 4c56297fdd70294df8b274651ad3bc28b3cf9e1025ccbb5fab8dfd3a046f7707797a44a94be0ef08fad496c2ebc3da80490d841a208057f80b0d2ed1e93a01c1
data/.gitignore CHANGED
@@ -1,19 +1,14 @@
1
1
  # rcov generated
2
2
  coverage
3
-
4
3
  # rdoc generated
5
4
  rdoc
6
-
7
5
  # yard generated
8
6
  doc
9
7
  .yardoc
10
-
11
8
  # bundler
12
9
  .bundle
13
-
14
10
  # jeweler generated
15
11
  pkg
16
-
17
12
  # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
13
  #
19
14
  # * Create a file at ~/.gitignore
@@ -25,17 +20,12 @@ pkg
25
20
  #
26
21
  # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
22
  #
28
-
29
23
  # For MacOS:
30
24
  #
31
25
  .DS_Store
32
-
33
-
34
26
  # For TextMate
35
27
  *.tmproj
36
28
  tmtags
37
-
38
-
39
29
  # For emacs:
40
30
  #*~
41
31
  #\#*
@@ -43,3 +33,5 @@ tmtags
43
33
  #
44
34
  # For vim:
45
35
  #*.swp
36
+ notes.md
37
+ test_harness.rb
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.2"
4
3
  - "1.9.3"
5
4
  - "2.0.0"
5
+ - "2.1.1"
6
6
  # uncomment this line if your project needs to run something other than `rake`:
7
7
  # script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -1,14 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Gems required to use google_calendar.
4
- gem "nokogiri", ">= 1.4.4"
5
- gem "addressable", ">= 2.2.2"
6
-
7
- # Gem development dependencies.
8
- group :development do
9
- gem "shoulda", ">= 0"
10
- gem "bundler", ">= 1.0.0"
11
- gem "mocha", ">= 0"
12
- gem "rake", "> 10"
13
- gem "rdoc", "> 3"
14
- end
3
+ # Using google_calendar to manage dependencies
4
+ gemspec
@@ -1,37 +1,94 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ google_calendar (0.4.0)
5
+ addressable (>= 2.2.2)
6
+ signet (>= 0.5.1)
7
+
1
8
  GEM
2
9
  remote: http://rubygems.org/
3
10
  specs:
4
- activesupport (3.2.13)
5
- i18n (= 0.6.1)
6
- multi_json (~> 1.0)
7
- addressable (2.3.4)
8
- i18n (0.6.1)
9
- json (1.8.0)
10
- metaclass (0.0.1)
11
- mini_portile (0.5.0)
12
- mocha (0.14.0)
11
+ addressable (2.3.6)
12
+ ansi (1.4.3)
13
+ builder (3.2.2)
14
+ celluloid (0.16.0)
15
+ timers (~> 4.0.0)
16
+ coderay (1.1.0)
17
+ docile (1.1.5)
18
+ faraday (0.9.0)
19
+ multipart-post (>= 1.2, < 3)
20
+ ffi (1.9.6)
21
+ formatador (0.2.5)
22
+ guard (2.8.2)
23
+ formatador (>= 0.2.4)
24
+ listen (~> 2.7)
25
+ lumberjack (~> 1.0)
26
+ pry (>= 0.9.12)
27
+ thor (>= 0.18.1)
28
+ guard-minitest (2.3.2)
29
+ guard (~> 2.0)
30
+ minitest (>= 3.0)
31
+ hitimes (1.2.2)
32
+ json (1.8.1)
33
+ jwt (1.0.0)
34
+ listen (2.8.0)
35
+ celluloid (>= 0.15.2)
36
+ rb-fsevent (>= 0.9.3)
37
+ rb-inotify (>= 0.9)
38
+ lumberjack (1.0.9)
39
+ metaclass (0.0.4)
40
+ method_source (0.8.2)
41
+ minitest (5.4.3)
42
+ minitest-reporters (1.0.7)
43
+ ansi
44
+ builder
45
+ minitest (>= 5.0)
46
+ ruby-progressbar
47
+ mocha (1.1.0)
13
48
  metaclass (~> 0.0.1)
14
- multi_json (1.7.7)
15
- nokogiri (1.6.0)
16
- mini_portile (~> 0.5.0)
17
- rake (10.0.4)
18
- rdoc (4.0.1)
49
+ multi_json (1.10.1)
50
+ multipart-post (2.0.0)
51
+ pry (0.10.1)
52
+ coderay (~> 1.1.0)
53
+ method_source (~> 0.8.1)
54
+ slop (~> 3.4)
55
+ rake (10.3.2)
56
+ rb-fsevent (0.9.4)
57
+ rb-inotify (0.9.5)
58
+ ffi (>= 0.5.0)
59
+ rdoc (4.1.2)
19
60
  json (~> 1.4)
20
- shoulda (3.5.0)
21
- shoulda-context (~> 1.0, >= 1.0.1)
22
- shoulda-matchers (>= 1.4.1, < 3.0)
23
- shoulda-context (1.1.2)
24
- shoulda-matchers (2.2.0)
25
- activesupport (>= 3.0.0)
61
+ ruby-progressbar (1.7.0)
62
+ shoulda-context (1.2.1)
63
+ signet (0.5.1)
64
+ addressable (>= 2.2.3)
65
+ faraday (>= 0.9.0.rc5)
66
+ jwt (>= 0.1.5)
67
+ multi_json (>= 1.0.0)
68
+ simplecov (0.9.1)
69
+ docile (~> 1.1.0)
70
+ multi_json (~> 1.0)
71
+ simplecov-html (~> 0.8.0)
72
+ simplecov-html (0.8.0)
73
+ slop (3.6.0)
74
+ terminal-notifier-guard (1.6.4)
75
+ thor (0.19.1)
76
+ timers (4.0.1)
77
+ hitimes
26
78
 
27
79
  PLATFORMS
28
80
  ruby
29
81
 
30
82
  DEPENDENCIES
31
- addressable (>= 2.2.2)
32
83
  bundler (>= 1.0.0)
84
+ google_calendar!
85
+ guard-minitest
86
+ minitest (~> 5.1)
87
+ minitest-reporters
33
88
  mocha
34
- nokogiri (>= 1.4.4)
35
89
  rake (> 10)
36
- rdoc (> 3)
37
- shoulda
90
+ rb-fsevent
91
+ rdoc (>= 3)
92
+ shoulda-context
93
+ simplecov (~> 0.9.0)
94
+ terminal-notifier-guard
@@ -0,0 +1,7 @@
1
+ guard 'minitest' do
2
+ # with Minitest::Unit
3
+ watch(%r|^test/(.*)\/?test_(.*)\.rb|)
4
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { 'test' }
5
+ watch(%r|^test/mocks(.*)([^/]+)\.json|) { 'test' }
6
+ watch(%r|^test/helper\.rb|) { 'test' }
7
+ end
@@ -3,20 +3,71 @@
3
3
 
4
4
  A fast lightweight and minimalist wrapper around the google calendar api.
5
5
 
6
- {<img src="https://travis-ci.org/northworld/google_calendar.png?branch=master" alt="Build Status" />}[https://travis-ci.org/northworld/google_calendar] {<img src="https://gemnasium.com/northworld/google_calendar.png" alt="Dependency Status" />}[https://gemnasium.com/northworld/google_calendar] {<img src="https://codeclimate.com/github/northworld/google_calendar.png" />}[https://codeclimate.com/github/northworld/google_calendar]
7
-
6
+ {<img src="https://travis-ci.org/northworld/google_calendar.png?branch=master" alt="Build Status" />}[https://travis-ci.org/northworld/google_calendar] {<img src="https://gemnasium.com/northworld/google_calendar.png" alt="Dependency Status" />}[https://gemnasium.com/northworld/google_calendar] {<img src="https://codeclimate.com/github/northworld/google_calendar/badges/gpa.svg" />}[https://codeclimate.com/github/northworld/google_calendar]
8
7
  == Install
9
8
  [sudo] gem install 'google_calendar'
10
9
 
11
- Note: Google requests that you set the name of your application so they can better monitor the use of their services.
10
+ == Setup
11
+
12
+ Obtain a Client ID and Secret from Google
13
+
14
+ Go to the {Google Developers Console}[https://console.developers.google.com/].
15
+ Select a project, or create a new one.
16
+ In the sidebar on the left, expand APIs & auth. Next, click APIs. In the list of APIs, make sure the status is ON for the Calendar API.
17
+ In the sidebar on the left, select Credentials.
18
+ In either case, you end up on the Credentials page and can create your project's credentials from here.
19
+
20
+ If you haven't done so already, create your OAuth 2.0 credentials by clicking Create new Client ID under the OAuth heading. Next, look for your application's client ID and client secret in the relevant table. You may also create and edit redirect URIs from this page.
21
+
22
+ Take note of the Client ID as you'll need to add it to your code later.
23
+
24
+ === How to find your calendar ID
25
+ Visit Google calendar in your web browser.
26
+ In the calendar list on the left, click the down-arrow button next to the appropriate calendar, then select Calendar settings.
27
+ In the Calendar Address section, locate the Calendar ID listed next to the XML, ICAL and HTML buttons.
28
+ Copy the Calendar ID.
12
29
 
13
30
  == Usage
14
31
  require 'rubygems'
15
32
  require 'google_calendar'
16
33
 
17
- cal = Google::Calendar.new(:username => 'some.person@gmail.com',
18
- :password => 'super-secret',
19
- :app_name => 'mycompany.com-googlecalendar-integration')
34
+ YOUR_CLIENT_ID = ""
35
+ YOUR_SECRET = ""
36
+ YOUR_CALENDAR_ID = ""
37
+
38
+ # Create an instance of the calendar.
39
+ cal = Google::Calendar.new(:client_id => YOUR_CLIENT_ID,
40
+ :client_secret => YOUR_SECRET,
41
+ :calendar => YOUR_CALENDAR_ID,
42
+ :redirect_url => "urn:ietf:wg:oauth:2.0:oob" # this is what Google uses for 'applications'
43
+ )
44
+
45
+ puts "Do you already have a refresh token? (y/n)"
46
+ has_token = $stdin.gets.chomp
47
+
48
+ if has_token.downcase != 'y'
49
+
50
+ # A user needs to approve access in order to work with their calendars.
51
+ puts "Visit the following web page in your browser and approve access."
52
+ puts cal.authorize_url
53
+ puts "\nCopy the code that Google returned and paste it here:"
54
+
55
+ # Pass the ONE TIME USE access code here to login and get a refresh token that you can use for access from now on.
56
+ refresh_token = cal.login_with_auth_code( $stdin.gets.chomp )
57
+
58
+ puts "\nMake sure you SAVE YOUR REFRESH TOKEN so you don't have to prompt the user to approve access again."
59
+ puts "your refresh token is:\n\t#{refresh_token}\n"
60
+ puts "Press return to continue"
61
+ $stdin.gets.chomp
62
+
63
+ else
64
+ puts "Enter your refresh token"
65
+ refresh_token = $stdin.gets.chomp
66
+ cal.login_with_refresh_token(refresh_token)
67
+
68
+ # Note: You can also pass your refresh_token to the constructor and it will login at that time.
69
+
70
+ end
20
71
 
21
72
  event = cal.create_event do |e|
22
73
  e.title = 'A Cool Event'
@@ -37,8 +88,9 @@ Note: Google requests that you set the name of your application so they can bett
37
88
  puts cal.events
38
89
 
39
90
  # Query events
40
- puts cal.find_events('my search string')
91
+ puts cal.find_events('your search string')
41
92
 
93
+ This sample code is located in readme_code.rb in the root folder.
42
94
 
43
95
  Note: This is not a complete implementation of the calendar api, it just includes the features we needed to support our internal calendar integration.
44
96
 
@@ -54,4 +106,4 @@ Note: This is not a complete implementation of the calendar api, it just include
54
106
 
55
107
  == Copyright
56
108
 
57
- Copyright (c) 2010 Steve Zich. See LICENSE.txt for further details.
109
+ Copyright (c) 2010 Steve Zich. See LICENSE.txt for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -2,8 +2,8 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "google_calendar"
5
- s.version = "0.3.1"
6
- s.date = "2013-08-23"
5
+ s.version = "0.4.0"
6
+ s.date = "2014-11-17"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
 
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.email = "steve.zich@gmail.com"
12
12
 
13
13
  s.summary = "A lightweight google calendar API wrapper"
14
- s.description = "A minimal wrapper around the google calendar API, which uses nokogiri for fast parsing."
14
+ s.description = "A minimal wrapper around the google calendar API"
15
15
  s.homepage = "http://github.com/northworld/google_calendar"
16
16
  s.licenses = ["MIT"]
17
17
 
@@ -26,29 +26,19 @@ Gem::Specification.new do |s|
26
26
  s.require_paths = ["lib"]
27
27
  s.rubygems_version = "1.8.24"
28
28
 
29
-
30
- if s.respond_to? :specification_version then
31
- s.specification_version = 3
32
-
33
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
34
- s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.4"])
35
- s.add_runtime_dependency(%q<addressable>, [">= 2.2.2"])
36
- s.add_development_dependency(%q<shoulda>, [">= 0"])
37
- s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
38
- s.add_development_dependency(%q<mocha>, [">= 0"])
39
- else
40
- s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
41
- s.add_dependency(%q<addressable>, [">= 2.2.2"])
42
- s.add_dependency(%q<shoulda>, [">= 0"])
43
- s.add_dependency(%q<bundler>, [">= 1.0.0"])
44
- s.add_dependency(%q<mocha>, [">= 0"])
45
- end
46
- else
47
- s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
48
- s.add_dependency(%q<addressable>, [">= 2.2.2"])
49
- s.add_dependency(%q<shoulda>, [">= 0"])
50
- s.add_dependency(%q<bundler>, [">= 1.0.0"])
51
- s.add_dependency(%q<mocha>, [">= 0"])
52
- end
53
- end
54
-
29
+ s.add_runtime_dependency(%q<signet>, [">= 0.5.1"])
30
+ s.add_runtime_dependency(%q<addressable>, [">= 2.2.2"])
31
+
32
+ s.add_development_dependency(%q<terminal-notifier-guard>, [">= 0"])
33
+ s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
34
+ s.add_development_dependency(%q<guard-minitest>, [">= 0"])
35
+ s.add_development_dependency(%q<minitest>, ["~> 5.1"])
36
+ s.add_development_dependency(%q<minitest-reporters>, [">=0"])
37
+ s.add_development_dependency(%q<shoulda-context>, [">= 0"])
38
+ s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
39
+ s.add_development_dependency(%q<mocha>, [">= 0"])
40
+ s.add_development_dependency(%q<rake>, ["> 10"])
41
+ s.add_development_dependency(%q<rdoc>, [">= 3"])
42
+ s.add_development_dependency(%q<simplecov>, ["~> 0.9.0"])
43
+
44
+ end
@@ -1,102 +1,157 @@
1
- require 'nokogiri'
2
-
3
1
  module Google
4
2
 
3
+ #
5
4
  # Calendar is the main object you use to interact with events.
6
5
  # use it to find, create, update and delete them.
7
6
  #
8
7
  class Calendar
9
8
 
10
- # Setup and connect to the specified google calendar.
9
+ attr_reader :connection
10
+
11
+ #
12
+ # Setup and connect to the specified Google Calendar.
11
13
  # the +params+ paramater accepts
12
- # * :username => the username of the specified calendar (i.e. some.guy@gmail.com)
13
- # * :password => the password for the specified user (i.e. super-secret)
14
- # * :calendar => the name of the calendar you would like to work with (optional, defaults to the calendar the user setup as their default one.)
15
- # * :app_name => the name of your application (defaults to 'northworld.com-googlecalendar-integration')
16
- # * :auth_url => the base url that is used to connect to google (defaults to 'https://www.google.com/accounts/ClientLogin')
14
+ # * :client_id => the client ID that you received from Google after registering your application with them (https://console.developers.google.com/). REQUIRED
15
+ # * :client_secret => the client secret you received from Google after registering your application with them. REQUIRED
16
+ # * :redirect_url => the url where your users will be redirected to after they have successfully permitted access to their calendars. Use 'urn:ietf:wg:oauth:2.0:oob' if you are using an 'application'" REQUIRED
17
+ # * :calendar_id => the id of the calendar you would like to work with (see Readme.rdoc for instructions on how to find yours)
18
+ # * :refresh_token => if a user has already given you access to their calendars, you can specify their refresh token here and you will be 'logged on' automatically (i.e. they don't need to authorize access again). OPTIONAL
17
19
  #
18
- # After creating an instace you are immediatly logged on and ready to go.
20
+ # See Readme.rdoc or readme_code.rb for an explication on the OAuth2 authorization process.
19
21
  #
20
- # ==== Examples
21
- # # Use the default calendar
22
- # Calendar.new(:username => 'some.guy@gmail.com', :password => 'ilovepie!')
22
+ # ==== Example
23
+ # Google::Calendar.new(:client_id => YOUR_CLIENT_ID,
24
+ # :client_secret => YOUR_SECRET,
25
+ # :calendar => YOUR_CALENDAR_ID,
26
+ # :redirect_url => "urn:ietf:wg:oauth:2.0:oob" # this is what Google uses for 'applications'
27
+ # )
23
28
  #
24
- # # Specify the calendar
25
- # Calendar.new(:username => 'some.guy@gmail.com', :password => 'ilovepie!', :calendar => 'my.company@gmail.com')
29
+ def initialize(params={})
30
+ options = {
31
+ :client_id => params[:client_id],
32
+ :client_secret => params[:client_secret],
33
+ :refresh_token => params[:refresh_token],
34
+ :redirect_url => params[:redirect_url],
35
+ :calendar_id => params[:calendar]
36
+ }
37
+
38
+ @connection = Connection.new options
39
+ end
40
+
26
41
  #
27
- # # Specify the app_name
28
- # Calendar.new(:username => 'some.guy@gmail.com', :password => 'ilovepie!', :app_name => 'mycompany.com-googlecalendar-integration')
42
+ # The URL you need to send a user in order to let them grant you access to their calendars.
29
43
  #
44
+ def authorize_url
45
+ @connection.authorize_url
46
+ end
30
47
 
31
- # Calendar attributes
32
- attr_accessor :username, :password, :app_name, :auth_url, :connection, :calendar
48
+ #
49
+ # The single use auth code that google uses during the auth process.
50
+ #
51
+ def auth_code
52
+ @connection.auth_code
53
+ end
33
54
 
34
- def initialize(params)
35
- self.username = params[:username]
36
- self.password = params[:password]
37
- self.calendar = params[:calendar]
38
- self.app_name = params[:app_name]
39
- self.auth_url = params[:auth_url]
55
+ #
56
+ # The current access token. Used during a session, typically expires in a hour.
57
+ #
58
+ def access_token
59
+ @connection.access_token
60
+ end
40
61
 
41
- self.connection = Connection.new(:username => username,
42
- :password => password,
43
- :app_name => app_name,
44
- :auth_url => auth_url)
62
+ #
63
+ # The refresh token is used to obtain a new access token. It remains valid until a user revokes access.
64
+ #
65
+ def refresh_token
66
+ @connection.refresh_token
45
67
  end
46
68
 
69
+ #
70
+ # Convenience method used to streamline the process of logging in with a auth code.
71
+ #
72
+ def login_with_auth_code(auth_code)
73
+ @connection.login_with_auth_code(auth_code)
74
+ end
75
+
76
+ #
77
+ # Convenience method used to streamline the process of logging in with a refresh token.
78
+ #
79
+ def login_with_refresh_token(refresh_token)
80
+ @connection.login_with_refresh_token(refresh_token)
81
+ end
82
+
83
+ #
47
84
  # Find all of the events associated with this calendar.
48
85
  # Returns:
49
- # nil if nothing found.
50
- # a single event if only one found.
86
+ # an empty array if nothing found.
87
+ # an array with one element if only one found.
51
88
  # an array of events if many found.
52
89
  #
53
90
  def events
54
91
  event_lookup()
55
92
  end
56
93
 
57
- # This is equivalnt to running a search in
58
- # the google calendar web application. Google does not provide a way to easily specify
59
- # what attributes you would like to search (i.e. title), by default it searches everything.
94
+ #
95
+ # This is equivalent to running a search in the Google calendar web application.
96
+ # Google does not provide a way to specify what attributes you would like to
97
+ # search (i.e. title), by default it searches everything.
60
98
  # If you would like to find specific attribute value (i.e. title=Picnic), run a query
61
99
  # and parse the results.
62
100
  # Returns:
63
- # nil if nothing found.
64
- # a single event if only one found.
101
+ # an empty array if nothing found.
102
+ # an array with one element if only one found.
65
103
  # an array of events if many found.
66
104
  #
67
105
  def find_events(query)
68
106
  event_lookup("?q=#{query}")
69
107
  end
70
108
 
109
+ #
71
110
  # Find all of the events associated with this calendar that start in the given time frame.
72
111
  # The lower bound is inclusive, whereas the upper bound is exclusive.
73
112
  # Events that overlap the range are included.
113
+ #
114
+ # the +options+ parameter accepts
115
+ # :max_results => the maximum number of results to return defaults to 25 the largest number Google accepts is 2500
116
+ # :order_by => how you would like the results ordered, can be either 'startTime' or 'updated'. Defaults to 'startTime'. Note: it must be 'updated' if expand_recurring_events is set to false.
117
+ # :expand_recurring_events => When set to true each instance of a recurring event is returned. Defaults to true.
118
+ #
74
119
  # Returns:
75
- # nil if nothing found.
76
- # a single event if only one found.
120
+ # an empty array if nothing found.
121
+ # an array with one element if only one found.
77
122
  # an array of events if many found.
78
123
  #
79
- def find_events_in_range(start_min, start_max,options = {})
80
- options[:max_results] ||= 25
81
- options[:order_by] ||= 'lastmodified' # other option is 'starttime'
82
- formatted_start_min = start_min.strftime("%Y-%m-%dT%H:%M:%S")
83
- formatted_start_max = start_max.strftime("%Y-%m-%dT%H:%M:%S")
84
- query = "?start-min=#{formatted_start_min}&start-max=#{formatted_start_max}&recurrence-expansion-start=#{formatted_start_min}&recurrence-expansion-end=#{formatted_start_max}"
85
- query = "#{query}&orderby=#{options[:order_by]}&max-results=#{options[:max_results]}"
124
+ def find_events_in_range(start_min, start_max, options = {})
125
+ formatted_start_min = encode_time(start_min)
126
+ formatted_start_max = encode_time(start_max)
127
+ query = "?timeMin=#{formatted_start_min}&timeMax=#{formatted_start_max}#{parse_options(options)}"
86
128
  event_lookup(query)
87
129
  end
88
130
 
131
+ #
132
+ # Find all events that are occurring at the time the method is run or later.
133
+ #
134
+ # the +options+ parameter accepts
135
+ # :max_results => the maximum number of results to return defaults to 25 the largest number Google accepts is 2500
136
+ # :order_by => how you would like the results ordered, can be either 'startTime' or 'updated'. Defaults to 'startTime'. Note: it must be 'updated' if expand_recurring_events is set to false.
137
+ # :expand_recurring_events => When set to true each instance of a recurring event is returned. Defaults to true.
138
+ #
139
+ # Returns:
140
+ # an empty array if nothing found.
141
+ # an array with one element if only one found.
142
+ # an array of events if many found.
143
+ #
89
144
  def find_future_events(options={})
90
- options[:max_results] ||= 25
91
- options[:order_by] ||= 'lastmodified' # other option is 'starttime'
92
- query = "?futureevents=true&orderby=#{options[:order_by]}&max-results=#{options[:max_results]}"
145
+ formatted_start_min = encode_time(DateTime.now)
146
+ query = "?timeMin=#{formatted_start_min}#{parse_options(options)}"
93
147
  event_lookup(query)
94
148
  end
95
149
 
150
+ #
96
151
  # Attempts to find the event specified by the id
97
152
  # Returns:
98
- # nil if nothing found.
99
- # a single event if only one found.
153
+ # an empty array if nothing found.
154
+ # an array with one element if only one found.
100
155
  # an array of events if many found.
101
156
  #
102
157
  def find_event_by_id(id)
@@ -104,8 +159,9 @@ module Google
104
159
  event_lookup("/#{id}")
105
160
  end
106
161
 
107
- # Creates a new event and immediatly saves it.
108
- # returns the event
162
+ #
163
+ # Creates a new event and immediately saves it.
164
+ # Returns the event
109
165
  #
110
166
  # ==== Examples
111
167
  # # Use a block
@@ -114,7 +170,7 @@ module Google
114
170
  # e.where = "Room 101"
115
171
  # end
116
172
  #
117
- # # Don't use a block (need to call save maunally)
173
+ # # Don't use a block (need to call save manually)
118
174
  # event = cal.create_event
119
175
  # event.title = "A New Event"
120
176
  # event.where = "Room 101"
@@ -124,108 +180,83 @@ module Google
124
180
  setup_event(Event.new, &blk)
125
181
  end
126
182
 
127
- # looks for the spedified event id.
183
+ #
184
+ # Looks for the specified event id.
128
185
  # If it is found it, updates it's vales and returns it.
129
186
  # If the event is no longer on the server it creates a new one with the specified values.
130
187
  # Works like the create_event method.
131
188
  #
132
189
  def find_or_create_event_by_id(id, &blk)
133
- setup_event(find_event_by_id(id) || Event.new, &blk)
190
+ setup_event(find_event_by_id(id)[0] || Event.new, &blk)
134
191
  end
135
192
 
193
+ #
136
194
  # Saves the specified event.
137
195
  # This is a callback used by the Event class.
138
196
  #
139
197
  def save_event(event)
140
- method = (event.id == nil || event.id == '') ? :post : :put
141
- query_string = (method == :put) ? "/#{event.id}" : ''
142
- @connection.send(Addressable::URI.parse(events_url + query_string), method, event.to_xml)
198
+ method = event.new_event? ? :post : :put
199
+ body = event.use_quickadd? ? nil : event.to_json
200
+
201
+ query_string = if event.use_quickadd?
202
+ "/quickAdd?text=#{ Addressable::URI.encode_component(event.quickadd)}"
203
+ elsif event.new_event?
204
+ ''
205
+ else # update existing event.
206
+ "/#{event.id}"
207
+ end
208
+
209
+ @connection.send_events_request(query_string, method, body)
143
210
  end
144
211
 
212
+ #
145
213
  # Deletes the specified event.
146
214
  # This is a callback used by the Event class.
147
215
  #
148
216
  def delete_event(event)
149
- @connection.send(Addressable::URI.parse(events_url + "/#{event.id}"), :delete)
217
+ @connection.send_events_request("/#{event.id}", :delete)
150
218
  end
151
219
 
152
- # Explicitly reload the connection to google calendar
220
+ protected
221
+
153
222
  #
154
- # Examples
155
- # class User
156
- # def calendar
157
- # @calendar ||= Google::Calendar.new :username => "foo@gmail.com", :password => "bar"
158
- # end
159
- # end
160
- # user = User.new
161
- # 2.times { user.calendar } #only one HTTP authentication request to google
162
- # user.calendar.reload #new HTTP authentication request to google
223
+ # Utility method used to centralize the parsing of common query parameters.
163
224
  #
164
- # Returns Google::Calendar instance
165
- def reload
166
- self.connection = Connection.new(:username => username,
167
- :password => password,
168
- :app_name => app_name,
169
- :auth_url => auth_url)
170
- self
171
- end
172
-
173
- def display_color
174
- calendar_data.xpath("//entry[title='#{@calendar}']/color/@value").first.value
225
+ def parse_options(options) # :nodoc
226
+ options[:max_results] ||= 25
227
+ options[:order_by] ||= 'startTime' # other option is 'updated'
228
+ options[:expand_recurring_events] ||= true
229
+ "&orderBy=#{options[:order_by]}&maxResults=#{options[:max_results]}&singleEvents=#{options[:expand_recurring_events]}"
175
230
  end
176
231
 
177
- protected
232
+ #
233
+ # Utility method to centralize time encoding.
234
+ #
235
+ def encode_time(time) #:nodoc:
236
+ Addressable::URI.encode_component(time.strftime("%FT%T%:z"), Addressable::URI::CharacterClasses::UNRESERVED)
237
+ end
178
238
 
239
+ #
240
+ # Utility method used to centralize event lookup.
241
+ #
179
242
  def event_lookup(query_string = '') #:nodoc:
180
243
  begin
181
- response = @connection.send(Addressable::URI.parse(events_url + query_string), :get)
182
- events = Event.build_from_google_feed(response.body, self)
183
- events.length > 1 ? events : events[0]
244
+ response = @connection.send_events_request(query_string, :get)
245
+ events = Event.build_from_google_feed( JSON.parse(response.body) , self) || []
246
+ return events if events.empty?
247
+ events.length > 1 ? events : [events[0]]
184
248
  rescue Google::HTTPNotFound
185
249
  return nil
186
250
  end
187
251
  end
188
252
 
189
- def calendar_id #:nodoc:
190
- @calendar || "default"
191
- end
192
-
193
- # Initialize the events URL given String attribute @calendar value :
194
253
  #
195
- # contains a '@' : construct the feed url with @calendar.
196
- # does not contain '@' : fetch user's all calendars (http://code.google.com/apis/calendar/data/2.0/developers_guide_protocol.html#RetrievingAllCalendars)
197
- # and return feed url matching @calendar.
198
- # nil : default feed url.
254
+ # Utility method used to centralize event setup
199
255
  #
200
- # Returns:
201
- # a String url for a calendar feeds.
202
- # raise a Google::InvalidCalendar error if @calendar is invalid.
203
- #
204
- def events_url
205
- if @calendar and !@calendar.include?("@")
206
- link = calendar_data.xpath("//entry[title='#{@calendar}']/link[contains(@rel, '#eventFeed')]/@href").to_s
207
- link.empty? ? raise(Google::InvalidCalendar) : link
208
- else
209
- "https://www.google.com/calendar/feeds/#{calendar_id}/private/full"
210
- end
211
- end
212
-
213
- def calendar_data
214
- unless @calendar_data
215
- xml = @connection.send(Addressable::URI.parse("https://www.google.com/calendar/feeds/default/allcalendars/full"), :get)
216
- @calendar_data = Nokogiri::XML(xml.body)
217
- @calendar_data.remove_namespaces!
218
- end
219
- @calendar_data
220
- end
221
-
222
256
  def setup_event(event) #:nodoc:
223
257
  event.calendar = self
224
258
  if block_given?
225
- yield(event)
226
- event.title = event.title.encode(:xml => :text) if event.title
227
- event.content = event.content.encode(:xml => :text) if event.content
228
- event.where = event.where.encode(:xml => :text) if event.where
259
+ yield(event)
229
260
  end
230
261
  event.save
231
262
  event