help_scout-sdk 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -0
- data/lib/help_scout/api.rb +1 -1
- data/lib/help_scout/api/access_token.rb +28 -22
- data/lib/help_scout/api/access_token/cache.rb +40 -0
- data/lib/help_scout/api/access_token/request.rb +36 -0
- data/lib/help_scout/api/client.rb +9 -8
- data/lib/help_scout/configuration.rb +10 -1
- data/lib/help_scout/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d4c58f9f96b57b2d1bbc0cd69ad741ffa6201244861167992e8212901d491d2
|
4
|
+
data.tar.gz: 055c66adf697283a7836ce6fdb91156cea27ea1cddf0fc6f8b2c05c07ed174a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2058da0b726acce0ef9993b40e827bb2be27f2947c78dfcb57216e51acb3fbcd4969b86a658e621e1bd63c1e6410f291a55cb2aaa03fd446374208e2376eeed0
|
7
|
+
data.tar.gz: 10b8bbca725910b62a0b3120247506d50b8c7e3f34ed50a39ae2ddeb340d9081803b66d2649e9a9b410de4d1af2eb346372f3b96bcb6e7543f38e6f7c790f163
|
data/README.md
CHANGED
@@ -95,6 +95,19 @@ HelpScout::User.list
|
|
95
95
|
user = HelpScout::User.get(id)
|
96
96
|
```
|
97
97
|
|
98
|
+
### Caching Access Tokens
|
99
|
+
|
100
|
+
Since short-lived access tokens aren't likely to be embedded into environment variables, it can be difficult to share them across processes. To work around this, you can configure a `token_cache` (and optional `token_cache_key`) to be used to store and retrieve the token until expiry. In general any object that conforms to the `ActiveSupport::Cache::Store` API should work. For example, using an application's Rails cache:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
HelpScout.configuration.token_cache = Rails.cache
|
104
|
+
HelpScout.configuration.token_cache_key
|
105
|
+
# => 'help_scout_token_cache'
|
106
|
+
HelpScout.configuration.token_cache_key = 'my-own-key'
|
107
|
+
```
|
108
|
+
|
109
|
+
With caching configured, whenever the gem attempts to create an access token, it will first attempt to read a value from the cache using the configured cache key. If it's a hit, the cached values will be used to create a new `AccessToken`. If it's a miss, then the gem will make a request to the Help Scout API to retrieve a new token, writing the token's details to the cache before returning the new token.
|
110
|
+
|
98
111
|
## Development
|
99
112
|
|
100
113
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/help_scout/api.rb
CHANGED
@@ -1,32 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'date'
|
4
|
+
require 'help_scout/api/access_token/cache'
|
5
|
+
require 'help_scout/api/access_token/request'
|
6
|
+
|
3
7
|
module HelpScout
|
4
8
|
class API
|
5
9
|
class AccessToken
|
6
10
|
class << self
|
7
11
|
def create
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
case response.status
|
12
|
-
when 200 then new HelpScout::Response.new(response).body
|
13
|
-
when 429 then raise HelpScout::API::ThrottleLimitReached, response.body&.dig('error')
|
14
|
-
else raise HelpScout::API::InternalError, "unexpected response (status #{response.status})"
|
15
|
-
end
|
16
|
-
end
|
12
|
+
cache = HelpScout::API::AccessToken::Cache.new
|
13
|
+
request = HelpScout::API::AccessToken::Request.new
|
17
14
|
|
18
|
-
|
19
|
-
HelpScout.api.access_token = create
|
15
|
+
cache.configured? ? cache.fetch_token { request.execute } : request.execute
|
20
16
|
end
|
21
17
|
|
22
|
-
|
18
|
+
def refresh!
|
19
|
+
return HelpScout.api.access_token unless HelpScout.access_token.nil? || HelpScout.access_token.stale?
|
23
20
|
|
24
|
-
|
25
|
-
@_token_request_params ||= {
|
26
|
-
grant_type: 'client_credentials',
|
27
|
-
client_id: HelpScout.app_id,
|
28
|
-
client_secret: HelpScout.app_secret
|
29
|
-
}
|
21
|
+
HelpScout.api.access_token = create
|
30
22
|
end
|
31
23
|
end
|
32
24
|
|
@@ -35,10 +27,20 @@ module HelpScout
|
|
35
27
|
|
36
28
|
def initialize(params)
|
37
29
|
@value = params[:access_token]
|
38
|
-
@expires_in = params[:expires_in]
|
39
|
-
return unless @expires_in
|
40
30
|
|
41
|
-
|
31
|
+
if params[:expires_at]
|
32
|
+
@expires_at = DateTime.parse(params[:expires_at].to_s).to_time.utc
|
33
|
+
elsif params[:expires_in]
|
34
|
+
@expires_in = params[:expires_in].to_i
|
35
|
+
@expires_at = (Time.now.utc + @expires_in)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def as_json(*)
|
40
|
+
{
|
41
|
+
access_token: value,
|
42
|
+
expires_at: expires_at
|
43
|
+
}
|
42
44
|
end
|
43
45
|
|
44
46
|
def expired?
|
@@ -48,10 +50,14 @@ module HelpScout
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def invalid?
|
51
|
-
invalid
|
53
|
+
!!invalid # rubocop:disable Style/DoubleNegation
|
52
54
|
end
|
53
55
|
|
54
56
|
def invalidate!
|
57
|
+
cache = HelpScout::API::AccessToken::Cache.new
|
58
|
+
|
59
|
+
cache.delete if cache.configured?
|
60
|
+
|
55
61
|
self.invalid = true
|
56
62
|
end
|
57
63
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HelpScout
|
4
|
+
class API
|
5
|
+
class AccessToken
|
6
|
+
class Cache
|
7
|
+
attr_reader :backend, :key
|
8
|
+
|
9
|
+
def initialize(backend: nil, key: nil)
|
10
|
+
@backend = backend || HelpScout.configuration.token_cache
|
11
|
+
@key = key || HelpScout.configuration.token_cache_key
|
12
|
+
end
|
13
|
+
|
14
|
+
def configured?
|
15
|
+
backend.present? && key.present?
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete
|
19
|
+
backend.delete(key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def fetch_token(&token_request)
|
23
|
+
raise ArgumentError, 'A request fallback block is required' unless block_given?
|
24
|
+
|
25
|
+
if (cached_token_json = backend.read(key))
|
26
|
+
AccessToken.new(JSON.parse(cached_token_json, symbolize_names: true))
|
27
|
+
else
|
28
|
+
token_request.call.tap { |token| write(token) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def write(token)
|
35
|
+
backend.write(key, token.to_json, expires_in: token.expires_in)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HelpScout
|
4
|
+
class API
|
5
|
+
class AccessToken
|
6
|
+
class Request
|
7
|
+
attr_reader :response
|
8
|
+
|
9
|
+
def execute
|
10
|
+
@response = request_token
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def request_token
|
16
|
+
connection = API::Client.new(authorize: false).connection
|
17
|
+
http_response = connection.post('oauth2/token', token_request_params)
|
18
|
+
|
19
|
+
case http_response.status
|
20
|
+
when 200 then AccessToken.new(Response.new(http_response).body)
|
21
|
+
when 429 then raise API::ThrottleLimitReached, http_response.body&.dig('error')
|
22
|
+
else raise API::InternalError, "unexpected response (status #{http_response.status})"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def token_request_params
|
27
|
+
@_token_request_params ||= {
|
28
|
+
grant_type: 'client_credentials',
|
29
|
+
client_id: HelpScout.app_id,
|
30
|
+
client_secret: HelpScout.app_secret
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -10,14 +10,20 @@ module HelpScout
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def connection
|
13
|
-
@_connection ||=
|
14
|
-
|
15
|
-
|
13
|
+
@_connection ||= build_connection.tap do |conn|
|
14
|
+
if authorize?
|
15
|
+
HelpScout::API::AccessToken.refresh!
|
16
|
+
conn.authorization(:Bearer, access_token) if access_token
|
17
|
+
end
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
21
|
private
|
20
22
|
|
23
|
+
def access_token
|
24
|
+
HelpScout.access_token&.value
|
25
|
+
end
|
26
|
+
|
21
27
|
def authorize?
|
22
28
|
authorize
|
23
29
|
end
|
@@ -25,15 +31,10 @@ module HelpScout
|
|
25
31
|
def build_connection
|
26
32
|
Faraday.new(url: BASE_URL) do |conn|
|
27
33
|
conn.request :json
|
28
|
-
conn.authorization(:Bearer, HelpScout.access_token.value) if authorize? && HelpScout.access_token&.value
|
29
34
|
conn.response(:json, content_type: /\bjson$/)
|
30
35
|
conn.adapter(Faraday.default_adapter)
|
31
36
|
end
|
32
37
|
end
|
33
|
-
|
34
|
-
def token_needs_refresh?
|
35
|
-
HelpScout.access_token.nil? || HelpScout.access_token.stale?
|
36
|
-
end
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
@@ -2,13 +2,22 @@
|
|
2
2
|
|
3
3
|
module HelpScout
|
4
4
|
class Configuration
|
5
|
-
attr_accessor :app_id, :app_secret, :default_mailbox
|
5
|
+
attr_accessor :app_id, :app_secret, :default_mailbox, :token_cache
|
6
6
|
attr_reader :access_token
|
7
|
+
attr_writer :token_cache_key
|
8
|
+
|
9
|
+
DEFAULT_CACHE_KEY = 'help_scout_token_cache'
|
7
10
|
|
8
11
|
def access_token=(token_value)
|
9
12
|
return unless token_value
|
10
13
|
|
11
14
|
@access_token = HelpScout::API::AccessToken.new(access_token: token_value)
|
12
15
|
end
|
16
|
+
|
17
|
+
def token_cache_key
|
18
|
+
return @token_cache_key if defined?(@token_cache_key)
|
19
|
+
|
20
|
+
@token_cache_key = DEFAULT_CACHE_KEY
|
21
|
+
end
|
13
22
|
end
|
14
23
|
end
|
data/lib/help_scout/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: help_scout-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TaxJar
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -234,6 +234,8 @@ files:
|
|
234
234
|
- lib/help_scout-sdk.rb
|
235
235
|
- lib/help_scout/api.rb
|
236
236
|
- lib/help_scout/api/access_token.rb
|
237
|
+
- lib/help_scout/api/access_token/cache.rb
|
238
|
+
- lib/help_scout/api/access_token/request.rb
|
237
239
|
- lib/help_scout/api/client.rb
|
238
240
|
- lib/help_scout/attachment.rb
|
239
241
|
- lib/help_scout/base.rb
|