openc-asana 0.1.2
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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +4 -0
- data/.gitignore +13 -0
- data/.rspec +4 -0
- data/.rubocop.yml +11 -0
- data/.travis.yml +12 -0
- data/.yardopts +5 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +21 -0
- data/Guardfile +86 -0
- data/LICENSE.txt +21 -0
- data/README.md +355 -0
- data/Rakefile +65 -0
- data/examples/Gemfile +6 -0
- data/examples/Gemfile.lock +59 -0
- data/examples/api_token.rb +21 -0
- data/examples/cli_app.rb +25 -0
- data/examples/events.rb +38 -0
- data/examples/omniauth_integration.rb +54 -0
- data/lib/asana.rb +12 -0
- data/lib/asana/authentication.rb +8 -0
- data/lib/asana/authentication/oauth2.rb +42 -0
- data/lib/asana/authentication/oauth2/access_token_authentication.rb +51 -0
- data/lib/asana/authentication/oauth2/bearer_token_authentication.rb +32 -0
- data/lib/asana/authentication/oauth2/client.rb +50 -0
- data/lib/asana/authentication/token_authentication.rb +20 -0
- data/lib/asana/client.rb +124 -0
- data/lib/asana/client/configuration.rb +165 -0
- data/lib/asana/errors.rb +92 -0
- data/lib/asana/http_client.rb +155 -0
- data/lib/asana/http_client/environment_info.rb +53 -0
- data/lib/asana/http_client/error_handling.rb +103 -0
- data/lib/asana/http_client/response.rb +32 -0
- data/lib/asana/resource_includes/attachment_uploading.rb +33 -0
- data/lib/asana/resource_includes/collection.rb +68 -0
- data/lib/asana/resource_includes/event.rb +51 -0
- data/lib/asana/resource_includes/event_subscription.rb +14 -0
- data/lib/asana/resource_includes/events.rb +103 -0
- data/lib/asana/resource_includes/registry.rb +63 -0
- data/lib/asana/resource_includes/resource.rb +103 -0
- data/lib/asana/resource_includes/response_helper.rb +14 -0
- data/lib/asana/resources.rb +14 -0
- data/lib/asana/resources/attachment.rb +44 -0
- data/lib/asana/resources/project.rb +154 -0
- data/lib/asana/resources/story.rb +64 -0
- data/lib/asana/resources/tag.rb +120 -0
- data/lib/asana/resources/task.rb +300 -0
- data/lib/asana/resources/team.rb +55 -0
- data/lib/asana/resources/user.rb +72 -0
- data/lib/asana/resources/workspace.rb +91 -0
- data/lib/asana/ruby2_0_0_compatibility.rb +3 -0
- data/lib/asana/version.rb +5 -0
- data/lib/templates/index.js +8 -0
- data/lib/templates/resource.ejs +225 -0
- data/openc-asana.gemspec +32 -0
- data/package.json +7 -0
- metadata +200 -0
data/Rakefile
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
require 'yard'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
RuboCop::RakeTask.new
|
8
|
+
|
9
|
+
YARD::Rake::YardocTask.new do |t|
|
10
|
+
t.stats_options = ['--list-undoc']
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Generates a test resource from a YAML using the resource template.'
|
14
|
+
task :codegen do
|
15
|
+
`node spec/support/codegen.js`
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :bump do
|
19
|
+
def read_version
|
20
|
+
File.readlines('./lib/asana/version.rb')
|
21
|
+
.detect { |l| l =~ /VERSION/ }
|
22
|
+
.scan(/VERSION = '([^']+)/).flatten.first.split('.')
|
23
|
+
.map { |n| Integer(n) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# rubocop:disable Metrics/MethodLength
|
27
|
+
def write_version(major, minor, patch)
|
28
|
+
str = <<-EOS
|
29
|
+
#:nodoc:
|
30
|
+
module Asana
|
31
|
+
# Public: Version of the gem.
|
32
|
+
VERSION = '#{major}.#{minor}.#{patch}'
|
33
|
+
end
|
34
|
+
EOS
|
35
|
+
File.open('./lib/asana/version.rb', 'w') do |f|
|
36
|
+
f.write str
|
37
|
+
end
|
38
|
+
|
39
|
+
new_version = "#{major}.#{minor}.#{patch}"
|
40
|
+
system('git add lib/asana/version.rb')
|
41
|
+
system(%(git commit -m "Bumped to #{new_version}" && ) +
|
42
|
+
%(git tag -a v#{new_version} -m "Version #{new_version}"))
|
43
|
+
puts "\nRun git push --tags to release."
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'Bumps a patch version'
|
47
|
+
task :patch do
|
48
|
+
major, minor, patch = read_version
|
49
|
+
write_version major, minor, patch + 1
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Bumps a minor version'
|
53
|
+
task :minor do
|
54
|
+
major, minor, = read_version
|
55
|
+
write_version major, minor + 1, 0
|
56
|
+
end
|
57
|
+
|
58
|
+
desc 'Bumps a major version'
|
59
|
+
task :major do
|
60
|
+
major, = read_version
|
61
|
+
write_version major + 1, 0, 0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
task default: [:codegen, :spec, :rubocop, :yard]
|
data/examples/Gemfile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
asana (0.1.1)
|
5
|
+
faraday (~> 0.9)
|
6
|
+
faraday_middleware (~> 0.9)
|
7
|
+
faraday_middleware-multi_json (~> 0.0)
|
8
|
+
oauth2 (~> 1.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
faraday (0.9.1)
|
14
|
+
multipart-post (>= 1.2, < 3)
|
15
|
+
faraday_middleware (0.9.1)
|
16
|
+
faraday (>= 0.7.4, < 0.10)
|
17
|
+
faraday_middleware-multi_json (0.0.6)
|
18
|
+
faraday_middleware
|
19
|
+
multi_json
|
20
|
+
hashie (3.4.1)
|
21
|
+
jwt (1.5.0)
|
22
|
+
multi_json (1.11.0)
|
23
|
+
multi_xml (0.5.5)
|
24
|
+
multipart-post (2.0.0)
|
25
|
+
oauth2 (1.0.0)
|
26
|
+
faraday (>= 0.8, < 0.10)
|
27
|
+
jwt (~> 1.0)
|
28
|
+
multi_json (~> 1.3)
|
29
|
+
multi_xml (~> 0.5)
|
30
|
+
rack (~> 1.2)
|
31
|
+
omniauth (1.2.2)
|
32
|
+
hashie (>= 1.2, < 4)
|
33
|
+
rack (~> 1.0)
|
34
|
+
omniauth-asana (0.0.1)
|
35
|
+
omniauth (~> 1.0)
|
36
|
+
omniauth-oauth2 (~> 1.1)
|
37
|
+
omniauth-oauth2 (1.3.0)
|
38
|
+
oauth2 (~> 1.0)
|
39
|
+
omniauth (~> 1.2)
|
40
|
+
rack (1.6.1)
|
41
|
+
rack-protection (1.5.3)
|
42
|
+
rack
|
43
|
+
sinatra (1.4.6)
|
44
|
+
rack (~> 1.4)
|
45
|
+
rack-protection (~> 1.4)
|
46
|
+
tilt (>= 1.3, < 3)
|
47
|
+
tilt (2.0.1)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
asana!
|
54
|
+
omniauth
|
55
|
+
omniauth-asana
|
56
|
+
sinatra
|
57
|
+
|
58
|
+
BUNDLED WITH
|
59
|
+
1.10.3
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require 'asana'
|
4
|
+
|
5
|
+
api_token = ENV['ASANA_API_TOKEN']
|
6
|
+
unless api_token
|
7
|
+
abort "Run this program with the env var ASANA_API_TOKEN.\n" \
|
8
|
+
"Go to http://app.asana.com/-/account_api to see your API token."
|
9
|
+
end
|
10
|
+
|
11
|
+
client = Asana::Client.new do |c|
|
12
|
+
c.authentication :api_token, api_token
|
13
|
+
end
|
14
|
+
|
15
|
+
puts "My Workspaces:"
|
16
|
+
client.workspaces.find_all.each do |workspace|
|
17
|
+
puts "\t* #{workspace.name} - tags:"
|
18
|
+
client.tags.find_by_workspace(workspace: workspace.id).each do |tag|
|
19
|
+
puts "\t\t- #{tag.name}"
|
20
|
+
end
|
21
|
+
end
|
data/examples/cli_app.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require 'asana'
|
4
|
+
|
5
|
+
id, secret = ENV['ASANA_CLIENT_ID'], ENV['ASANA_CLIENT_SECRET']
|
6
|
+
unless id && secret
|
7
|
+
abort "Run this program with the env vars ASANA_CLIENT_ID and ASANA_CLIENT_SECRET.\n" \
|
8
|
+
"Refer to https://asana.com/developers/documentation/getting-started/authentication "\
|
9
|
+
"to get your credentials." \
|
10
|
+
"The redirect URI for your application should be \"urn:ietf:wg:oauth:2.0:oob\"."
|
11
|
+
end
|
12
|
+
|
13
|
+
access_token = Asana::Authentication::OAuth2.offline_flow(client_id: id,
|
14
|
+
client_secret: secret)
|
15
|
+
client = Asana::Client.new do |c|
|
16
|
+
c.authentication :oauth2, access_token
|
17
|
+
end
|
18
|
+
|
19
|
+
puts "My Workspaces:"
|
20
|
+
client.workspaces.find_all.each do |workspace|
|
21
|
+
puts "\t* #{workspace.name} - tags:"
|
22
|
+
client.tags.find_by_workspace(workspace: workspace.id).each do |tag|
|
23
|
+
puts "\t\t- #{tag.name}"
|
24
|
+
end
|
25
|
+
end
|
data/examples/events.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.require
|
4
|
+
require 'asana'
|
5
|
+
|
6
|
+
api_token = ENV['ASANA_API_TOKEN']
|
7
|
+
unless api_token
|
8
|
+
abort "Run this program with the env var ASANA_API_TOKEN.\n" \
|
9
|
+
"Go to http://app.asana.com/-/account_api to see your API token."
|
10
|
+
end
|
11
|
+
|
12
|
+
client = Asana::Client.new do |c|
|
13
|
+
c.authentication :api_token, api_token
|
14
|
+
end
|
15
|
+
|
16
|
+
workspace = client.workspaces.find_all.first
|
17
|
+
task = client.tasks.find_all(assignee: "me", workspace: workspace.id).first
|
18
|
+
unless task
|
19
|
+
task = client.tasks.create(workspace: workspace.id, name: "Hello world!", assignee: "me")
|
20
|
+
end
|
21
|
+
|
22
|
+
Thread.abort_on_exception = true
|
23
|
+
|
24
|
+
Thread.new do
|
25
|
+
puts "Listening for 'changed' events on #{task} in one thread..."
|
26
|
+
task.events(wait: 2).lazy.select { |event| event.action == 'changed' }.each do |event|
|
27
|
+
puts "#{event.user.name} changed #{event.resource}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Thread.new do
|
32
|
+
puts "Listening for non-'changed' events on #{task} in another thread..."
|
33
|
+
task.events(wait: 1).lazy.reject { |event| event.action == 'changed' }.each do |event|
|
34
|
+
puts "'#{event.action}' event: #{event}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
sleep
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require 'asana'
|
4
|
+
|
5
|
+
class SinatraApp < Sinatra::Base
|
6
|
+
id, secret = ENV['ASANA_CLIENT_ID'], ENV['ASANA_CLIENT_SECRET']
|
7
|
+
unless id && secret
|
8
|
+
abort "Run this program with the env vars ASANA_CLIENT_ID and ASANA_CLIENT_SECRET.\n" \
|
9
|
+
"Refer to https://asana.com/developers/documentation/getting-started/authentication "\
|
10
|
+
"to get your credentials."
|
11
|
+
end
|
12
|
+
|
13
|
+
use OmniAuth::Strategies::Asana, id, secret
|
14
|
+
|
15
|
+
enable :sessions
|
16
|
+
|
17
|
+
get '/' do
|
18
|
+
if $client
|
19
|
+
'<a href="/workspaces">My Workspaces</a>'
|
20
|
+
else
|
21
|
+
'<a href="/sign_in">sign in to asana</a>'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
get '/workspaces' do
|
26
|
+
if $client
|
27
|
+
"<h1>My Workspaces</h1>" \
|
28
|
+
"<ul>" + $client.workspaces.find_all.map { |w| "<li>#{w.name}</li>" }.join + "</ul>"
|
29
|
+
else
|
30
|
+
redirect '/sign_in'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/auth/:name/callback' do
|
35
|
+
creds = request.env["omniauth.auth"]["credentials"].tap { |h| h.delete('expires') }
|
36
|
+
strategy = request.env["omniauth.strategy"]
|
37
|
+
access_token = OAuth2::AccessToken.from_hash(strategy.client, creds).refresh!
|
38
|
+
$client = Asana::Client.new do |c|
|
39
|
+
c.authentication :oauth2, access_token
|
40
|
+
end
|
41
|
+
redirect '/workspaces'
|
42
|
+
end
|
43
|
+
|
44
|
+
get '/sign_in' do
|
45
|
+
redirect '/auth/asana'
|
46
|
+
end
|
47
|
+
|
48
|
+
get '/sign_out' do
|
49
|
+
$client = nil
|
50
|
+
redirect '/'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
SinatraApp.run! if __FILE__ == $0
|
data/lib/asana.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'asana/ruby2_0_0_compatibility'
|
2
|
+
require 'asana/authentication'
|
3
|
+
require 'asana/resources'
|
4
|
+
require 'asana/client'
|
5
|
+
require 'asana/errors'
|
6
|
+
require 'asana/http_client'
|
7
|
+
require 'asana/version'
|
8
|
+
|
9
|
+
# Public: Top-level namespace of the Asana API Ruby client.
|
10
|
+
module Asana
|
11
|
+
include Asana::Resources
|
12
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'oauth2/bearer_token_authentication'
|
2
|
+
require_relative 'oauth2/access_token_authentication'
|
3
|
+
require_relative 'oauth2/client'
|
4
|
+
|
5
|
+
module Asana
|
6
|
+
module Authentication
|
7
|
+
# Public: Deals with OAuth2 authentication. Contains a function to get an
|
8
|
+
# access token throught a browserless authentication flow, needed for some
|
9
|
+
# applications such as CLI applications.
|
10
|
+
module OAuth2
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# Public: Retrieves an access token through an offline authentication
|
14
|
+
# flow. If your application can receive HTTP requests, you might want to
|
15
|
+
# opt for a browser-based flow and use the omniauth-asana gem instead.
|
16
|
+
#
|
17
|
+
# Your registered application's redirect_uri should be exactly
|
18
|
+
# "urn:ietf:wg:oauth:2.0:oob".
|
19
|
+
#
|
20
|
+
# client_id - [String] the client id of the registered Asana API
|
21
|
+
# application.
|
22
|
+
# client_secret - [String] the client secret of the registered Asana API
|
23
|
+
# application.
|
24
|
+
#
|
25
|
+
# Returns an ::OAuth2::AccessToken object.
|
26
|
+
#
|
27
|
+
# Note: This function reads from STDIN and writes to STDOUT. It is meant
|
28
|
+
# to be used only within the context of a CLI application.
|
29
|
+
def offline_flow(client_id: required('client_id'),
|
30
|
+
client_secret: required('client_secret'))
|
31
|
+
client = Client.new(client_id: client_id,
|
32
|
+
client_secret: client_secret,
|
33
|
+
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob')
|
34
|
+
STDOUT.puts '1. Go to the following URL to authorize the ' \
|
35
|
+
" application: #{client.authorize_url}"
|
36
|
+
STDOUT.puts '2. Paste the authorization code here: '
|
37
|
+
auth_code = STDIN.gets.chomp
|
38
|
+
client.token_from_auth_code(auth_code)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Asana
|
2
|
+
module Authentication
|
3
|
+
module OAuth2
|
4
|
+
# Public: A mechanism to authenticate with an OAuth2 access token (a
|
5
|
+
# bearer token and a refresh token) or just a refresh token.
|
6
|
+
class AccessTokenAuthentication
|
7
|
+
# Public: Builds an AccessTokenAuthentication from a refresh token and
|
8
|
+
# client credentials, by refreshing into a new one.
|
9
|
+
#
|
10
|
+
# refresh_token - [String] a refresh token
|
11
|
+
# client_id - [String] the client id of the registered Asana API
|
12
|
+
# Application.
|
13
|
+
# client_secret - [String] the client secret of the registered Asana API
|
14
|
+
# Application.
|
15
|
+
# redirect_uri - [String] the redirect uri of the registered Asana API
|
16
|
+
# Application.
|
17
|
+
#
|
18
|
+
# Returns an [AccessTokenAuthentication] instance with a refreshed
|
19
|
+
# access token.
|
20
|
+
def self.from_refresh_token(refresh_token,
|
21
|
+
client_id: required('client_id'),
|
22
|
+
client_secret: required('client_secret'),
|
23
|
+
redirect_uri: required('redirect_uri'))
|
24
|
+
client = Client.new(client_id: client_id,
|
25
|
+
client_secret: client_secret,
|
26
|
+
redirect_uri: redirect_uri)
|
27
|
+
new(client.token_from_refresh_token(refresh_token))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Initializes a new AccessTokenAuthentication.
|
31
|
+
#
|
32
|
+
# access_token - [::OAuth2::AccessToken] An ::OAuth2::AccessToken
|
33
|
+
# object.
|
34
|
+
def initialize(access_token)
|
35
|
+
@token = access_token
|
36
|
+
end
|
37
|
+
|
38
|
+
# Public: Configures a Faraday connection injecting a bearer token,
|
39
|
+
# auto-refreshing it when needed.
|
40
|
+
#
|
41
|
+
# connection - [Faraday::Connection] the Faraday connection instance.
|
42
|
+
#
|
43
|
+
# Returns nothing.
|
44
|
+
def configure(connection)
|
45
|
+
@token = @token.refresh! if @token.expired?
|
46
|
+
connection.request :oauth2, @token.token
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Asana
|
2
|
+
module Authentication
|
3
|
+
module OAuth2
|
4
|
+
# Public: A mechanism to authenticate with an OAuth2 bearer token obtained
|
5
|
+
# somewhere, for instance through omniauth-asana.
|
6
|
+
#
|
7
|
+
# Note: This authentication mechanism doesn't support token refreshing. If
|
8
|
+
# you'd like refreshing and you have a refresh token as well as a bearer
|
9
|
+
# token, you can generate a proper access token with
|
10
|
+
# {AccessTokenAuthentication.from_refresh_token}.
|
11
|
+
class BearerTokenAuthentication
|
12
|
+
# Public: Initializes a new BearerTokenAuthentication with a plain
|
13
|
+
# bearer token.
|
14
|
+
#
|
15
|
+
# bearer_token - [String] a plain bearer token.
|
16
|
+
def initialize(bearer_token)
|
17
|
+
@token = bearer_token
|
18
|
+
end
|
19
|
+
|
20
|
+
# Public: Configures a Faraday connection injecting its token as an
|
21
|
+
# OAuth2 bearer token.
|
22
|
+
#
|
23
|
+
# connection - [Faraday::Connection] the Faraday connection instance.
|
24
|
+
#
|
25
|
+
# Returns nothing.
|
26
|
+
def configure(connection)
|
27
|
+
connection.request :oauth2, @token
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module Asana
|
4
|
+
module Authentication
|
5
|
+
module OAuth2
|
6
|
+
# Public: Deals with the details of obtaining an OAuth2 authorization URL
|
7
|
+
# and obtaining access tokens from either authorization codes or refresh
|
8
|
+
# tokens.
|
9
|
+
class Client
|
10
|
+
# Public: Initializes a new client with client credentials associated
|
11
|
+
# with a registered Asana API application.
|
12
|
+
#
|
13
|
+
# client_id - [String] a client id from the registered application
|
14
|
+
# client_secret - [String] a client secret from the registered
|
15
|
+
# application
|
16
|
+
# redirect_uri - [String] a redirect uri from the registered
|
17
|
+
# application
|
18
|
+
def initialize(client_id: required('client_id'),
|
19
|
+
client_secret: required('client_secret'),
|
20
|
+
redirect_uri: required('redirect_uri'))
|
21
|
+
@client = ::OAuth2::Client.new(client_id, client_secret,
|
22
|
+
site: 'https://app.asana.com',
|
23
|
+
authorize_url: '/-/oauth_authorize',
|
24
|
+
token_url: '/-/oauth_token')
|
25
|
+
@redirect_uri = redirect_uri
|
26
|
+
end
|
27
|
+
|
28
|
+
# Public:
|
29
|
+
# Returns the [String] OAuth2 authorize URL.
|
30
|
+
def authorize_url
|
31
|
+
@client.auth_code.authorize_url(redirect_uri: @redirect_uri)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Retrieves a token from an authorization code.
|
35
|
+
#
|
36
|
+
# Returns the [::OAuth2::AccessToken] token.
|
37
|
+
def token_from_auth_code(auth_code)
|
38
|
+
@client.auth_code.get_token(auth_code, redirect_uri: @redirect_uri)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public: Retrieves a token from a refresh token.
|
42
|
+
#
|
43
|
+
# Returns the refreshed [::OAuth2::AccessToken] token.
|
44
|
+
def token_from_refresh_token(token)
|
45
|
+
::OAuth2::AccessToken.new(@client, '', refresh_token: token).refresh!
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|