jbr 3.2.0 → 3.3.0
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +10 -0
- data/lib/jbr/oauth.rb +2 -9
- data/lib/jbr/refused.rb +5 -0
- data/lib/jbr/token.rb +35 -0
- data/lib/jbr/version.rb +1 -1
- data/lib/jbr.rb +2 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 074fba6db0300fd967935b1996f1791016e216aa49ef829e771f56340400af1f
|
|
4
|
+
data.tar.gz: c8433c006174ab91d76db6a331268c325a90ff4f049f179c5adf46acd9716487
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d3e116c317b973a9600af44e3fd02466e360321f08b4e1c696c2e214854b91b8318c45a8ffdb7c50f6f880bf07e6388bf060d33f54ad58b60b2ead27aab535d
|
|
7
|
+
data.tar.gz: 28ee328df69a90a166cfaa4ed6ee0b22fad572c7bca8defb501afba0b3054c652b17741df883f4be32b0bd33ca7253a4a7e5872564b2f636f02d459323a7693c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [3.3.0] - 2026-08-13
|
|
2
|
+
|
|
3
|
+
- [Fix] Credentials are given up only when Jobber says the grant itself is no good. Any
|
|
4
|
+
refusal at all used to set `invalid_at` -- a 500, a rate limit, an unreadable body -- so
|
|
5
|
+
a moment of trouble at Jobber's end read as a dead token, and an app acting on that could
|
|
6
|
+
revoke one that still worked. Only an `invalid_grant` Jobber names counts now; everything
|
|
7
|
+
else raises `Jbr::Error` for the caller to retry, which is what trouble deserves
|
|
8
|
+
- [New] `Jbr::Refused`, a `Jbr::Error` for the grant being no good rather than for the
|
|
9
|
+
answer failing to arrive. Rescue it to tell the two apart
|
|
10
|
+
- [Change] The token endpoint moved to `Jbr::Token`. `Jbr::OAuth.post` still answers it
|
|
11
|
+
unchanged, and so do `Jbr::OAuth.client_id` and `Jbr::OAuth.client_secret`
|
|
12
|
+
|
|
1
13
|
## [3.2.0] - 2026-08-13
|
|
2
14
|
|
|
3
15
|
- [New] Wait rather than be refused. Jobber holds an app to two limits at once -- 2,500
|
data/README.md
CHANGED
|
@@ -41,6 +41,16 @@ Revoke credentials:
|
|
|
41
41
|
oauth.delete
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
Credentials go bad only when Jobber says so. A refused refresh — the `invalid_grant` Jobber
|
|
45
|
+
names — sets `invalid_at` and answers queries with nothing. Anything else that goes wrong,
|
|
46
|
+
including a 500 or a rate limit, raises `Jbr::Error` instead, because a token that may still
|
|
47
|
+
work is worth more than a tidy failure:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
oauth.invalid_at # => 2026-08-13 11:02:41, or nil while the credentials are good
|
|
51
|
+
oauth.query '{ ok }' # => {} once they are refused, raises Jbr::Error where Jobber had trouble
|
|
52
|
+
```
|
|
53
|
+
|
|
44
54
|
### Requests
|
|
45
55
|
|
|
46
56
|
Create a Jobber request, finding or creating a Client with a matching phone number:
|
data/lib/jbr/oauth.rb
CHANGED
|
@@ -66,14 +66,7 @@ module Jbr
|
|
|
66
66
|
|
|
67
67
|
# Exchange a code or a refresh token for credentials.
|
|
68
68
|
def self.post(params = {})
|
|
69
|
-
|
|
70
|
-
response = Net::HTTP.post_form uri,
|
|
71
|
-
params.merge(client_id: client_id, client_secret: client_secret)
|
|
72
|
-
raise Error, response.body unless response.is_a? Net::HTTPSuccess
|
|
73
|
-
output = JSON.parse(response.body)
|
|
74
|
-
{ access_token: output['access_token'], refresh_token: output['refresh_token'],
|
|
75
|
-
expires_at: (Time.now + output.fetch('expires_in', 3600).to_i),
|
|
76
|
-
}
|
|
69
|
+
Token.post params.merge(client_id: client_id, client_secret: client_secret)
|
|
77
70
|
end
|
|
78
71
|
|
|
79
72
|
private
|
|
@@ -85,7 +78,7 @@ module Jbr
|
|
|
85
78
|
@access_token = output[:access_token]
|
|
86
79
|
@refresh_token = output[:refresh_token]
|
|
87
80
|
@expires_at = output[:expires_at]
|
|
88
|
-
rescue
|
|
81
|
+
rescue Refused
|
|
89
82
|
@invalid_at = Time.now
|
|
90
83
|
false
|
|
91
84
|
end
|
data/lib/jbr/refused.rb
ADDED
data/lib/jbr/token.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Jbr
|
|
2
|
+
# The endpoint that trades an authorization code or a refresh token for credentials.
|
|
3
|
+
class Token
|
|
4
|
+
# Where a grant is exchanged.
|
|
5
|
+
URL = 'https://api.getjobber.com/api/oauth/token'
|
|
6
|
+
|
|
7
|
+
# What Jobber calls a grant that is no good, in the OAuth 2 word for it.
|
|
8
|
+
REFUSAL = 'invalid_grant'
|
|
9
|
+
|
|
10
|
+
# Trade a grant for credentials.
|
|
11
|
+
# @param params [Hash] the grant, and the app making the exchange.
|
|
12
|
+
# @raise [Refused] where Jobber says the grant itself is no good.
|
|
13
|
+
# @raise [Error] where Jobber could not answer about it.
|
|
14
|
+
# @return [Hash] the tokens, and the moment the access one expires.
|
|
15
|
+
def self.post(params = {})
|
|
16
|
+
response = Net::HTTP.post_form URI(URL), params
|
|
17
|
+
raise Refused, response.body if refused? response
|
|
18
|
+
raise Error, response.body unless response.is_a? Net::HTTPSuccess
|
|
19
|
+
|
|
20
|
+
output = JSON.parse response.body
|
|
21
|
+
{ access_token: output['access_token'], refresh_token: output['refresh_token'],
|
|
22
|
+
expires_at: (Time.now + output.fetch('expires_in', 3600).to_i),
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.refused?(response)
|
|
27
|
+
return false if response.is_a? Net::HTTPSuccess
|
|
28
|
+
|
|
29
|
+
JSON.parse(response.body)['error'] == REFUSAL
|
|
30
|
+
rescue JSON::ParserError
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
private_class_method :refused?
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/jbr/version.rb
CHANGED
data/lib/jbr.rb
CHANGED
|
@@ -15,6 +15,8 @@ require 'jbr/mock'
|
|
|
15
15
|
|
|
16
16
|
require 'jbr/url'
|
|
17
17
|
require 'jbr/error'
|
|
18
|
+
require 'jbr/refused'
|
|
19
|
+
require 'jbr/token'
|
|
18
20
|
# Phone before Cliental, and Cliental before the records that include it: what each asks
|
|
19
21
|
# Jobber for about a client is built as they load.
|
|
20
22
|
require 'jbr/phone'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jbr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Claudio Baccigalupo
|
|
@@ -137,9 +137,11 @@ files:
|
|
|
137
137
|
- lib/jbr/properted.rb
|
|
138
138
|
- lib/jbr/property.rb
|
|
139
139
|
- lib/jbr/quote.rb
|
|
140
|
+
- lib/jbr/refused.rb
|
|
140
141
|
- lib/jbr/request.rb
|
|
141
142
|
- lib/jbr/resource.rb
|
|
142
143
|
- lib/jbr/throttle.rb
|
|
144
|
+
- lib/jbr/token.rb
|
|
143
145
|
- lib/jbr/url.rb
|
|
144
146
|
- lib/jbr/version.rb
|
|
145
147
|
- lib/jbr/visit.rb
|