gcal_mapper 0.1.1
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/.gitignore +32 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +20 -0
- data/Guardfile +19 -0
- data/LICENSE +22 -0
- data/README.md +370 -0
- data/Rakefile +32 -0
- data/bin/ci/file/auth.yaml +7 -0
- data/bin/ci/file/bad_yaml.yaml +0 -0
- data/bin/ci/file/config.yaml +8 -0
- data/bin/ci/file/privatekey.p12 +0 -0
- data/bin/ci/travis_build.sh +4 -0
- data/bin/ci/vcr/GcalMapper_Authentification/access_token_should_exist_with_assertion_auth.yml +49 -0
- data/bin/ci/vcr/GcalMapper_Authentification/should_be_fasle_if_bad_client_email_is_given.yml +47 -0
- data/bin/ci/vcr/GcalMapper_Authentification_Assertion/should_have_access_token_attribute.yml +49 -0
- data/bin/ci/vcr/GcalMapper_Authentification_Assertion/should_have_refresh_token_attribute.yml +49 -0
- data/bin/ci/vcr/GcalMapper_Calendar/should_get_the_calendar_list.yml +190 -0
- data/bin/ci/vcr/GcalMapper_Calendar/should_get_the_events_list.yml +45 -0
- data/bin/ci/vcr/GcalMapper_Calendar/should_raise_error_if_the_calendar_id_isn_t_accessible.yml +56 -0
- data/bin/ci/vcr/GcalMapper_Calendar/should_raise_error_if_the_token_is_bad.yml +60 -0
- data/bin/ci/vcr/GcalMapper_Mapper/should_save_all_events.yml +232 -0
- data/bin/ci/vcr/GcalMapper_Mapper/should_save_events_only_once.yml +232 -0
- data/bin/gcal-mapper +108 -0
- data/gcal_mapper.gemspec +25 -0
- data/lib/gcal_mapper.rb +15 -0
- data/lib/gcal_mapper/authentification.rb +57 -0
- data/lib/gcal_mapper/authentification/assertion.rb +110 -0
- data/lib/gcal_mapper/authentification/base.rb +20 -0
- data/lib/gcal_mapper/authentification/oauth2.rb +68 -0
- data/lib/gcal_mapper/calendar.rb +51 -0
- data/lib/gcal_mapper/configuration.rb +23 -0
- data/lib/gcal_mapper/errors.rb +40 -0
- data/lib/gcal_mapper/mapper.rb +76 -0
- data/lib/gcal_mapper/mapper/active_record.rb +74 -0
- data/lib/gcal_mapper/mapper/dsl.rb +57 -0
- data/lib/gcal_mapper/mapper/simple.rb +97 -0
- data/lib/gcal_mapper/railtie.rb +8 -0
- data/lib/gcal_mapper/rest_request.rb +73 -0
- data/lib/gcal_mapper/sync.rb +159 -0
- data/lib/gcal_mapper/version.rb +4 -0
- data/spec/authentification/assertion_spec.rb +15 -0
- data/spec/authentification/base_spec.rb +18 -0
- data/spec/authentification/oauth2_spec.rb +15 -0
- data/spec/authentification_spec.rb +34 -0
- data/spec/calendar_spec.rb +33 -0
- data/spec/gcal_mapper_spec.rb +5 -0
- data/spec/mapper/active_record_spec.rb +46 -0
- data/spec/mapper/dsl_spec.rb +31 -0
- data/spec/mapper/simple_spec.rb +48 -0
- data/spec/mapper_spec.rb +32 -0
- data/spec/rest_request_spec.rb +5 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/models/event.rb +25 -0
- data/spec/support/models/event_jeu.rb +22 -0
- data/spec/support/schema.rb +28 -0
- data/spec/sync_spec.rb +28 -0
- metadata +200 -0
data/bin/gcal-mapper
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
bin_dir = File.expand_path("..", __FILE__)
|
3
|
+
lib_dir = File.expand_path("../lib", bin_dir)
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(lib_dir)
|
6
|
+
$LOAD_PATH.uniq!
|
7
|
+
|
8
|
+
require 'launchy'
|
9
|
+
require 'socket'
|
10
|
+
require 'gcal_mapper'
|
11
|
+
|
12
|
+
OAUTH_SERVER_PORT = 12736
|
13
|
+
|
14
|
+
options = {}
|
15
|
+
|
16
|
+
opt_parser = OptionParser.new do |opt|
|
17
|
+
|
18
|
+
opt.on('--client_id CLIENT_ID', 'your client id') do |client_id|
|
19
|
+
options[:client_id] = client_id
|
20
|
+
end
|
21
|
+
|
22
|
+
opt.on('--client_secret CLIENT_SECRET', 'your client secret') do |client_secret|
|
23
|
+
options[:client_secret] = client_secret
|
24
|
+
end
|
25
|
+
|
26
|
+
opt.on('-f FILE', '--file FILE', 'the file to save credentials') do |file|
|
27
|
+
options[:file] = file
|
28
|
+
end
|
29
|
+
|
30
|
+
opt.on('--scope SCOPE', 'the scope to ask authorization for') do |scope|
|
31
|
+
options[:scope] = scope
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
opt_parser.parse!
|
38
|
+
options[:scope] = 'https://www.googleapis.com/auth/calendar' if options[:scope].nil?
|
39
|
+
options[:file] = '~/google_auth.yaml' if options[:file].nil?
|
40
|
+
|
41
|
+
authorize_url = 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto&'
|
42
|
+
authorize_url += 'client_id=' + options[:client_id] + '&'
|
43
|
+
authorize_url += 'redirect_uri=http://localhost:' + OAUTH_SERVER_PORT.to_s + '/&response_type=code&'
|
44
|
+
authorize_url += 'scope=' + options[:scope]
|
45
|
+
|
46
|
+
# open web browser with the authorisation page
|
47
|
+
Launchy.open(authorize_url)
|
48
|
+
|
49
|
+
msg = ''
|
50
|
+
|
51
|
+
# tcp server to receive the response and close the window
|
52
|
+
server = TCPServer.new('0.0.0.0', OAUTH_SERVER_PORT)
|
53
|
+
loop do
|
54
|
+
Thread.new(server.accept) do |client|
|
55
|
+
msg = client.readline
|
56
|
+
body = "<html><head><script>function closeWindow() {window.open('', '_self', '');window.close();} setTimeout(closeWindow, 10);</script></head><body>You may close this window.</body></html>\r\n"
|
57
|
+
headers = [
|
58
|
+
"",
|
59
|
+
"HTTP/1.1 200 OK",
|
60
|
+
"Date: Fri, 30 Sep 2011 08:11:27 GMT",
|
61
|
+
"Server: TCP socket test",
|
62
|
+
"Content-Type: text/html; charset=iso-8859-1",
|
63
|
+
"Content-Length: #{body.length}\r\n\r\n"].join("\r\n")
|
64
|
+
|
65
|
+
client.write headers
|
66
|
+
client.write body
|
67
|
+
|
68
|
+
client.close
|
69
|
+
end
|
70
|
+
|
71
|
+
sleep(1.0/24.0)
|
72
|
+
break if msg.include?('code')
|
73
|
+
end
|
74
|
+
|
75
|
+
# keep just the authorization code
|
76
|
+
msg.slice!('GET /?code=')
|
77
|
+
msg.chop!
|
78
|
+
msg.slice!(' HTTP/1.1')
|
79
|
+
|
80
|
+
# form rest request and send it
|
81
|
+
url = 'https://accounts.google.com/o/oauth2/token'
|
82
|
+
data = {
|
83
|
+
'code' => msg,
|
84
|
+
'grant_type'=> 'authorization_code',
|
85
|
+
'redirect_uri' => 'http://localhost:' + OAUTH_SERVER_PORT.to_s + '/',
|
86
|
+
'client_id' => options[:client_id],
|
87
|
+
'client_secret' => options[:client_secret]
|
88
|
+
}
|
89
|
+
opts = {
|
90
|
+
:method => :post,
|
91
|
+
:headers => {'Content-Type' => 'application/x-www-form-urlencoded'},
|
92
|
+
:parameters => data
|
93
|
+
}
|
94
|
+
req = GcalMapper::RestRequest.new(url, opts)
|
95
|
+
response = req.execute
|
96
|
+
|
97
|
+
# store credentials in yaml file
|
98
|
+
config = {
|
99
|
+
'mechanism' => 'oauth_2',
|
100
|
+
'scope' => options[:scope],
|
101
|
+
'client_id' => options[:client_id],
|
102
|
+
'client_secret' => options[:client_secret],
|
103
|
+
'access_token' => response['access_token'],
|
104
|
+
'refresh_token' => response['refresh_token']
|
105
|
+
}
|
106
|
+
config_file = File.expand_path(options[:file])
|
107
|
+
open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
|
108
|
+
exit(0)
|
data/gcal_mapper.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/gcal_mapper/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['Néville Dubuis']
|
6
|
+
gem.email = ['neville.dubuis@liquid-concept.ch']
|
7
|
+
gem.description = %q{A library to map Google Calendar events with an ORM}
|
8
|
+
gem.summary = %q{A library to map Google Calendar events with an ORM}
|
9
|
+
gem.homepage = 'http://rubygems.org/gems/gcal_mapper'
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = ['gcal-mapper']
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = 'gcal_mapper'
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.version = GcalMapper::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'launchy'
|
19
|
+
|
20
|
+
gem.add_development_dependency 'activerecord'
|
21
|
+
gem.add_development_dependency 'rspec', '>= 2.0'
|
22
|
+
gem.add_development_dependency 'vcr'
|
23
|
+
gem.add_development_dependency 'fakeweb'
|
24
|
+
|
25
|
+
end
|
data/lib/gcal_mapper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gcal_mapper/version'
|
2
|
+
require 'gcal_mapper/rest_request'
|
3
|
+
require 'gcal_mapper/authentification'
|
4
|
+
require 'gcal_mapper/calendar'
|
5
|
+
require 'gcal_mapper/errors'
|
6
|
+
require 'gcal_mapper/sync'
|
7
|
+
require 'gcal_mapper/mapper'
|
8
|
+
require 'gcal_mapper/configuration'
|
9
|
+
require 'gcal_mapper/railtie' if defined?(Rails)
|
10
|
+
|
11
|
+
#
|
12
|
+
# A library to map Google Calendar events with an ORM.
|
13
|
+
#
|
14
|
+
module GcalMapper
|
15
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'gcal_mapper/authentification/assertion'
|
2
|
+
require 'gcal_mapper/authentification/oauth2'
|
3
|
+
|
4
|
+
module GcalMapper
|
5
|
+
#
|
6
|
+
# Abstract which type of authentification is required
|
7
|
+
#
|
8
|
+
class Authentification
|
9
|
+
REQUEST_URL = 'https://accounts.google.com/o/oauth2/token' # url where to request to authentificate
|
10
|
+
|
11
|
+
attr_reader :file # file that is needed for authentification
|
12
|
+
attr_reader :client_email # for assertion authentification
|
13
|
+
attr_reader :password # password for the p12 file
|
14
|
+
|
15
|
+
# intialize client info needed for connection to Oauth2.
|
16
|
+
#
|
17
|
+
# @param [String] file path to the yaml or p12 file
|
18
|
+
# @param [String] client_email email from the api_consol (service account only)
|
19
|
+
# @param [String] user_email email from the impersonated user (service account only)
|
20
|
+
# @param [String] password p12 key password (service account only)
|
21
|
+
def initialize(file, client_email=nil, user_email=nil, password='notasecret')
|
22
|
+
@file = File.expand_path(file)
|
23
|
+
@client_email = client_email
|
24
|
+
@user_email = user_email
|
25
|
+
@password = password
|
26
|
+
raise GcalMapper::AuthFileError if !File.exist?(@file)
|
27
|
+
end
|
28
|
+
|
29
|
+
# do the authentification for one of the right authentification method
|
30
|
+
#
|
31
|
+
# @return [Bool] true if instantiation ok
|
32
|
+
def authenticate
|
33
|
+
if client_email==nil
|
34
|
+
@auth = Authentification::Oauth2.new(@file)
|
35
|
+
else
|
36
|
+
@auth = Authentification::Assertion.new(@file, @client_email, @user_email, @password)
|
37
|
+
end
|
38
|
+
|
39
|
+
!access_token.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Gives the access token
|
43
|
+
#
|
44
|
+
# @return [string] the access token
|
45
|
+
def access_token
|
46
|
+
@auth.access_token
|
47
|
+
end
|
48
|
+
|
49
|
+
# refresh the access token
|
50
|
+
#
|
51
|
+
# @return [string] the access token
|
52
|
+
def refresh_token
|
53
|
+
@auth.refresh_token
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'gcal_mapper/authentification/base'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module GcalMapper
|
5
|
+
class Authentification
|
6
|
+
#
|
7
|
+
# make the authentification for service account and request data from google calendar.
|
8
|
+
#
|
9
|
+
class Assertion < Authentification::Base
|
10
|
+
ASSERTION_SCOPE = 'https://www.google.com/calendar/feeds/' # scope for assertion
|
11
|
+
JWT_HEADER = {'alg' => 'RS256', 'typ' => 'JWT'} # header of the jwt to send
|
12
|
+
ASSERTION_TYPE = 'http://oauth.net/grant_type/jwt/1.0/bearer' # url to specify which type of assertion
|
13
|
+
|
14
|
+
|
15
|
+
attr_accessor :client_email # the email given by google for the service account
|
16
|
+
attr_accessor :user_email # the email of the user to impersonate
|
17
|
+
|
18
|
+
# New object
|
19
|
+
#
|
20
|
+
# @param [String] p12_file the path to the p12 key file
|
21
|
+
# @param [String] client_email email from the api_consol
|
22
|
+
# @param [String] user_email email from the impersonated user
|
23
|
+
# @param [String] password p12 key password
|
24
|
+
def initialize(p12_file, client_email, user_email, password)
|
25
|
+
@client_email = client_email
|
26
|
+
@p12_file = p12_file
|
27
|
+
@user_email = user_email
|
28
|
+
@password = password
|
29
|
+
request_token
|
30
|
+
@validity = Time.now.getutc.to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
# give the acess token for th application and refresh if it is outdated
|
34
|
+
#
|
35
|
+
# @return [String] access token
|
36
|
+
def access_token
|
37
|
+
if Time.now.getutc.to_i - @validity > 3600
|
38
|
+
refresh_token
|
39
|
+
end
|
40
|
+
|
41
|
+
@access_token
|
42
|
+
end
|
43
|
+
|
44
|
+
# refresh the token by asking for a new one
|
45
|
+
#
|
46
|
+
# @return [String] access token
|
47
|
+
def refresh_token
|
48
|
+
request_token
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
# generate the JWT that must be include with the request acess token.
|
53
|
+
# the format of the JWT is (base64url encoded header).(base64url encoded claim set).(base64url encoded signature)
|
54
|
+
#
|
55
|
+
# @return [String] the generate JWT.
|
56
|
+
def generate_assertion()
|
57
|
+
encoded_header = [JWT_HEADER.to_json].pack("m0").tr("+/", "-_")
|
58
|
+
|
59
|
+
|
60
|
+
utc_time = Time.now.getutc.to_i
|
61
|
+
claim = {
|
62
|
+
'aud' => Authentification::REQUEST_URL,
|
63
|
+
'scope'=> ASSERTION_SCOPE,
|
64
|
+
'prn' => @user_email,
|
65
|
+
'iat' => utc_time,
|
66
|
+
'exp' => utc_time+3600,
|
67
|
+
'iss' => @client_email
|
68
|
+
}
|
69
|
+
encoded_claim = [claim.to_json].pack("m0").tr("+/", "-_")
|
70
|
+
begin
|
71
|
+
p12 = OpenSSL::PKCS12.new(File.read(@p12_file), @password)
|
72
|
+
rescue
|
73
|
+
raise GcalMapper::AuthFileError
|
74
|
+
end
|
75
|
+
key = p12.key
|
76
|
+
sign = key.sign(OpenSSL::Digest::SHA256.new, encoded_header + '.' + encoded_claim)
|
77
|
+
encoded_sign = [sign].pack("m0").tr("+/", "-_")
|
78
|
+
|
79
|
+
encoded_header + '.' + encoded_claim + '.' + encoded_sign
|
80
|
+
end
|
81
|
+
|
82
|
+
# Prepare all the parameters for sending the request token request to google
|
83
|
+
# and save the token in instance variable.
|
84
|
+
#
|
85
|
+
# @return [Hash] the HTTP response.
|
86
|
+
def request_token
|
87
|
+
data = {
|
88
|
+
'grant_type' => 'assertion',
|
89
|
+
'assertion_type' => ASSERTION_TYPE,
|
90
|
+
'assertion' => generate_assertion
|
91
|
+
}
|
92
|
+
options = {
|
93
|
+
:method => :post,
|
94
|
+
:headers => {'Content-Type' => 'application/x-www-form-urlencoded'},
|
95
|
+
:parameters => data
|
96
|
+
}
|
97
|
+
req = GcalMapper::RestRequest.new(Authentification::REQUEST_URL, options)
|
98
|
+
begin
|
99
|
+
response = req.execute
|
100
|
+
rescue
|
101
|
+
raise GcalMapper::AuthentificationError
|
102
|
+
end
|
103
|
+
@valididity = Time.now.getutc.to_i
|
104
|
+
|
105
|
+
@access_token = response['access_token']
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GcalMapper
|
2
|
+
class Authentification
|
3
|
+
#
|
4
|
+
# Base class for authentification methods
|
5
|
+
#
|
6
|
+
class Base
|
7
|
+
|
8
|
+
# raise error if this method is called -> mean that child class has not implemeted this method
|
9
|
+
def access_token
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
# raise error if this method is called -> mean that child class has not implemeted this method
|
14
|
+
def refresh_token
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'gcal_mapper/authentification/base'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module GcalMapper
|
5
|
+
class Authentification
|
6
|
+
#
|
7
|
+
# make the authentification with Oauth2 and request data from google calendar.
|
8
|
+
#
|
9
|
+
class Oauth2 < Authentification::Base
|
10
|
+
|
11
|
+
# intialize client info needed for connection to Oauth2.
|
12
|
+
#
|
13
|
+
# @param [String] yaml_file path to the yaml file which contains acess token, ...
|
14
|
+
def initialize (yaml_file)
|
15
|
+
begin
|
16
|
+
oauth_yaml = YAML.load_file(yaml_file)
|
17
|
+
@client_id = oauth_yaml["client_id"]
|
18
|
+
@client_secret = oauth_yaml["client_secret"]
|
19
|
+
@scope = oauth_yaml["scope"]
|
20
|
+
@refresh_token = oauth_yaml["refresh_token"]
|
21
|
+
@access_token = oauth_yaml["access_token"]
|
22
|
+
@validity = Time.now.getutc.to_i
|
23
|
+
rescue
|
24
|
+
raise GcalMapper::AuthFileError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# give the acess token for th application and refresh if it is outdated
|
29
|
+
#
|
30
|
+
# @return [String] access token
|
31
|
+
def access_token
|
32
|
+
if (Time.now.getutc.to_i - @validity) > 3600
|
33
|
+
refresh_token
|
34
|
+
end
|
35
|
+
|
36
|
+
@access_token
|
37
|
+
end
|
38
|
+
|
39
|
+
# refresh the token by using refresh token
|
40
|
+
#
|
41
|
+
# @return [String] access token
|
42
|
+
def refresh_token
|
43
|
+
data = {
|
44
|
+
'client_id' => @client_id,
|
45
|
+
'client_secret' => @client_secret,
|
46
|
+
'refresh_token' => @refresh_token,
|
47
|
+
'grant_type' => 'refresh_token'
|
48
|
+
}
|
49
|
+
options = {
|
50
|
+
:method => :post,
|
51
|
+
:headers => {'Content-Type' => 'application/x-www-form-urlencoded'},
|
52
|
+
:parameters => data
|
53
|
+
}
|
54
|
+
req = GcalMapper::RestRequest.new(Authentification::REQUEST_URL, options)
|
55
|
+
begin
|
56
|
+
response = req.execute
|
57
|
+
rescue
|
58
|
+
raise GcalMapper::AuthentificationError
|
59
|
+
end
|
60
|
+
@validity = Time.now.getutc.to_i
|
61
|
+
|
62
|
+
@access_token = response['access_token']
|
63
|
+
response
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module GcalMapper
|
2
|
+
#
|
3
|
+
# Provide methods to get google calendar data
|
4
|
+
#
|
5
|
+
class Calendar
|
6
|
+
|
7
|
+
# Get the calendar list for the connected user.
|
8
|
+
#
|
9
|
+
# @param [Hash] access_token the token obtain with Authentification.access_token
|
10
|
+
# @return [Array] google calendar id that the user can access.
|
11
|
+
def get_calendars_list(access_token)
|
12
|
+
url = 'https://www.googleapis.com/calendar/v3/users/me/calendarList'
|
13
|
+
options = {
|
14
|
+
:method => :get,
|
15
|
+
:headers => {'Authorization' => 'Bearer ' + access_token}
|
16
|
+
}
|
17
|
+
req = GcalMapper::RestRequest.new(url, options)
|
18
|
+
response = req.execute
|
19
|
+
|
20
|
+
tab_cal=response['items']
|
21
|
+
ids = []
|
22
|
+
|
23
|
+
tab_cal.each do |t|
|
24
|
+
t.each do |k, v|
|
25
|
+
if k == 'id'
|
26
|
+
ids.push(v)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ids
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get all events from specified calendar(s).
|
35
|
+
#
|
36
|
+
# @param [Hash] access_token the token obtain with Authentification.access_token
|
37
|
+
# @param [Array] calendar_id contain the calendar(s) id you want to map
|
38
|
+
# @return [Array] all events from given calendar(s) id.
|
39
|
+
def get_events_list(access_token, calendar_id)
|
40
|
+
url = 'https://www.googleapis.com/calendar/v3/calendars/'+calendar_id+'/events?showDeleted=true'
|
41
|
+
options = {
|
42
|
+
:method => :get,
|
43
|
+
:headers => {'Authorization' => 'Bearer ' + access_token},
|
44
|
+
}
|
45
|
+
req = GcalMapper::RestRequest.new(url, options)
|
46
|
+
response = req.execute
|
47
|
+
response['items']
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|