zendesk_api 1.37.0 → 3.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c5a2ced45e0201f6f9a45e5b8f7cf6951ca92c15ce893283c2289d0b260dc77
4
- data.tar.gz: 31fa7566865e7191f49dadf6a5e01573264f4fc62ddfd4f635f8f7edd4be9ab2
3
+ metadata.gz: 8ecc2ccbe7be3ec6da2b36fdcd7b75004fcecd91a26de63d0bb561dcddff86cc
4
+ data.tar.gz: c4b7a7d6baa3246d2835251d03d2a7c0fd69961fd2ca3575a7486f3a7adf06f6
5
5
  SHA512:
6
- metadata.gz: a1b355c67c8126f69f32ff6cd24d03b81b75eec27a0a72044383d0e06a871ba5bd18778119523a013725162048393d7a6bf58f075013e852303255b78bccb73f
7
- data.tar.gz: 78ecdd8fd4d2fd889df06aea1ac98df7c68e6f89378f1358594b30853b23b3179f304ee4d87a781bda0047bc1970b8c28dfd147907d74223e28ffceb1676d1b1
6
+ metadata.gz: 9183c973ac61c198dd69d975c5bc9eb27cc424b47e50027d32c2a462f651b08681925b00fd4686d248b615a80445c34b59273861a164917ea6738b54d04c1a4b
7
+ data.tar.gz: 980637e5be8ba003774a6fe5fe53dc2a4003ba6e58b933d21aaba66cb9c66eb0dd3f706ac6b2e69740f1c22cfe2a3d4c7301a7cfd313c0753ef3cff7cbc2683b
@@ -1,5 +1,3 @@
1
- require 'faraday'
2
-
3
1
  require 'zendesk_api/version'
4
2
  require 'zendesk_api/sideloading'
5
3
  require 'zendesk_api/configuration'
@@ -26,7 +24,7 @@ module ZendeskAPI
26
24
  # The top-level class that handles configuration and connection to the Zendesk API.
27
25
  # Can also be used as an accessor to resource collections.
28
26
  class Client
29
- GZIP_EXCEPTIONS = [:em_http, :httpclient]
27
+ GZIP_EXCEPTIONS = [:em_http, :httpclient, :httpx]
30
28
 
31
29
  # @return [Configuration] Config instance
32
30
  attr_reader :config
@@ -39,24 +37,25 @@ module ZendeskAPI
39
37
  def method_missing(method, *args, &block)
40
38
  method = method.to_s
41
39
  options = args.last.is_a?(Hash) ? args.pop : {}
42
-
43
40
  unless config.use_resource_cache
44
- raise "Resource for #{method} does not exist" unless method_as_class(method)
45
- return ZendeskAPI::Collection.new(self, method_as_class(method), options)
41
+ resource_class = resource_class_for(method)
42
+ raise "Resource for #{method} does not exist" unless resource_class
43
+ return ZendeskAPI::Collection.new(self, resource_class, options)
46
44
  end
47
45
 
48
46
  @resource_cache[method] ||= { :class => nil, :cache => ZendeskAPI::LRUCache.new }
49
47
  if !options.delete(:reload) && (cached = @resource_cache[method][:cache].read(options.hash))
50
48
  cached
51
49
  else
52
- @resource_cache[method][:class] ||= method_as_class(method)
50
+ @resource_cache[method][:class] ||= resource_class_for(method)
53
51
  raise "Resource for #{method} does not exist" unless @resource_cache[method][:class]
54
52
  @resource_cache[method][:cache].write(options.hash, ZendeskAPI::Collection.new(self, @resource_cache[method][:class], options))
55
53
  end
56
54
  end
57
55
 
58
56
  def respond_to?(method, *args)
59
- ((cache = @resource_cache[method]) && cache[:class]) || !method_as_class(method).nil? || super
57
+ cache = @resource_cache[method]
58
+ !!(cache.to_h[:class] || resource_class_for(method) || super)
60
59
  end
61
60
 
62
61
  # Returns the current user (aka me)
@@ -100,9 +99,7 @@ module ZendeskAPI
100
99
  config.retry = !!config.retry # nil -> false
101
100
 
102
101
  set_raise_error_when_rated_limited
103
-
104
102
  set_token_auth
105
-
106
103
  set_default_logger
107
104
  add_warning_callback
108
105
  end
@@ -112,7 +109,6 @@ module ZendeskAPI
112
109
  # @return [Faraday::Connection] Faraday connection for the client
113
110
  def connection
114
111
  @connection ||= build_connection
115
- return @connection
116
112
  end
117
113
 
118
114
  # Pushes a callback onto the stack. Callbacks are executed on responses, last in the Faraday middleware stack.
@@ -155,7 +151,6 @@ module ZendeskAPI
155
151
  builder.use ZendeskAPI::Middleware::Response::ParseIsoDates
156
152
  builder.use ZendeskAPI::Middleware::Response::ParseJson
157
153
  builder.use ZendeskAPI::Middleware::Response::SanitizeResponse
158
-
159
154
  adapter = config.adapter || Faraday.default_adapter
160
155
 
161
156
  unless GZIP_EXCEPTIONS.include?(adapter)
@@ -163,14 +158,7 @@ module ZendeskAPI
163
158
  builder.use ZendeskAPI::Middleware::Response::Deflate
164
159
  end
165
160
 
166
- # request
167
- if config.access_token && !config.url_based_access_token
168
- builder.request(:authorization, "Bearer", config.access_token)
169
- elsif config.access_token
170
- builder.use ZendeskAPI::Middleware::Request::UrlBasedAccessToken, config.access_token
171
- else
172
- builder.use Faraday::Request::BasicAuthentication, config.username, config.password
173
- end
161
+ set_authentication(builder, config)
174
162
 
175
163
  if config.cache
176
164
  builder.use ZendeskAPI::Middleware::Request::EtagCache, :cache => config.cache
@@ -181,20 +169,25 @@ module ZendeskAPI
181
169
  builder.use ZendeskAPI::Middleware::Request::EncodeJson
182
170
 
183
171
  # Should always be first in the stack
184
- builder.use ZendeskAPI::Middleware::Request::Retry, :logger => config.logger, :retry_codes => config.retry_codes, :retry_on_exception => config.retry_on_exception if config.retry
172
+ if config.retry
173
+ builder.use ZendeskAPI::Middleware::Request::Retry,
174
+ :logger => config.logger,
175
+ :retry_codes => config.retry_codes,
176
+ :retry_on_exception => config.retry_on_exception
177
+ end
185
178
  if config.raise_error_when_rate_limited
186
179
  builder.use ZendeskAPI::Middleware::Request::RaiseRateLimited, :logger => config.logger
187
180
  end
188
181
 
189
- builder.adapter(*adapter)
182
+ builder.adapter(*adapter, &config.adapter_proc)
190
183
  end
191
184
  end
192
185
 
193
186
  private
194
187
 
195
- def method_as_class(method)
196
- klass_as_string = ZendeskAPI::Helpers.modulize_string(Inflection.singular(method.to_s.gsub(/\W/, '')))
197
- ZendeskAPI::Association.class_from_namespace(klass_as_string)
188
+ def resource_class_for(method)
189
+ resource_name = ZendeskAPI::Helpers.modulize_string(Inflection.singular(method.to_s.gsub(/\W/, '')))
190
+ ZendeskAPI::Association.class_from_namespace(resource_name)
198
191
  end
199
192
 
200
193
  def check_url
@@ -239,5 +232,16 @@ module ZendeskAPI
239
232
  end
240
233
  end
241
234
  end
235
+
236
+ # See https://lostisland.github.io/faraday/middleware/authentication
237
+ def set_authentication(builder, config)
238
+ if config.access_token && !config.url_based_access_token
239
+ builder.request :authorization, "Bearer", config.access_token
240
+ elsif config.access_token
241
+ builder.use ZendeskAPI::Middleware::Request::UrlBasedAccessToken, config.access_token
242
+ else
243
+ builder.request :authorization, :basic, config.username, config.password
244
+ end
245
+ end
242
246
  end
243
247
  end
@@ -1,12 +1,14 @@
1
1
  require 'zendesk_api/resource'
2
2
  require 'zendesk_api/resources'
3
3
  require 'zendesk_api/search'
4
+ require 'zendesk_api/pagination'
4
5
 
5
6
  module ZendeskAPI
6
7
  # Represents a collection of resources. Lazily loaded, resources aren't
7
8
  # actually fetched until explicitly needed (e.g. #each, {#fetch}).
8
9
  class Collection
9
10
  include ZendeskAPI::Sideloading
11
+ include Pagination
10
12
 
11
13
  # Options passed in that are automatically converted from an array to a comma-separated list.
12
14
  SPECIALLY_JOINED_PARAMS = [:ids, :only]
@@ -114,30 +116,6 @@ module ZendeskAPI
114
116
  @count || -1
115
117
  end
116
118
 
117
- # Changes the per_page option. Returns self, so it can be chained. No execution.
118
- # @return [Collection] self
119
- def per_page(count)
120
- clear_cache if count
121
- @options["per_page"] = count
122
- self
123
- end
124
-
125
- # Changes the page option. Returns self, so it can be chained. No execution.
126
- # @return [Collection] self
127
- def page(number)
128
- clear_cache if number
129
- @options["page"] = number
130
- self
131
- end
132
-
133
- def first_page?
134
- !@prev_page
135
- end
136
-
137
- def last_page?
138
- !@next_page || @next_page == @query
139
- end
140
-
141
119
  # Saves all newly created resources stored in this collection.
142
120
  # @return [Collection] self
143
121
  def save
@@ -186,17 +164,8 @@ module ZendeskAPI
186
164
  elsif association && association.options.parent && association.options.parent.new_record?
187
165
  return (@resources = [])
188
166
  end
189
- path_query_link = (@query || path)
190
-
191
- @response = get_response(path_query_link)
192
-
193
- if path_query_link == "search/export"
194
- handle_cursor_response(@response.body)
195
- else
196
- handle_response(@response.body)
197
- end
198
167
 
199
- @resources
168
+ get_resources(@query || path)
200
169
  end
201
170
 
202
171
  def fetch(*args)
@@ -252,10 +221,12 @@ module ZendeskAPI
252
221
  # * If there is a next_page url cached, it executes a fetch on that url and returns the results.
253
222
  # * Otherwise, returns an empty array.
254
223
  def next
255
- if @options["page"]
224
+ if @options["page"] && !cbp_request?
256
225
  clear_cache
257
- @options["page"] += 1
226
+ @options["page"] = @options["page"].to_i + 1
258
227
  elsif (@query = @next_page)
228
+ # Send _only_ url param "?page[after]=token" to get the next page
229
+ @options.page&.delete("before")
259
230
  fetch(true)
260
231
  else
261
232
  clear_cache
@@ -268,10 +239,12 @@ module ZendeskAPI
268
239
  # * If there is a prev_page url cached, it executes a fetch on that url and returns the results.
269
240
  # * Otherwise, returns an empty array.
270
241
  def prev
271
- if @options["page"] && @options["page"] > 1
242
+ if !cbp_request? && @options["page"].to_i > 1
272
243
  clear_cache
273
244
  @options["page"] -= 1
274
245
  elsif (@query = @prev_page)
246
+ # Send _only_ url param "?page[before]=token" to get the prev page
247
+ @options.page&.delete("after")
275
248
  fetch(true)
276
249
  else
277
250
  clear_cache
@@ -326,22 +299,13 @@ module ZendeskAPI
326
299
  map(&:to_param)
327
300
  end
328
301
 
329
- def more_results?(response)
330
- response["meta"].present? && response["results"].present?
331
- end
332
- alias_method :has_more_results?, :more_results? # For backward compatibility with 1.33.0 and 1.34.0
333
-
334
- def get_response_body(link)
335
- @client.connection.send("get", link).body
336
- end
337
-
338
302
  def get_next_page_data(original_response_body)
339
303
  link = original_response_body["links"]["next"]
340
-
304
+ result_key = @resource_class.model_key || "results"
341
305
  while link
342
- response = get_response_body(link)
306
+ response = @client.connection.send("get", link).body
343
307
 
344
- original_response_body["results"] = original_response_body["results"] + response["results"]
308
+ original_response_body[result_key] = original_response_body[result_key] + response[result_key]
345
309
 
346
310
  link = response["meta"]["has_more"] ? response["links"]["next"] : nil
347
311
  end
@@ -351,14 +315,20 @@ module ZendeskAPI
351
315
 
352
316
  private
353
317
 
354
- def set_page_and_count(body)
355
- @count = (body["count"] || @resources.size).to_i
356
- @next_page, @prev_page = body["next_page"], body["previous_page"]
318
+ def get_resources(path_query_link)
319
+ if intentional_obp_request?
320
+ warn "Offset Based Pagination will be deprecated soon"
321
+ elsif supports_cbp? && first_cbp_request?
322
+ # only set cbp options if it's the first request, otherwise the options would be already in place
323
+ set_cbp_options
324
+ end
325
+ @response = get_response(path_query_link)
357
326
 
358
- if @next_page =~ /page=(\d+)/
359
- @options["page"] = $1.to_i - 1
360
- elsif @prev_page =~ /page=(\d+)/
361
- @options["page"] = $1.to_i + 1
327
+ # Keep pre-existing behaviour for search/export
328
+ if path_query_link == "search/export"
329
+ handle_search_export_response(@response.body)
330
+ else
331
+ handle_response(@response.body)
362
332
  end
363
333
  end
364
334
 
@@ -370,13 +340,7 @@ module ZendeskAPI
370
340
 
371
341
  while (bang ? fetch! : fetch)
372
342
  each do |resource|
373
- arguments = [resource, @options["page"] || 1]
374
-
375
- if block.arity >= 0
376
- arguments = arguments.take(block.arity)
377
- end
378
-
379
- block.call(*arguments)
343
+ block.call(resource, @options["page"] || 1)
380
344
  end
381
345
 
382
346
  last_page? ? break : self.next
@@ -422,7 +386,7 @@ module ZendeskAPI
422
386
 
423
387
  def get_response(path)
424
388
  @error = nil
425
- @response = @client.connection.send(@verb || "get", path) do |req|
389
+ @client.connection.send(@verb || "get", path) do |req|
426
390
  opts = @options.delete_if { |_, v| v.nil? }
427
391
 
428
392
  req.params.merge!(:include => @includes.join(",")) if @includes.any?
@@ -435,36 +399,30 @@ module ZendeskAPI
435
399
  end
436
400
  end
437
401
 
438
- def handle_cursor_response(response_body)
439
- unless response_body.is_a?(Hash)
440
- raise ZendeskAPI::Error::NetworkError, @response.env
441
- end
402
+ def handle_search_export_response(response_body)
403
+ assert_valid_response_body(response_body)
442
404
 
405
+ # Note this doesn't happen in #handle_response
443
406
  response_body = get_next_page_data(response_body) if more_results?(response_body)
444
407
 
445
408
  body = response_body.dup
446
409
  results = body.delete(@resource_class.model_key) || body.delete("results")
447
410
 
448
- unless results
449
- raise ZendeskAPI::Error::ClientError, "Expected #{@resource_class.model_key} or 'results' in response keys: #{body.keys.inspect}"
450
- end
411
+ assert_results(results, body)
451
412
 
452
413
  @resources = results.map do |res|
453
414
  wrap_resource(res)
454
415
  end
455
416
  end
456
417
 
418
+ # For both CBP and OBP
457
419
  def handle_response(response_body)
458
- unless response_body.is_a?(Hash)
459
- raise ZendeskAPI::Error::NetworkError, @response.env
460
- end
420
+ assert_valid_response_body(response_body)
461
421
 
462
422
  body = response_body.dup
463
423
  results = body.delete(@resource_class.model_key) || body.delete("results")
464
424
 
465
- unless results
466
- raise ZendeskAPI::Error::ClientError, "Expected #{@resource_class.model_key} or 'results' in response keys: #{body.keys.inspect}"
467
- end
425
+ assert_results(results, body)
468
426
 
469
427
  @resources = results.map do |res|
470
428
  wrap_resource(res)
@@ -472,6 +430,8 @@ module ZendeskAPI
472
430
 
473
431
  set_page_and_count(body)
474
432
  set_includes(@resources, @includes, body)
433
+
434
+ @resources
475
435
  end
476
436
 
477
437
  # Simplified Associations#wrap_resource
@@ -501,9 +461,13 @@ module ZendeskAPI
501
461
  to_a.public_send(name, *args, &block)
502
462
  end
503
463
 
464
+ # If you call client.tickets.foo - and foo is not an attribute nor an association, it ends up here, as a new collection
504
465
  def next_collection(name, *args, &block)
505
466
  opts = args.last.is_a?(Hash) ? args.last : {}
506
- opts.merge!(:collection_path => @collection_path.dup.push(name))
467
+ opts.merge!(collection_path: [*@collection_path, name], page: nil)
468
+ # Why `page: nil`?
469
+ # when you do client.tickets.fetch followed by client.tickets.foos => the request to /tickets/foos will
470
+ # have the options page set to whatever the last options were for the tickets collection
507
471
  self.class.new(@client, @resource_class, @options.merge(opts))
508
472
  end
509
473
 
@@ -514,5 +478,16 @@ module ZendeskAPI
514
478
  def resource_methods
515
479
  @resource_methods ||= @resource_class.singleton_methods(false).map(&:to_sym)
516
480
  end
481
+
482
+ def assert_valid_response_body(response_body)
483
+ unless response_body.is_a?(Hash)
484
+ raise ZendeskAPI::Error::NetworkError, @response.env
485
+ end
486
+ end
487
+
488
+ def assert_results(results, body)
489
+ return if results
490
+ raise ZendeskAPI::Error::ClientError, "Expected #{@resource_class.model_key} or 'results' in response keys: #{body.keys.inspect}"
491
+ end
517
492
  end
518
493
  end
@@ -28,6 +28,9 @@ module ZendeskAPI
28
28
  # @return [Symbol] Faraday adapter
29
29
  attr_accessor :adapter
30
30
 
31
+ # @return [Proc] Faraday adapter proc
32
+ attr_accessor :adapter_proc
33
+
31
34
  # @return [Boolean] Whether to allow non-HTTPS connections for development purposes.
32
35
  attr_accessor :allow_http
33
36
 
@@ -33,12 +33,7 @@ module ZendeskAPI
33
33
  private
34
34
 
35
35
  def generate_error_msg(response_body)
36
- return unless response_body["description"] || response_body["message"]
37
-
38
- [
39
- response_body["description"],
40
- response_body["message"]
41
- ].compact.join(" - ")
36
+ response_body.values_at("description", "message", "error", "errors").compact.join(" - ")
42
37
  end
43
38
  end
44
39
 
@@ -1,6 +1,10 @@
1
1
  module ZendeskAPI
2
2
  # @private
3
3
  module Helpers
4
+ def self.present?(value)
5
+ ![nil, false, "", " ", [], {}].include?(value)
6
+ end
7
+
4
8
  # From https://github.com/rubyworks/facets/blob/master/lib/core/facets/string/modulize.rb
5
9
  # Converts a string to module name representation.
6
10
  #
@@ -6,7 +6,6 @@ module ZendeskAPI
6
6
  class EncodeJson < Faraday::Middleware
7
7
  CONTENT_TYPE = 'Content-Type'.freeze
8
8
  MIME_TYPE = 'application/json'.freeze
9
- dependency 'json'
10
9
 
11
10
  def call(env)
12
11
  type = env[:request_headers][CONTENT_TYPE].to_s
@@ -4,7 +4,7 @@ module ZendeskAPI
4
4
  module Middleware
5
5
  module Response
6
6
  # @private
7
- class Callback < Faraday::Response::Middleware
7
+ class Callback < Faraday::Middleware
8
8
  def initialize(app, client)
9
9
  super(app)
10
10
  @client = client
@@ -5,11 +5,12 @@ module ZendeskAPI
5
5
  module Response
6
6
  # Faraday middleware to handle content-encoding = inflate
7
7
  # @private
8
- class Deflate < Faraday::Response::Middleware
8
+ class Deflate < Faraday::Middleware
9
9
  def on_complete(env)
10
- if !env.body.strip.empty? && env[:response_headers]['content-encoding'] == "deflate"
11
- env.body = Zlib::Inflate.inflate(env.body)
12
- end
10
+ return if env[:response_headers]['content-encoding'] != "deflate"
11
+ return if env.body.strip.empty?
12
+
13
+ env.body = Zlib::Inflate.inflate(env.body)
13
14
  end
14
15
  end
15
16
  end
@@ -7,11 +7,12 @@ module ZendeskAPI
7
7
  # @private
8
8
  module Response
9
9
  # Faraday middleware to handle content-encoding = gzip
10
- class Gzip < Faraday::Response::Middleware
10
+ class Gzip < Faraday::Middleware
11
11
  def on_complete(env)
12
- if !env[:body].strip.empty? && env[:response_headers]['content-encoding'] == "gzip"
13
- env[:body] = Zlib::GzipReader.new(StringIO.new(env[:body])).read
14
- end
12
+ return if env[:response_headers]['content-encoding'] != "gzip"
13
+ return if env[:body].force_encoding(Encoding::BINARY).strip.empty?
14
+
15
+ env[:body] = Zlib::GzipReader.new(StringIO.new(env[:body])).read
15
16
  end
16
17
  end
17
18
  end
@@ -6,7 +6,7 @@ module ZendeskAPI
6
6
  module Response
7
7
  # Parse ISO dates from response body
8
8
  # @private
9
- class ParseIsoDates < Faraday::Response::Middleware
9
+ class ParseIsoDates < Faraday::Middleware
10
10
  def call(env)
11
11
  @app.call(env).on_complete do |env|
12
12
  parse_dates!(env[:body])
@@ -3,9 +3,8 @@ module ZendeskAPI
3
3
  module Middleware
4
4
  # @private
5
5
  module Response
6
- class ParseJson < Faraday::Response::Middleware
6
+ class ParseJson < Faraday::Middleware
7
7
  CONTENT_TYPE = 'Content-Type'.freeze
8
- dependency 'json'
9
8
 
10
9
  def on_complete(env)
11
10
  type = env[:response_headers][CONTENT_TYPE].to_s
@@ -1,7 +1,7 @@
1
1
  module ZendeskAPI
2
2
  module Middleware
3
3
  module Response
4
- class SanitizeResponse < Faraday::Response::Middleware
4
+ class SanitizeResponse < Faraday::Middleware
5
5
  def on_complete(env)
6
6
  env[:body].scrub!('')
7
7
  end
@@ -0,0 +1,99 @@
1
+ module ZendeskAPI
2
+ class Collection
3
+ # Contains all methods related to pagination in an attempt to slim down collection.rb
4
+ module Pagination
5
+ DEFAULT_PAGE_SIZE = 100
6
+ def more_results?(response)
7
+ Helpers.present?(response["meta"]) && response["meta"]["has_more"]
8
+ end
9
+ alias has_more_results? more_results? # For backward compatibility with 1.33.0 and 1.34.0
10
+
11
+ # Changes the per_page option. Returns self, so it can be chained. No execution.
12
+ # @return [Collection] self
13
+ def per_page(count)
14
+ clear_cache if count
15
+ @options["per_page"] = count
16
+ self
17
+ end
18
+
19
+ # Changes the page option. Returns self, so it can be chained. No execution.
20
+ # @return [Collection] self
21
+ def page(number)
22
+ clear_cache if number
23
+ @options["page"] = number
24
+ self
25
+ end
26
+
27
+ def first_page?
28
+ !@prev_page
29
+ end
30
+
31
+ def last_page?
32
+ !@next_page || @next_page == @query
33
+ end
34
+
35
+ private
36
+
37
+ def page_links(body)
38
+ if body["meta"] && body["links"]
39
+ [body["links"]["next"], body["links"]["prev"]]
40
+ else
41
+ [body["next_page"], body["previous_page"]]
42
+ end
43
+ end
44
+
45
+ def cbp_response?(body)
46
+ !!(body["meta"] && body["links"])
47
+ end
48
+
49
+ def set_cbp_options
50
+ @options_per_page_was = @options.delete("per_page")
51
+ # Default to CBP by using the page param as a map
52
+ @options.page = { size: (@options_per_page_was || DEFAULT_PAGE_SIZE) }
53
+ end
54
+
55
+ # CBP requests look like: `/resources?page[size]=100`
56
+ # OBP requests look like: `/resources?page=2`
57
+ def cbp_request?
58
+ @options["page"].is_a?(Hash)
59
+ end
60
+
61
+ def intentional_obp_request?
62
+ Helpers.present?(@options["page"]) && !cbp_request?
63
+ end
64
+
65
+ def supports_cbp?
66
+ @resource_class.cbp_path_regexes.any? { |supported_path_regex| path.match?(supported_path_regex) }
67
+ end
68
+
69
+ def first_cbp_request?
70
+ # @next_page will be nil when making the first cbp request
71
+ @next_page.nil?
72
+ end
73
+
74
+ def set_page_and_count(body)
75
+ @count = (body["count"] || @resources.size).to_i
76
+ @next_page, @prev_page = page_links(body)
77
+
78
+ if cbp_response?(body)
79
+ set_cbp_response_options(body)
80
+ elsif @next_page =~ /page=(\d+)/
81
+ @options["page"] = Regexp.last_match(1).to_i - 1
82
+ elsif @prev_page =~ /page=(\d+)/
83
+ @options["page"] = Regexp.last_match(1).to_i + 1
84
+ end
85
+ end
86
+
87
+ def set_cbp_response_options(body)
88
+ @options.page = {} unless cbp_request?
89
+ # the line above means an intentional CBP request where page[size] is passed on the query
90
+ # this is to cater for CBP responses where we don't specify page[size] but the endpoint
91
+ # responds CBP by default. i.e `client.trigger_categories.fetch`
92
+ @options.page.merge!(
93
+ before: body["meta"]["before_cursor"],
94
+ after: body["meta"]["after_cursor"]
95
+ )
96
+ end
97
+ end
98
+ end
99
+ end
@@ -39,6 +39,14 @@ module ZendeskAPI
39
39
  def namespace(namespace)
40
40
  @namespace = namespace
41
41
  end
42
+
43
+ def new_from_response(client, response, includes = nil)
44
+ new(client).tap do |resource|
45
+ resource.handle_response(response)
46
+ resource.set_includes(resource, includes, response.body) if includes
47
+ resource.attributes.clear_changes
48
+ end
49
+ end
42
50
  end
43
51
 
44
52
  # @return [Hash] The resource's attributes
@@ -123,19 +131,16 @@ module ZendeskAPI
123
131
 
124
132
  # Compares resources by class and id. If id is nil, then by object_id
125
133
  def ==(other)
134
+ return false unless other
135
+
126
136
  return true if other.object_id == object_id
127
137
 
128
- if other && !(other.is_a?(Data) || other.is_a?(Integer))
129
- warn "Trying to compare #{other.class} to a Resource from #{caller.first}"
130
- end
138
+ return other.id && (other.id == id) if other.is_a?(Data)
131
139
 
132
- if other.is_a?(Data)
133
- other.id && other.id == id
134
- elsif other.is_a?(Integer)
135
- id == other
136
- else
137
- false
138
- end
140
+ return id == other if other.is_a?(Integer)
141
+
142
+ warn "Trying to compare #{other.class} to a Resource
143
+ from #{caller.first}"
139
144
  end
140
145
  alias :eql :==
141
146
 
@@ -163,6 +168,10 @@ module ZendeskAPI
163
168
  class DataResource < Data
164
169
  attr_accessor :error, :error_message
165
170
  extend Verbs
171
+
172
+ def self.cbp_path_regexes
173
+ []
174
+ end
166
175
  end
167
176
 
168
177
  # Represents a resource that can only GET
@@ -24,6 +24,10 @@ module ZendeskAPI
24
24
 
25
25
  class Topic < Resource
26
26
  class << self
27
+ def cbp_path_regexes
28
+ [%r{^community/topics$}]
29
+ end
30
+
27
31
  def resource_path
28
32
  "community/topics"
29
33
  end
@@ -83,6 +87,10 @@ module ZendeskAPI
83
87
  def attributes_for_save
84
88
  { self.class.resource_name => [id] }
85
89
  end
90
+
91
+ def self.cbp_path_regexes
92
+ [/^tags$/]
93
+ end
86
94
  end
87
95
 
88
96
  class Attachment < ReadResource
@@ -152,9 +160,17 @@ module ZendeskAPI
152
160
  def self.incremental_export(client, start_time)
153
161
  ZendeskAPI::Collection.new(client, self, :path => "incremental/organizations?start_time=#{start_time.to_i}")
154
162
  end
163
+
164
+ def self.cbp_path_regexes
165
+ [/^organizations$/]
166
+ end
155
167
  end
156
168
 
157
169
  class Brand < Resource
170
+ def self.cbp_path_regexes
171
+ [/^brands$/]
172
+ end
173
+
158
174
  def destroy!
159
175
  self.active = false
160
176
  save!
@@ -180,6 +196,10 @@ module ZendeskAPI
180
196
 
181
197
  has User
182
198
  has Organization
199
+
200
+ def self.cbp_path_regexes
201
+ [%r{^organizations/\d+/subscriptions$}]
202
+ end
183
203
  end
184
204
 
185
205
  class Category < Resource
@@ -228,6 +248,18 @@ module ZendeskAPI
228
248
  has_many Vote
229
249
  class Translation < Resource; end
230
250
  has_many Translation
251
+ class Label < DataResource
252
+ include Read
253
+ include Create
254
+ include Destroy
255
+
256
+ def destroy!
257
+ super do |req|
258
+ req.path = path
259
+ end
260
+ end
261
+ end
262
+ has_many Label
231
263
  end
232
264
 
233
265
  class TopicSubscription < Resource
@@ -246,15 +278,19 @@ module ZendeskAPI
246
278
  end
247
279
 
248
280
  class Topic < Resource
249
- has_many :subscriptions, :class => TopicSubscription, :inline => true
250
- has_many Tag, :extend => Tag::Update, :inline => :create
281
+ has_many :subscriptions, class: TopicSubscription, inline: true
282
+ has_many Tag, extend: Tag::Update, inline: :create
251
283
  has_many Attachment
252
- has_many :uploads, :class => Attachment, :inline => true
284
+ has_many :uploads, class: Attachment, inline: true
253
285
  end
254
286
 
255
287
  class Activity < Resource
256
288
  has User
257
289
  has :actor, :class => User
290
+
291
+ def self.cbp_path_regexes
292
+ [/^activities$/]
293
+ end
258
294
  end
259
295
 
260
296
  class Setting < UpdateResource
@@ -306,7 +342,7 @@ module ZendeskAPI
306
342
  class Comment < DataResource
307
343
  include Save
308
344
 
309
- has_many :uploads, :class => Attachment, :inline => true
345
+ has_many :uploads, class: Attachment, inline: true
310
346
  has :author, :class => User
311
347
 
312
348
  def save
@@ -337,10 +373,18 @@ module ZendeskAPI
337
373
  namespace 'portal'
338
374
  end
339
375
 
340
- class TicketField < Resource; end
376
+ class TicketField < Resource
377
+ def self.cbp_path_regexes
378
+ [/^ticket_fields$/]
379
+ end
380
+ end
341
381
 
342
382
  class TicketMetric < DataResource
343
383
  include Read
384
+
385
+ def self.cbp_path_regexes
386
+ [/^ticket_metrics$/]
387
+ end
344
388
  end
345
389
 
346
390
  class TicketRelated < DataResource; end
@@ -348,7 +392,7 @@ module ZendeskAPI
348
392
  class TicketEvent < DataResource
349
393
  class Event < Data; end
350
394
 
351
- has_many :child_events, :class => Event
395
+ has_many :child_events, class: Event
352
396
  has Ticket
353
397
  has :updater, :class => User
354
398
 
@@ -366,6 +410,10 @@ module ZendeskAPI
366
410
  extend UpdateMany
367
411
  extend DestroyMany
368
412
 
413
+ def self.cbp_path_regexes
414
+ [/^tickets$/, %r{organizations/\d+/tickets}]
415
+ end
416
+
369
417
  # Unlike other attributes, "comment" is not a property of the ticket,
370
418
  # but is used as a "comment on save", so it should be kept unchanged,
371
419
  # See https://github.com/zendesk/zendesk_api_client_rb/issues/321
@@ -384,13 +432,17 @@ module ZendeskAPI
384
432
  has :author, :class => User
385
433
 
386
434
  has_many Event
435
+
436
+ def self.cbp_path_regexes
437
+ [%r{^tickets/\d+/audits$}]
438
+ end
387
439
  end
388
440
 
389
441
  class Comment < DataResource
390
442
  include Save
391
443
 
392
- has_many :uploads, :class => Attachment, :inline => true
393
- has :author, :class => User
444
+ has_many :uploads, class: Attachment, inline: true
445
+ has :author, class: User
394
446
 
395
447
  def save
396
448
  if new_record?
@@ -417,35 +469,35 @@ module ZendeskAPI
417
469
  has :submitter, :class => User
418
470
  has :assignee, :class => User
419
471
 
420
- has_many :collaborators, :class => User, :inline => true, :extend => (Module.new do
472
+ has_many :collaborators, class: User, inline: true, extend: (Module.new do
421
473
  def to_param
422
474
  map(&:id)
423
475
  end
424
476
  end)
425
477
 
426
478
  has_many Audit
427
- has :metrics, :class => TicketMetric
479
+ has :metrics, class: TicketMetric
428
480
  has Group
429
481
  has Organization
430
482
  has Brand
431
- has :related, :class => TicketRelated
483
+ has :related, class: TicketRelated
432
484
 
433
- has Comment, :inline => true
485
+ has Comment, inline: true
434
486
  has_many Comment
435
487
 
436
- has :last_comment, :class => Comment, :inline => true
437
- has_many :last_comments, :class => Comment, :inline => true
488
+ has :last_comment, class: Comment, inline: true
489
+ has_many :last_comments, class: Comment, inline: true
438
490
 
439
- has_many Tag, :extend => Tag::Update, :inline => :create
491
+ has_many Tag, extend: Tag::Update, inline: :create
440
492
 
441
- has_many :incidents, :class => Ticket
493
+ has_many :incidents, class: Ticket
442
494
 
443
495
  # Gets a incremental export of tickets from the start_time until now.
444
496
  # @param [Client] client The {Client} object to be used
445
497
  # @param [Integer] start_time The start_time parameter
446
498
  # @return [Collection] Collection of {Ticket}
447
499
  def self.incremental_export(client, start_time)
448
- ZendeskAPI::Collection.new(client, self, :path => "incremental/tickets?start_time=#{start_time.to_i}")
500
+ ZendeskAPI::Collection.new(client, self, path: "incremental/tickets?start_time=#{start_time.to_i}")
449
501
  end
450
502
 
451
503
  # Imports a ticket through the imports/tickets endpoint using save!
@@ -454,7 +506,7 @@ module ZendeskAPI
454
506
  # @return [Ticket] Created object or nil
455
507
  def self.import!(client, attributes)
456
508
  new(client, attributes).tap do |ticket|
457
- ticket.save!(:path => "imports/tickets")
509
+ ticket.save!(path: "imports/tickets")
458
510
  end
459
511
  end
460
512
 
@@ -464,7 +516,7 @@ module ZendeskAPI
464
516
  # @return [Ticket] Created object or nil
465
517
  def self.import(client, attributes)
466
518
  ticket = new(client, attributes)
467
- return unless ticket.save(:path => "imports/tickets")
519
+ return unless ticket.save(path: "imports/tickets")
468
520
  ticket
469
521
  end
470
522
  end
@@ -474,6 +526,10 @@ module ZendeskAPI
474
526
 
475
527
  # Recovers this suspended ticket to an actual ticket
476
528
  put :recover
529
+
530
+ def self.cbp_path_regexes
531
+ [/^suspended_tickets$/]
532
+ end
477
533
  end
478
534
 
479
535
  class DeletedTicket < ReadResource
@@ -483,6 +539,10 @@ module ZendeskAPI
483
539
  # Restores this previously deleted ticket to an actual ticket
484
540
  put :restore
485
541
  put :restore_many
542
+
543
+ def self.cbp_path_regexes
544
+ [/^deleted_tickets$/]
545
+ end
486
546
  end
487
547
 
488
548
  class UserViewRow < DataResource
@@ -498,9 +558,9 @@ module ZendeskAPI
498
558
  # @internal Optional columns
499
559
 
500
560
  has Group
501
- has :assignee, :class => User
502
- has :requester, :class => User
503
- has :submitter, :class => User
561
+ has :assignee, class: User
562
+ has :requester, class: User
563
+ has :submitter, class: User
504
564
  has Organization
505
565
 
506
566
  def self.model_key
@@ -580,6 +640,10 @@ module ZendeskAPI
580
640
  def self.preview(client, options = {})
581
641
  Collection.new(client, ViewRow, options.merge(:path => "views/preview", :verb => :post))
582
642
  end
643
+
644
+ def self.cbp_path_regexes
645
+ [/^views$/]
646
+ end
583
647
  end
584
648
 
585
649
  class Trigger < Rule
@@ -587,6 +651,10 @@ module ZendeskAPI
587
651
  include Actions
588
652
 
589
653
  has :execution, :class => RuleExecution
654
+
655
+ def self.cbp_path_regexes
656
+ [/^triggers$/, %r{^triggers/active$}]
657
+ end
590
658
  end
591
659
 
592
660
  class Automation < Rule
@@ -594,6 +662,10 @@ module ZendeskAPI
594
662
  include Actions
595
663
 
596
664
  has :execution, :class => RuleExecution
665
+
666
+ def self.cbp_path_regexes
667
+ [/^automations$/]
668
+ end
597
669
  end
598
670
 
599
671
  class Macro < Rule
@@ -601,6 +673,10 @@ module ZendeskAPI
601
673
 
602
674
  has :execution, :class => RuleExecution
603
675
 
676
+ def self.cbp_path_regexes
677
+ [/^macros$/]
678
+ end
679
+
604
680
  # Returns the update to a ticket that happens when a macro will be applied.
605
681
  # @param [Ticket] ticket Optional {Ticket} to apply this macro to.
606
682
  # @raise [Faraday::ClientError] Raised for any non-200 response.
@@ -636,6 +712,18 @@ module ZendeskAPI
636
712
 
637
713
  has User
638
714
  has Group
715
+
716
+ def self.cbp_path_regexes
717
+ [%r{^groups/\d+/memberships$}]
718
+ end
719
+ end
720
+
721
+ class Group < Resource
722
+ has_many :memberships, class: GroupMembership, path: "memberships"
723
+
724
+ def self.cbp_path_regexes
725
+ [/^groups$/, %r{^groups/assignable$}]
726
+ end
639
727
  end
640
728
 
641
729
  class User < Resource
@@ -660,6 +748,10 @@ module ZendeskAPI
660
748
  put :request_verification
661
749
  end
662
750
 
751
+ def self.cbp_path_regexes
752
+ [/^users$/, %r{^organizations/\d+/users$}]
753
+ end
754
+
663
755
  any :password
664
756
 
665
757
  # Set a user's password
@@ -777,6 +869,10 @@ module ZendeskAPI
777
869
  def self.singular_resource_name
778
870
  "client"
779
871
  end
872
+
873
+ def self.cbp_path_regexes
874
+ [%r{^oauth/clients$}]
875
+ end
780
876
  end
781
877
 
782
878
  class OauthToken < ReadResource
@@ -25,6 +25,10 @@ module ZendeskAPI
25
25
  (klass || Result).new(client, attributes)
26
26
  end
27
27
 
28
+ def self.cbp_path_regexes
29
+ []
30
+ end
31
+
28
32
  class Result < Data; end
29
33
 
30
34
  class << self
@@ -44,14 +44,12 @@ module ZendeskAPI
44
44
  end
45
45
 
46
46
  define_method method do |*method_args|
47
- begin
48
- send("#{method}!", *method_args)
49
- rescue ZendeskAPI::Error::RecordInvalid => e
50
- @errors = e.errors
51
- false
52
- rescue ZendeskAPI::Error::ClientError
53
- false
54
- end
47
+ send("#{method}!", *method_args)
48
+ rescue ZendeskAPI::Error::RecordInvalid => e
49
+ @errors = e.errors
50
+ false
51
+ rescue ZendeskAPI::Error::ClientError
52
+ false
55
53
  end
56
54
  end
57
55
  end
@@ -1,3 +1,3 @@
1
1
  module ZendeskAPI
2
- VERSION = "1.37.0"
2
+ VERSION = "3.0.5"
3
3
  end
data/lib/zendesk_api.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  module ZendeskAPI; end
2
2
 
3
+ require 'faraday'
4
+ require 'faraday/multipart'
5
+
6
+ require 'zendesk_api/helpers'
3
7
  require 'zendesk_api/core_ext/inflection'
4
8
  require 'zendesk_api/client'
metadata CHANGED
@@ -1,36 +1,44 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zendesk_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.37.0
4
+ version: 3.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Davidovitz
8
8
  - Michael Grosser
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-09-07 00:00:00.000000000 Z
12
+ date: 2023-09-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: 0.9.0
21
- - - "<"
18
+ - - ">"
22
19
  - !ruby/object:Gem::Version
23
20
  version: 2.0.0
24
21
  type: :runtime
25
22
  prerelease: false
26
23
  version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">"
26
+ - !ruby/object:Gem::Version
27
+ version: 2.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: faraday-multipart
30
+ requirement: !ruby/object:Gem::Requirement
27
31
  requirements:
28
32
  - - ">="
29
33
  - !ruby/object:Gem::Version
30
- version: 0.9.0
31
- - - "<"
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
32
40
  - !ruby/object:Gem::Version
33
- version: 2.0.0
41
+ version: '0'
34
42
  - !ruby/object:Gem::Dependency
35
43
  name: hashie
36
44
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +136,7 @@ files:
128
136
  - lib/zendesk_api/middleware/response/parse_json.rb
129
137
  - lib/zendesk_api/middleware/response/raise_error.rb
130
138
  - lib/zendesk_api/middleware/response/sanitize_response.rb
139
+ - lib/zendesk_api/pagination.rb
131
140
  - lib/zendesk_api/resource.rb
132
141
  - lib/zendesk_api/resources.rb
133
142
  - lib/zendesk_api/search.rb
@@ -144,11 +153,11 @@ licenses:
144
153
  - Apache-2.0
145
154
  metadata:
146
155
  bug_tracker_uri: https://github.com/zendesk/zendesk_api_client_rb/issues
147
- changelog_uri: https://github.com/zendesk/zendesk_api_client_rb/blob/v1.37.0/CHANGELOG.md
148
- documentation_uri: https://www.rubydoc.info/gems/zendesk_api/1.37.0
149
- source_code_uri: https://github.com/zendesk/zendesk_api_client_rb/tree/v1.37.0
156
+ changelog_uri: https://github.com/zendesk/zendesk_api_client_rb/blob/v3.0.5/CHANGELOG.md
157
+ documentation_uri: https://www.rubydoc.info/gems/zendesk_api/3.0.5
158
+ source_code_uri: https://github.com/zendesk/zendesk_api_client_rb/tree/v3.0.5
150
159
  wiki_uri: https://github.com/zendesk/zendesk_api_client_rb/wiki
151
- post_install_message:
160
+ post_install_message:
152
161
  rdoc_options: []
153
162
  require_paths:
154
163
  - lib
@@ -156,15 +165,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
156
165
  requirements:
157
166
  - - ">="
158
167
  - !ruby/object:Gem::Version
159
- version: '2.3'
168
+ version: '2.7'
160
169
  required_rubygems_version: !ruby/object:Gem::Requirement
161
170
  requirements:
162
171
  - - ">="
163
172
  - !ruby/object:Gem::Version
164
173
  version: 1.3.6
165
174
  requirements: []
166
- rubygems_version: 3.0.3
167
- signing_key:
175
+ rubygems_version: 3.0.3.1
176
+ signing_key:
168
177
  specification_version: 4
169
178
  summary: Zendesk REST API Client
170
179
  test_files: []