desk_api 0.5.8 → 0.6.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/LICENSE +2 -2
- data/README.md +274 -120
- data/lib/desk_api.rb +2 -2
- data/lib/desk_api/client.rb +6 -1
- data/lib/desk_api/configuration.rb +34 -26
- data/lib/desk_api/request/encode_json.rb +11 -0
- data/lib/desk_api/request/oauth.rb +20 -0
- data/lib/desk_api/request/retry.rb +37 -42
- data/lib/desk_api/resource.rb +86 -22
- data/lib/desk_api/response/parse_dates.rb +28 -0
- data/lib/desk_api/response/parse_json.rb +9 -0
- data/lib/desk_api/response/raise_error.rb +11 -16
- data/lib/desk_api/version.rb +1 -1
- data/spec/cassettes/DeskApi_Resource/_all/iterates_over_each_resource_on_each_page.yml +1953 -0
- data/spec/cassettes/DeskApi_Resource/_each_page/iterates_over_each_page.yml +1953 -0
- data/spec/cassettes/DeskApi_Resource/_each_page/raises_NoMethodError_is_called_on_non-page_resources.yml +207 -0
- data/spec/cassettes/DeskApi_Resource/_each_page/uses_a_default_per_page_of_1000.yml +1953 -0
- data/spec/cassettes/DeskApi_Resource/_load/loads_the_resource_if_not_already_loaded.yml +205 -0
- data/spec/cassettes/DeskApi_Resource/_loaded_/returns_true_if_the_resource_is_loaded.yml +205 -0
- data/spec/cassettes/DeskApi_Resource/_next_/changes__definition_to_next_page.yml +407 -0
- data/spec/cassettes/DeskApi_Resource/_next_/returns_nil_on_the_last_page.yml +315 -0
- data/spec/cassettes/DeskApi_Resource/_request/sends_request_through_a_client_and_returns_Faraday_Response.yml +207 -0
- data/spec/cassettes/DeskApi_Resource/_reset_/sets__links__embedded__changed_and__loaded_to_default_values.yml +253 -0
- data/spec/cassettes/DeskApi_Resource/_to_hash/converts_embedded_resources_to_hashes.yml +251 -0
- data/spec/cassettes/DeskApi_Resource/_to_hash/returns_a_hash_for_a_desk_resource.yml +66 -0
- data/spec/cassettes/DeskApi_Resource/_update/can_handle_action_params.yml +427 -0
- data/spec/desk_api/client_spec.rb +23 -17
- data/spec/desk_api/configuration_spec.rb +49 -41
- data/spec/desk_api/default_spec.rb +3 -3
- data/spec/desk_api/error_spec.rb +9 -7
- data/spec/desk_api/rate_limit_spec.rb +1 -1
- data/spec/desk_api/request/encode_json_spec.rb +33 -0
- data/spec/desk_api/request/oauth_spec.rb +31 -0
- data/spec/desk_api/request/retry_spec.rb +4 -4
- data/spec/desk_api/resource_spec.rb +247 -71
- data/spec/desk_api/response/parse_dates_spec.rb +34 -0
- data/spec/desk_api/response/parse_json_spec.rb +34 -0
- data/spec/desk_api/response/raise_error_spec.rb +31 -0
- data/spec/desk_api_spec.rb +6 -6
- data/spec/spec_helper.rb +2 -2
- data/spec/stubs/article.json +51 -0
- data/spec/stubs/to_hash_embed.json +1 -0
- metadata +78 -28
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -23
- data/.rspec +0 -1
- data/.travis.yml +0 -4
- data/.yardopts +0 -3
- data/Gemfile +0 -10
- data/Guardfile +0 -5
- data/Rakefile +0 -32
- data/desk_api.gemspec +0 -32
data/lib/desk_api.rb
CHANGED
data/lib/desk_api/client.rb
CHANGED
@@ -34,6 +34,11 @@ class DeskApi::Client
|
|
34
34
|
request(:patch, path, params)
|
35
35
|
end
|
36
36
|
|
37
|
+
# allow lookup by url
|
38
|
+
def by_url(url)
|
39
|
+
DeskApi::Resource.new(self, DeskApi::Resource.build_self_link(url))
|
40
|
+
end
|
41
|
+
|
37
42
|
private
|
38
43
|
# If the method is missing create a resource
|
39
44
|
def method_missing(method, params = {}, &block)
|
@@ -53,4 +58,4 @@ private
|
|
53
58
|
def connection
|
54
59
|
@connection ||= Faraday.new endpoint, connection_options, &middleware
|
55
60
|
end
|
56
|
-
end
|
61
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
require 'faraday_middleware/version'
|
3
|
-
require 'faraday_middleware/response/parse_dates'
|
1
|
+
require 'faraday'
|
4
2
|
|
5
3
|
require 'desk_api/default'
|
6
4
|
require 'desk_api/request/retry'
|
5
|
+
require 'desk_api/request/oauth'
|
6
|
+
require 'desk_api/request/encode_json'
|
7
|
+
require 'desk_api/response/parse_dates'
|
8
|
+
require 'desk_api/response/parse_json'
|
7
9
|
require 'desk_api/response/raise_error'
|
8
10
|
require 'desk_api/error/configuration_error'
|
9
11
|
require 'desk_api/error/client_error'
|
@@ -29,6 +31,24 @@ module DeskApi::Configuration
|
|
29
31
|
:connection_options
|
30
32
|
]
|
31
33
|
end
|
34
|
+
|
35
|
+
def included(base)
|
36
|
+
if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('0.9.0')
|
37
|
+
Faraday::Request.register_middleware desk_encode_json: DeskApi::Request::EncodeJson
|
38
|
+
Faraday::Request.register_middleware desk_oauth: DeskApi::Request::OAuth
|
39
|
+
Faraday::Request.register_middleware desk_retry: DeskApi::Request::Retry
|
40
|
+
Faraday::Response.register_middleware desk_parse_dates: DeskApi::Response::ParseDates
|
41
|
+
Faraday::Response.register_middleware desk_parse_json: DeskApi::Response::ParseJson
|
42
|
+
Faraday::Response.register_middleware desk_raise_error: DeskApi::Response::RaiseError
|
43
|
+
else
|
44
|
+
Faraday.register_middleware :request, desk_encode_json: DeskApi::Request::EncodeJson
|
45
|
+
Faraday.register_middleware :request, desk_oauth: DeskApi::Request::OAuth
|
46
|
+
Faraday.register_middleware :request, desk_retry: DeskApi::Request::Retry
|
47
|
+
Faraday.register_middleware :response, desk_parse_dates: DeskApi::Response::ParseDates
|
48
|
+
Faraday.register_middleware :response, desk_parse_json: DeskApi::Response::ParseJson
|
49
|
+
Faraday.register_middleware :response, desk_raise_error: DeskApi::Response::RaiseError
|
50
|
+
end
|
51
|
+
end
|
32
52
|
end
|
33
53
|
|
34
54
|
# if subdomain is set make sure endpoint is correct
|
@@ -38,28 +58,16 @@ module DeskApi::Configuration
|
|
38
58
|
|
39
59
|
def middleware
|
40
60
|
@middleware ||= Proc.new do |builder|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
else
|
52
|
-
builder.use FaradayMiddleware::EncodeJson
|
53
|
-
builder.use Faraday::Request::BasicAuthentication, @username, @password if basic_auth.values.all?
|
54
|
-
builder.use FaradayMiddleware::OAuth, oauth if oauth.values.all?
|
55
|
-
builder.use DeskApi::Request::Retry
|
56
|
-
|
57
|
-
builder.use FaradayMiddleware::ParseDates
|
58
|
-
builder.use DeskApi::Response::RaiseError, DeskApi::Error::ClientError
|
59
|
-
builder.use DeskApi::Response::RaiseError, DeskApi::Error::ServerError
|
60
|
-
builder.use FaradayMiddleware::ParseJson, content_type: /application\/json/
|
61
|
-
end
|
62
|
-
|
61
|
+
builder.request :desk_encode_json
|
62
|
+
builder.request :basic_auth, @username, @password if basic_auth.values.all?
|
63
|
+
builder.request :desk_oauth, oauth if oauth.values.all?
|
64
|
+
builder.request :desk_retry
|
65
|
+
|
66
|
+
builder.response :desk_parse_dates
|
67
|
+
builder.response :desk_raise_error, DeskApi::Error::ClientError
|
68
|
+
builder.response :desk_raise_error, DeskApi::Error::ServerError
|
69
|
+
builder.response :desk_parse_json
|
70
|
+
|
63
71
|
builder.adapter Faraday.default_adapter
|
64
72
|
end
|
65
73
|
end
|
@@ -136,4 +144,4 @@ private
|
|
136
144
|
raise(DeskApi::Error::ConfigurationError, "Invalid endpoint specified: `#{endpoint}` must be a valid url.")
|
137
145
|
end
|
138
146
|
end
|
139
|
-
end
|
147
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module DeskApi::Request
|
2
|
+
class EncodeJson < Faraday::Middleware
|
3
|
+
dependency 'json'
|
4
|
+
|
5
|
+
def call(env)
|
6
|
+
env[:request_headers]['Content-Type'] = 'application/json'
|
7
|
+
env[:body] = ::JSON.dump(env[:body]) if env[:body] and not env[:body].to_s.empty?
|
8
|
+
@app.call env
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module DeskApi::Request
|
2
|
+
class OAuth < Faraday::Middleware
|
3
|
+
dependency 'simple_oauth'
|
4
|
+
|
5
|
+
def initialize(app, options)
|
6
|
+
super(app)
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
env[:request_headers]['Authorization'] = oauth(env).to_s
|
12
|
+
@app.call env
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def oauth(env)
|
17
|
+
SimpleOAuth::Header.new env[:method], env[:url].to_s, {}, @options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,52 +1,47 @@
|
|
1
|
-
module DeskApi
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
1
|
+
module DeskApi::Request
|
2
|
+
class Retry < Faraday::Middleware
|
3
|
+
def initialize(app, options = {})
|
4
|
+
@max = options[:max] || 3
|
5
|
+
@interval = options[:interval] || 10
|
6
|
+
super(app)
|
7
|
+
end
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
raise
|
23
|
-
rescue exception_matcher
|
24
|
-
if retries > 0
|
25
|
-
retries -= 1
|
26
|
-
sleep @interval
|
27
|
-
env = env_clone
|
28
|
-
retry
|
29
|
-
end
|
30
|
-
raise
|
9
|
+
def call(env)
|
10
|
+
retries = @max
|
11
|
+
request_body = env[:body]
|
12
|
+
begin
|
13
|
+
env[:body] = request_body
|
14
|
+
@app.call(env)
|
15
|
+
rescue DeskApi::Error::TooManyRequests => e
|
16
|
+
if retries > 0
|
17
|
+
retries = 0
|
18
|
+
sleep e.rate_limit.reset_in
|
19
|
+
retry
|
31
20
|
end
|
21
|
+
raise
|
22
|
+
rescue exception_matcher
|
23
|
+
if retries > 0
|
24
|
+
retries -= 1
|
25
|
+
sleep @interval
|
26
|
+
retry
|
27
|
+
end
|
28
|
+
raise
|
32
29
|
end
|
30
|
+
end
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
32
|
+
def exception_matcher
|
33
|
+
exceptions = [Errno::ETIMEDOUT, 'Timeout::Error', Faraday::Error::TimeoutError]
|
34
|
+
matcher = Module.new
|
35
|
+
(class << matcher; self; end).class_eval do
|
36
|
+
define_method(:===) do |error|
|
37
|
+
exceptions.any? do |ex|
|
38
|
+
if ex.is_a? Module then error.is_a? ex
|
39
|
+
else error.class.to_s == ex.to_s
|
43
40
|
end
|
44
41
|
end
|
45
42
|
end
|
46
|
-
matcher
|
47
43
|
end
|
44
|
+
matcher
|
48
45
|
end
|
49
|
-
|
50
|
-
Faraday.register_middleware :request, retry: lambda { Retry }
|
51
46
|
end
|
52
|
-
end
|
47
|
+
end
|
data/lib/desk_api/resource.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
class DeskApi::Resource
|
2
|
+
# by_url is deprecated on resources
|
3
|
+
extend Forwardable
|
4
|
+
def_delegator :@_client, :by_url, :by_url
|
5
|
+
|
2
6
|
class << self
|
3
7
|
def build_self_link(link, params = {})
|
4
8
|
link = {'href'=>link} if link.kind_of?(String)
|
@@ -7,11 +11,13 @@ class DeskApi::Resource
|
|
7
11
|
end
|
8
12
|
|
9
13
|
def initialize(client, definition = {}, loaded = false)
|
10
|
-
|
14
|
+
reset!
|
15
|
+
@_client, @_definition, @_loaded = client, definition, loaded
|
16
|
+
# better default
|
11
17
|
end
|
12
18
|
|
13
19
|
def create(params = {})
|
14
|
-
|
20
|
+
new_resource(@_client.post(clean_base_url, params).body, true)
|
15
21
|
end
|
16
22
|
|
17
23
|
def update(params = {})
|
@@ -30,26 +36,51 @@ class DeskApi::Resource
|
|
30
36
|
params = { q: params } if params.kind_of?(String)
|
31
37
|
url = Addressable::URI.parse(clean_base_url + '/search')
|
32
38
|
url.query_values = params
|
33
|
-
|
39
|
+
new_resource(self.class.build_self_link(url.to_s))
|
34
40
|
end
|
35
41
|
|
36
42
|
def find(id, options = {})
|
37
|
-
res =
|
43
|
+
res = new_resource(self.class.build_self_link("#{clean_base_url}/#{id}"))
|
38
44
|
res.embed(*(options[:embed].kind_of?(Array) ? options[:embed] : [options[:embed]])) if options[:embed]
|
39
45
|
res.exec!
|
40
46
|
end
|
41
47
|
alias_method :by_id, :find
|
42
48
|
|
49
|
+
def next!
|
50
|
+
self.load
|
51
|
+
next_page = @_definition['_links']['next']
|
52
|
+
|
53
|
+
if next_page
|
54
|
+
@_definition = self.class.build_self_link(next_page)
|
55
|
+
self.reset!
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def all(&block)
|
61
|
+
raise ArgumentError, "Block must be given for #all" unless block_given?
|
62
|
+
each_page do |page, page_num|
|
63
|
+
page.entries.each { |resource| yield resource, page_num }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def each_page
|
68
|
+
raise ArgumentError, "Block must be given for #each_page" unless block_given?
|
69
|
+
page = self.first.per_page(self.query_params['per_page'] || 1000).dup
|
70
|
+
begin
|
71
|
+
yield page, page.page
|
72
|
+
end while page.next!
|
73
|
+
rescue NoMethodError => err
|
74
|
+
raise NoMethodError, "#each_page and #all are only available on resources which offer pagination"
|
75
|
+
end
|
76
|
+
|
77
|
+
|
43
78
|
def embed(*embedds)
|
44
79
|
# make sure we don't try to embed anything that's not defined
|
45
80
|
# add it to the query
|
46
81
|
self.tap{ |res| res.query_params = { embed: embedds.join(',') } }
|
47
82
|
end
|
48
83
|
|
49
|
-
def by_url(url)
|
50
|
-
self.class.new(@_client, self.class.build_self_link(url))
|
51
|
-
end
|
52
|
-
|
53
84
|
def get_self
|
54
85
|
@_definition['_links']['self']
|
55
86
|
end
|
@@ -63,6 +94,16 @@ class DeskApi::Resource
|
|
63
94
|
@_definition['_links']['self']['href'] = value
|
64
95
|
end
|
65
96
|
|
97
|
+
def to_hash
|
98
|
+
self.load
|
99
|
+
|
100
|
+
{}.tap do |hash|
|
101
|
+
@_definition.each do |k, v|
|
102
|
+
hash[k] = v
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
66
107
|
def resource_type
|
67
108
|
get_self['class']
|
68
109
|
end
|
@@ -100,7 +141,7 @@ class DeskApi::Resource
|
|
100
141
|
end
|
101
142
|
|
102
143
|
def respond_to?(method, include_private = false)
|
103
|
-
self.
|
144
|
+
self.load
|
104
145
|
meth = method.to_s
|
105
146
|
|
106
147
|
return true if is_embedded?(meth)
|
@@ -114,6 +155,15 @@ class DeskApi::Resource
|
|
114
155
|
def reload!
|
115
156
|
self.exec! true
|
116
157
|
end
|
158
|
+
alias_method :load!, :reload!
|
159
|
+
|
160
|
+
def load
|
161
|
+
self.exec! unless @_loaded
|
162
|
+
end
|
163
|
+
|
164
|
+
def loaded?
|
165
|
+
@_loaded
|
166
|
+
end
|
117
167
|
|
118
168
|
protected
|
119
169
|
|
@@ -127,11 +177,16 @@ protected
|
|
127
177
|
self
|
128
178
|
end
|
129
179
|
|
180
|
+
def reset!
|
181
|
+
@_links, @_embedded, @_changed, @_loaded = {}, {}, {}, false
|
182
|
+
self
|
183
|
+
end
|
184
|
+
|
130
185
|
private
|
131
|
-
attr_accessor :_client, :_loaded, :_changed, :_definition
|
186
|
+
attr_accessor :_client, :_loaded, :_changed, :_embedded, :_links, :_definition
|
132
187
|
|
133
188
|
def filter_update_actions(params = {})
|
134
|
-
params.select{ |key, _| key.to_s.include?('
|
189
|
+
params.select{ |key, _| key.to_s.include?('_action') }
|
135
190
|
end
|
136
191
|
|
137
192
|
def is_field?(method)
|
@@ -151,28 +206,37 @@ private
|
|
151
206
|
end
|
152
207
|
|
153
208
|
def get_embedded_resource(method)
|
154
|
-
|
209
|
+
return @_embedded[method] if @_embedded.key?(method)
|
210
|
+
@_embedded[method] = @_definition['_embedded'][method]
|
155
211
|
|
156
|
-
if
|
157
|
-
|
158
|
-
|
159
|
-
|
212
|
+
if @_embedded[method].kind_of?(Array)
|
213
|
+
@_embedded[method].tap do |ary|
|
214
|
+
ary.map!{ |definition| new_resource(definition, true) } unless ary.first.kind_of?(self.class)
|
215
|
+
end
|
160
216
|
else
|
161
|
-
|
217
|
+
@_embedded[method] = new_resource(@_embedded[method], true)
|
162
218
|
end
|
163
219
|
end
|
164
220
|
|
165
221
|
def get_linked_resource(method)
|
166
|
-
|
222
|
+
return @_links[method] if @_links.key?(method)
|
223
|
+
@_links[method] = @_definition['_links'][method]
|
224
|
+
|
225
|
+
if @_links[method] and not @_links[method].kind_of?(self.class)
|
226
|
+
@_links[method] = new_resource(self.class.build_self_link(@_links[method]))
|
227
|
+
end
|
228
|
+
end
|
167
229
|
|
168
|
-
|
169
|
-
|
230
|
+
def new_resource(definition, loaded=false, client=@_client)
|
231
|
+
self.class.new(client, definition, loaded)
|
232
|
+
end
|
170
233
|
|
171
|
-
|
234
|
+
def request(method, url, params={}, client=@_client)
|
235
|
+
client.send(method, url, params)
|
172
236
|
end
|
173
237
|
|
174
238
|
def method_missing(method, *args, &block)
|
175
|
-
self.
|
239
|
+
self.load
|
176
240
|
|
177
241
|
meth = method.to_s
|
178
242
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module DeskApi::Response
|
2
|
+
class ParseDates < Faraday::Response::Middleware
|
3
|
+
dependency 'time'
|
4
|
+
|
5
|
+
def on_complete(env)
|
6
|
+
env[:body] = parse_dates env[:body]
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def parse_dates(value)
|
12
|
+
case value
|
13
|
+
when Hash
|
14
|
+
value.each_pair do |key, element|
|
15
|
+
value[key] = parse_dates element
|
16
|
+
end
|
17
|
+
when Array
|
18
|
+
value.each_with_index do |element, index|
|
19
|
+
value[index] = parse_dates element
|
20
|
+
end
|
21
|
+
when /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z\Z/m
|
22
|
+
Time.parse value
|
23
|
+
else
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|