active_call-zoho_sign 0.1.4 → 0.1.6

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: 9f5b979aa0e18b49ea40fa109aba4afd213e5c1935cde79c60b14b5ae700420a
4
- data.tar.gz: 5c06f8ad0695d64905affc7c84432e39977d1531ac3e1aa94fcd9761c7fd2537
3
+ metadata.gz: d081ad9bfcfa500488f91ef33523321354c2e92125798dabf903b73455a36969
4
+ data.tar.gz: c1e116320af36f5a82b2c5fc438accc3417246c073957544e49ce31aa40baa1e
5
5
  SHA512:
6
- metadata.gz: f928364c2384f5b4437c1712d9d09185d1b187e7c1f52d2a04f29c4478b37e09172a5c3231b4bb79d071818a90a3bf909a7fbcde785619490c04b7ad6498611f
7
- data.tar.gz: 0d57d5710f292b8659b90c82a95cb6ac40c34feae262726e945aef322522fb59dcf45a8fb9a050d44a612aea88359e62eb028e7184f8f9fd4287a9de8b581958
6
+ metadata.gz: 61d2c71ceb5d3cd761adf9bcba5c6b82c32df65de03059be03c53cf0b77756e591347cb93399ff01d0ef0cbef049aafd7dd5dbbf8cab204c6cad6ba823c404dc
7
+ data.tar.gz: 303712d85e4e32f67f060d0bfcffde7673d10f2c01f8b8e4f9890655097417b0bb53ef02ec75b79702049e0c9daf249ed2ecf7fdb9379418a0ae3756952dccfb
data/.rubocop.yml CHANGED
@@ -20,7 +20,8 @@ Layout/HashAlignment:
20
20
  EnforcedColonStyle: table
21
21
 
22
22
  Layout/LineLength:
23
- AllowedPatterns: ['initialize']
23
+ AllowedPatterns:
24
+ - initialize
24
25
 
25
26
  Lint/MissingSuper:
26
27
  Enabled: false
@@ -37,15 +38,14 @@ Metrics/ClassLength:
37
38
 
38
39
  Metrics/CyclomaticComplexity:
39
40
  Exclude:
40
- - lib/zoho_sign/document/list_service.rb
41
- - lib/zoho_sign/template/list_service.rb
41
+ - lib/zoho_sign/concerns/enumerable.rb
42
42
 
43
43
  Metrics/MethodLength:
44
44
  Enabled: false
45
45
 
46
46
  Metrics/PerceivedComplexity:
47
47
  Exclude:
48
- - lib/zoho_sign/document/list_service.rb
48
+ - lib/zoho_sign/concerns/enumerable.rb
49
49
 
50
50
  Naming/FileName:
51
51
  Exclude:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [0.1.5] - 2025-04-05
2
+
3
+ - Added `ZohoSign::GrantToken::GetService`.
4
+ - Set access token in `before_call` hook instead of lambda so we can capture errors from the access token service objects.
5
+ - Fixed empty list enumerable errors.
6
+ - Remove spec dependencies already included in `active_call-api`.
7
+
8
+ ## [0.1.5] - 2025-04-03
9
+
10
+ - Refactor list endpoints to use `ZohoSign::Enumerable`.
11
+
1
12
  ## [0.1.4] - 2025-03-31
2
13
 
3
14
  - Sign a document embedded link fix.
data/README.md CHANGED
@@ -4,6 +4,18 @@
4
4
 
5
5
  Zoho Sign exposes the [Zoho Sign API](https://www.zoho.com/sign/api) endpoints through service objects.
6
6
 
7
+ - [Installation](#installation)
8
+ - [Configuration](#configuration)
9
+ - [Usage](#usage)
10
+ - [Using call](#using-call)
11
+ - [Using call!](#using-call!)
12
+ - [When to use call or call!](#using-call-or-call!)
13
+ - [Using lists](#using-lists)
14
+ - [Service Objects](#service-objects)
15
+ - [Development](#development)
16
+ - [Contributing](#contributing)
17
+ - [License](#license)
18
+
7
19
  ## Installation
8
20
 
9
21
  Install the gem and add to the application's Gemfile by executing:
@@ -20,6 +32,12 @@ gem install active_call-zoho_sign
20
32
 
21
33
  ## Configuration
22
34
 
35
+ Create a new **Self Client** client type from the [Zoho Developer Console](https://api-console.zoho.com) to retrieve your **Client ID** and **Client Secret**.
36
+
37
+ Choose what you need from the list of [Zoho Scopes](https://www.zoho.com/sign/api/oauth.html) like `ZohoSign.documents.ALL` to generate your **Grant Token**.
38
+
39
+ Get your **Refresh Token** by calling `ZohoSign::GrantToken::GetService.call(grant_token: '', client_id: '', client_secret: '').refresh_token`
40
+
23
41
  Configure your API credentials.
24
42
 
25
43
  In a Rails application, the standard practice is to place this code in a file named `zoho_sign.rb` within the `config/initializers` directory.
@@ -45,7 +63,7 @@ While testing, you can set your temporary development OAuth access token in the
45
63
 
46
64
  ## Usage
47
65
 
48
- ### Using `.call`
66
+ ### <a name='using-call'></a>Using `call`
49
67
 
50
68
  Each service object returned will undergo validation before the `call` method is invoked to access API endpoints.
51
69
 
@@ -99,7 +117,7 @@ service.response.status # => 400
99
117
  service.response.body # => {"code"=>9004, "message"=>"No match found", "status"=>"failure"}
100
118
  ```
101
119
 
102
- ### Using `.call!`
120
+ ### <a name='using-call!'></a>Using `call!`
103
121
 
104
122
  Each service object returned will undergo validation before the `call!` method is invoked to access API endpoints.
105
123
 
@@ -154,14 +172,14 @@ rescue ZohoSign::RequestError => exception
154
172
  exception.response.body # => {"code"=>9004, "message"=>"No match found", "status"=>"failure"}
155
173
  ```
156
174
 
157
- ### When to use `.call` or `.call!`
175
+ ### <a name='using-call-or-call!'></a>When to use `call` or `call!`
158
176
 
159
- An example of where to use `.call` would be in a **controller** doing an inline synchronous request.
177
+ An example of where to use `call` would be in a **controller** doing an inline synchronous request.
160
178
 
161
179
  ```ruby
162
- class DocumentController < ApplicationController
180
+ class SomeController < ApplicationController
163
181
  def update
164
- @document = ZohoSign::Document::UpdateService.call(params)
182
+ @document = ZohoSign::Document::UpdateService.call(**params)
165
183
 
166
184
  if @document.success?
167
185
  redirect_to [@document], notice: 'Success', status: :see_other
@@ -173,31 +191,37 @@ class DocumentController < ApplicationController
173
191
  end
174
192
  ```
175
193
 
176
- An example of where to use `.call!` would be in a **job** doing an asynchronous request.
194
+ An example of where to use `call!` would be in a **job** doing an asynchronous request.
177
195
 
178
196
  You can use the exceptions to determine which retry strategy to use and which to discard.
179
197
 
180
198
  ```ruby
181
- class DocumentJob < ApplicationJob
199
+ class SomeJob < ApplicationJob
182
200
  discard_on ZohoSign::NotFoundError
183
201
 
184
202
  retry_on ZohoSign::RequestTimeoutError, wait: 5.minutes, attempts: :unlimited
185
203
  retry_on ZohoSign::TooManyRequestsError, wait: :polynomially_longer, attempts: 10
186
204
 
187
205
  def perform
188
- ZohoSign::Document::UpdateService.call!(params)
206
+ ZohoSign::Document::UpdateService.call!(**params)
189
207
  end
190
208
  end
191
209
  ```
192
210
 
193
- ### Documents
211
+ ### Using lists
194
212
 
195
- #### List documents.
213
+ If you don't provide the `limit` argument, multiple API requests will be made untill all records have been returned. You could be rate limited, so use wisely.
196
214
 
197
- Note that the `offset` starts at `1` for the first item.
215
+ Note that the `offset` argument starts at `1` for the first item.
216
+
217
+ ## Service Objects
218
+
219
+ <details open>
220
+ <summary>Documents</summary>
221
+
222
+ ### Documents
198
223
 
199
- If you don't provide a `limit`, multiple API requests will be made untill all records have been returned. You could be
200
- rate limited, so use wisely.
224
+ #### List documents
201
225
 
202
226
  ```ruby
203
227
  service = ZohoSign::Document::ListService.call(offset: 1, limit: 10).each do |facade|
@@ -217,10 +241,9 @@ Filter by column.
217
241
  ZohoSign::Document::ListService.call(search_columns: { recipient_email: 'eric.cartman@example.com' }).map { _1 }
218
242
  ```
219
243
 
220
- Columns to sort and filter by are `request_name`, `folder_name`, `owner_full_name`, `recipient_email`,
221
- `form_name` `created_time`.
244
+ Columns to sort and filter by are `request_name`, `folder_name`, `owner_full_name`, `recipient_email`, `form_name` and `created_time`.
222
245
 
223
- #### Get a document.
246
+ #### Get a document
224
247
 
225
248
  ```ruby
226
249
  service = ZohoSign::Document::GetService.call(id: '')
@@ -235,7 +258,7 @@ service.sign_percentage
235
258
  ...
236
259
  ```
237
260
 
238
- #### Create a document.
261
+ #### Create a document
239
262
 
240
263
  ```ruby
241
264
  service = ZohoSign::Document::CreateService.call(
@@ -258,7 +281,7 @@ service = ZohoSign::Document::CreateService.call(
258
281
  )
259
282
  ```
260
283
 
261
- #### Update a document.
284
+ #### Update a document
262
285
 
263
286
  ```ruby
264
287
  service = ZohoSign::Document::UpdateService.call(
@@ -277,13 +300,13 @@ service = ZohoSign::Document::UpdateService.call(
277
300
  )
278
301
  ```
279
302
 
280
- #### Delete a document.
303
+ #### Delete a document
281
304
 
282
305
  ```ruby
283
306
  service = ZohoSign::Document::DeleteService.call(id: '')
284
307
  ```
285
308
 
286
- #### Sign a document.
309
+ #### Sign a document
287
310
 
288
311
  A unique signing URL will be generated, which will be valid for two minutes. If the signing page is not open by then, a new link needs to be generated and it is a one-time usable URL.
289
312
 
@@ -292,29 +315,44 @@ service = ZohoSign::Document::Action::EmbedToken::GetService.call(request_id: ''
292
315
  service.sign_url
293
316
  ```
294
317
 
318
+ </details>
319
+
320
+ <details>
321
+ <summary>Folders</summary>
322
+
295
323
  ### Folders
296
324
 
297
325
  TODO: ...
298
326
 
327
+ </details>
328
+
329
+ <details>
330
+ <summary>Field Types</summary>
331
+
299
332
  ### Field Types
300
333
 
301
334
  TODO: ...
302
335
 
336
+ </details>
337
+
338
+ <details>
339
+ <summary>Request Types</summary>
340
+
303
341
  ### Request Types
304
342
 
305
343
  TODO: ...
306
344
 
307
- ### Templates
345
+ </details>
308
346
 
309
- #### List templates.
347
+ <details>
348
+ <summary>Templates</summary>
310
349
 
311
- Note that the `offset` starts at `1` for the first item.
350
+ ### Templates
312
351
 
313
- If you don't provide a `limit`, multiple API requests will be made untill all records have been returned. You could be
314
- rate limited, so use wisely.
352
+ #### List templates
315
353
 
316
354
  ```ruby
317
- service = ZohoSign::Template::ListService.call(offset: 1, limit: 10).each do |facade|
355
+ ZohoSign::Template::ListService.call(offset: 1, limit: 10).each do |facade|
318
356
  facade.description
319
357
  end
320
358
  ```
@@ -331,9 +369,9 @@ Filter by column.
331
369
  ZohoSign::Template::ListService.call(search_columns: { template_name: 'Eric Template' }).map { _1 }
332
370
  ```
333
371
 
334
- Columns to sort and filter by are `template_name`, `owner_first_name`, `modified_time`.
372
+ Columns to sort and filter by are `template_name`, `owner_first_name` and `modified_time`.
335
373
 
336
- #### Get a template.
374
+ #### Get a template
337
375
 
338
376
  ```ruby
339
377
  service = ZohoSign::Template::GetService.call(id: '')
@@ -348,19 +386,19 @@ service.template_name
348
386
  ...
349
387
  ```
350
388
 
351
- #### Create a template.
389
+ #### Create a template
352
390
 
353
391
  TODO: ...
354
392
 
355
- #### Update a template.
393
+ #### Update a template
356
394
 
357
395
  TODO: ...
358
396
 
359
- #### Delete a template.
397
+ #### Delete a template
360
398
 
361
399
  TODO: ...
362
400
 
363
- #### Create document from template.
401
+ #### Create document from template
364
402
 
365
403
  The auto filled fields specified in the `field_data` object should be marked as **Prefill by you** when creating the document template.
366
404
 
@@ -397,6 +435,8 @@ service = ZohoSign::Template::Document::CreateService.call!(
397
435
  )
398
436
  ```
399
437
 
438
+ </details>
439
+
400
440
  ## Development
401
441
 
402
442
  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.
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ZohoSign::AccessToken::GetService < ZohoSign::BaseService
4
+ skip_callback :call, :before, :set_access_token
5
+
4
6
  after_call :set_facade
5
7
 
6
8
  delegate_missing_to :@facade
@@ -38,7 +40,6 @@ class ZohoSign::AccessToken::GetService < ZohoSign::BaseService
38
40
  client_id: client_id,
39
41
  client_secret: client_secret,
40
42
  refresh_token: refresh_token,
41
- redirect_uri: 'https://sign.zoho.com',
42
43
  grant_type: 'refresh_token'
43
44
  }
44
45
  end
@@ -15,7 +15,15 @@ class ZohoSign::BaseService < ActiveCall::Base
15
15
  config_accessor :log_bodies, default: false, instance_writer: false
16
16
  config_accessor :client_id, :client_secret, :refresh_token, instance_writer: false
17
17
 
18
- attr_reader :facade
18
+ attr_reader :access_token, :facade
19
+
20
+ before_call :set_access_token
21
+
22
+ validate on: :request do
23
+ next if is_a?(ZohoSign::AccessToken::GetService)
24
+
25
+ errors.merge!(access_token_service.errors) if access_token.nil? && !access_token_service.success?
26
+ end
19
27
 
20
28
  class << self
21
29
  def exception_mapping
@@ -32,6 +40,7 @@ class ZohoSign::BaseService < ActiveCall::Base
32
40
  proxy_authentication_required: ZohoSign::ProxyAuthenticationRequiredError,
33
41
  request_timeout: ZohoSign::RequestTimeoutError,
34
42
  conflict: ZohoSign::ConflictError,
43
+ gone: ZohoSign::GoneError,
35
44
  unprocessable_entity: ZohoSign::UnprocessableEntityError,
36
45
  too_many_requests: ZohoSign::TooManyRequestsError,
37
46
  internal_server_error: ZohoSign::InternalServerError,
@@ -48,7 +57,7 @@ class ZohoSign::BaseService < ActiveCall::Base
48
57
  def connection
49
58
  @_connection ||= Faraday.new do |conn|
50
59
  conn.url_prefix = base_url
51
- conn.request :authorization, 'Zoho-oauthtoken', -> { access_token }
60
+ conn.request :authorization, 'Zoho-oauthtoken', access_token
52
61
  conn.request :multipart
53
62
  conn.request :url_encoded
54
63
  conn.request :retry
@@ -69,12 +78,18 @@ class ZohoSign::BaseService < ActiveCall::Base
69
78
  }
70
79
  end
71
80
 
72
- def access_token
73
- access_token = ENV['ZOHO_SIGN_ACCESS_TOKEN'].presence || cache.read(CACHE_KEY[:access_token])
74
- return access_token if access_token.present?
81
+ def set_access_token
82
+ @access_token = ENV['ZOHO_SIGN_ACCESS_TOKEN'].presence || cache.read(CACHE_KEY[:access_token])
83
+ return if @access_token.present?
84
+ return unless access_token_service.success?
85
+
86
+ @access_token = cache.fetch(CACHE_KEY[:access_token], expires_in: [access_token_service.expires_in - 10, 0].max) do
87
+ access_token_service.facade.access_token
88
+ end
89
+ end
75
90
 
76
- service = ZohoSign::AccessToken::GetService.call
77
- cache.fetch(CACHE_KEY[:access_token], expires_in: [service.expires_in - 10, 0].max) { service.facade.access_token }
91
+ def access_token_service
92
+ @_access_token_service ||= ZohoSign::AccessToken::GetService.call
78
93
  end
79
94
 
80
95
  def forbidden?
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZohoSign::Enumerable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include Enumerable
8
+
9
+ attr_reader :path, :list_key, :facade_klass, :offset, :limit
10
+
11
+ validates :path, :list_key, :facade_klass, presence: true
12
+ validates :limit, presence: true, numericality: { greater_than_or_equal_to: 1 }
13
+ end
14
+
15
+ def initialize(path:, list_key:, facade_klass:, offset: 1, limit: Float::INFINITY)
16
+ @path = path
17
+ @list_key = list_key
18
+ @facade_klass = facade_klass
19
+ @limit = limit
20
+ @offset = offset
21
+ end
22
+
23
+ def call
24
+ self
25
+ end
26
+
27
+ def each
28
+ return to_enum(:each) unless block_given?
29
+ return if invalid?
30
+
31
+ total = 0
32
+
33
+ catch :list_end do
34
+ loop do
35
+ @response = connection.get(path, data: params.to_json)
36
+ validate(:response)
37
+
38
+ unless success?
39
+ raise exception_for(response, errors) if bang?
40
+
41
+ throw :list_end
42
+ end
43
+
44
+ throw :list_end unless response.body
45
+
46
+ response.body[list_key].each do |hash|
47
+ yield facade_klass.new(hash)
48
+ total += 1
49
+ throw :list_end if total >= limit
50
+ end
51
+
52
+ break unless response.body.dig('page_context', 'has_more_rows')
53
+
54
+ @_params[:page_context][:start_index] += max_limit_per_request
55
+ end
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def params
62
+ @_params ||= {
63
+ page_context: {
64
+ row_count: max_limit_per_request,
65
+ start_index: offset
66
+ }
67
+ }
68
+ end
69
+
70
+ def max_limit_per_request
71
+ @_max_limit_per_request ||= limit.infinite? ? 100 : [limit, 100].min
72
+ end
73
+ end
@@ -9,7 +9,7 @@ class ZohoSign::Document::GetService < ZohoSign::BaseService
9
9
 
10
10
  validates :id, presence: true
11
11
 
12
- def initialize(id: nil)
12
+ def initialize(id:)
13
13
  @id = id
14
14
  end
15
15
 
@@ -4,11 +4,10 @@ class ZohoSign::Document::ListService < ZohoSign::BaseService
4
4
  SORT_COLUMNS = %w[request_name folder_name owner_full_name recipient_email form_name created_time].freeze
5
5
  SORT_ORDERS = %w[ASC DESC].freeze
6
6
 
7
- include Enumerable
7
+ include ZohoSign::Enumerable
8
8
 
9
- attr_reader :limit, :offset, :sort_column, :sort_order, :search_columns
9
+ attr_reader :sort_column, :sort_order, :search_columns
10
10
 
11
- validates :limit, presence: true, numericality: { greater_than_or_equal_to: 1 }
12
11
  validates :sort_order, inclusion: { in: SORT_ORDERS, message: "Sort order must be one of #{SORT_ORDERS.join(', ')}" }
13
12
 
14
13
  validates :sort_column, inclusion: {
@@ -24,14 +23,6 @@ class ZohoSign::Document::ListService < ZohoSign::BaseService
24
23
  throw :abort
25
24
  end
26
25
 
27
- def initialize(limit: Float::INFINITY, offset: 1, sort_column: 'created_time', sort_order: 'DESC', search_columns: {})
28
- @limit = limit
29
- @offset = offset
30
- @sort_column = sort_column
31
- @sort_order = sort_order
32
- @search_columns = search_columns
33
- end
34
-
35
26
  # List documents.
36
27
  #
37
28
  # ==== Examples
@@ -39,43 +30,35 @@ class ZohoSign::Document::ListService < ZohoSign::BaseService
39
30
  # service = ZohoSign::Document::ListService.call.first
40
31
  # service.request_name
41
32
  #
33
+ # If you don't provide the `limit` argument, multiple API requests will be made untill all records have been returned.
34
+ # You could be rate limited, so use wisely.
35
+ #
42
36
  # ZohoSign::Document::ListService.call(offset: 11, limit: 10).each { _1 }
43
- # ZohoSign::Document::ListService.call(sort_column: 'recipient_email', sort_order: 'ASC').each { _1 }
44
- # ZohoSign::Document::ListService.call(search_columns: { recipient_email: 'eric.cartman@example.com' }).each { _1 }
37
+ #
38
+ # Sort by column.
39
+ #
40
+ # ZohoSign::Document::ListService.call(sort_column: 'recipient_email', sort_order: 'ASC').map { _1 }
41
+ #
42
+ # Filter by column.
43
+ #
44
+ # ZohoSign::Document::ListService.call(search_columns: { recipient_email: 'eric.cartman@example.com' }).map { _1 }
45
+ #
46
+ # Columns to sort and filter by are `request_name`, `folder_name`, `owner_full_name`, `recipient_email`, `form_name`
47
+ # and `created_time`.
45
48
  #
46
49
  # GET /api/v1/requests
47
- def call
48
- self
49
- end
50
-
51
- def each
52
- return to_enum(:each) unless block_given?
53
- return if invalid?
54
-
55
- total = 0
56
-
57
- catch :list_end do
58
- loop do
59
- @response = connection.get('requests', data: params.to_json)
60
- validate(:response)
61
-
62
- unless success?
63
- raise exception_for(response, errors) if bang?
64
-
65
- throw :list_end
66
- end
67
-
68
- response.body['requests'].each do |hash|
69
- yield ZohoSign::Document::Facade.new(hash)
70
- total += 1
71
- throw :list_end if total >= limit
72
- end
73
-
74
- break unless response.body.dig('page_context', 'has_more_rows')
50
+ def initialize(offset: 1, limit: Float::INFINITY, sort_column: 'created_time', sort_order: 'DESC', search_columns: {})
51
+ @sort_column = sort_column
52
+ @sort_order = sort_order
53
+ @search_columns = search_columns
75
54
 
76
- @_params[:page_context][:start_index] += max_limit_per_request
77
- end
78
- end
55
+ super(
56
+ path: 'requests',
57
+ list_key: 'requests',
58
+ facade_klass: ZohoSign::Document::Facade,
59
+ limit: limit,
60
+ offset: offset
61
+ )
79
62
  end
80
63
 
81
64
  private
@@ -91,8 +74,4 @@ class ZohoSign::Document::ListService < ZohoSign::BaseService
91
74
  }
92
75
  }
93
76
  end
94
-
95
- def max_limit_per_request
96
- @_max_limit_per_request ||= limit.infinite? ? 100 : [limit, 100].min
97
- end
98
77
  end
@@ -38,6 +38,9 @@ module ZohoSign
38
38
  # 409
39
39
  class ConflictError < ClientError; end
40
40
 
41
+ # 410
42
+ class GoneError < ClientError; end
43
+
41
44
  # 422
42
45
  class UnprocessableEntityError < ClientError; end
43
46
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ZohoSign::GrantToken::Facade
4
+ attr_reader :access_token, :refresh_token, :scope, :api_domain, :expires_in, :token_type
5
+
6
+ def initialize(hash)
7
+ @access_token = hash['access_token']
8
+ @api_domain = hash['api_domain']
9
+ @expires_in = hash['expires_in']
10
+ @refresh_token = hash['refresh_token']
11
+ @scope = hash['scope']
12
+ @token_type = hash['token_type']
13
+ end
14
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ZohoSign::GrantToken::GetService < ZohoSign::BaseService
4
+ attr_reader :grant_token, :client_id, :client_secret
5
+
6
+ after_call :set_facade
7
+
8
+ delegate_missing_to :@facade
9
+ delegate :refresh_token, to: :@facade, allow_nil: true
10
+
11
+ validates :grant_token, presence: true
12
+
13
+ def initialize(grant_token:, client_id: nil, client_secret: nil)
14
+ @grant_token = grant_token
15
+ @client_id = client_id.presence || ZohoSign::BaseService.client_id
16
+ @client_secret = client_secret.presence || ZohoSign::BaseService.client_secret
17
+ end
18
+
19
+ # Get refresh token from grant token.
20
+ #
21
+ # ==== Examples
22
+ #
23
+ # service = ZohoSign::GrantToken::GetService.call(grant_token: '', client_id: '', client_secret: '')
24
+ # service.refresh_token # => '1000.xxxx.yyyy'
25
+ # service.expires_in # => 3600
26
+ #
27
+ # POST /oauth/v2/token
28
+ def call
29
+ connection.post('oauth/v2/token', params.to_param)
30
+ end
31
+
32
+ private
33
+
34
+ def connection
35
+ @_connection ||= Faraday.new do |conn|
36
+ conn.url_prefix = 'https://accounts.zoho.com'
37
+ conn.request :retry
38
+ conn.response :json
39
+ conn.response :logger, logger, **logger_options do |logger|
40
+ logger.filter(/(code|client_id|client_secret)=([^&]+)/i, '\1=[FILTERED]')
41
+ logger.filter(/"access_token":"([^"]+)"/i, '"access_token":"[FILTERED]"')
42
+ logger.filter(/"refresh_token":"([^"]+)"/i, '"refresh_token":"[FILTERED]"')
43
+ end
44
+ conn.adapter Faraday.default_adapter
45
+ end
46
+ end
47
+
48
+ def params
49
+ {
50
+ client_id: client_id,
51
+ client_secret: client_secret,
52
+ code: grant_token,
53
+ grant_type: 'authorization_code'
54
+ }
55
+ end
56
+
57
+ def unauthorized?
58
+ response.status == 200 && response.body.key?('error')
59
+ end
60
+
61
+ def set_facade
62
+ @facade = ZohoCrm::GrantToken::Facade.new(response.body)
63
+ end
64
+ end
@@ -9,7 +9,7 @@ class ZohoSign::Template::GetService < ZohoSign::BaseService
9
9
 
10
10
  validates :id, presence: true
11
11
 
12
- def initialize(id: nil)
12
+ def initialize(id:)
13
13
  @id = id
14
14
  end
15
15
 
@@ -4,11 +4,10 @@ class ZohoSign::Template::ListService < ZohoSign::BaseService
4
4
  SORT_COLUMNS = %w[template_name owner_first_name modified_time].freeze
5
5
  SORT_ORDERS = %w[ASC DESC].freeze
6
6
 
7
- include Enumerable
7
+ include ZohoSign::Enumerable
8
8
 
9
- attr_reader :limit, :offset, :sort_column, :sort_order, :search_columns
9
+ attr_reader :sort_column, :sort_order, :search_columns
10
10
 
11
- validates :limit, presence: true, numericality: { greater_than_or_equal_to: 1 }
12
11
  validates :sort_order, inclusion: { in: SORT_ORDERS, message: "Sort order must be one of #{SORT_ORDERS.join(', ')}" }
13
12
 
14
13
  validates :sort_column, inclusion: {
@@ -24,14 +23,6 @@ class ZohoSign::Template::ListService < ZohoSign::BaseService
24
23
  throw :abort
25
24
  end
26
25
 
27
- def initialize(limit: Float::INFINITY, offset: 1, sort_column: 'template_name', sort_order: 'DESC', search_columns: {})
28
- @limit = limit
29
- @offset = offset
30
- @sort_column = sort_column
31
- @sort_order = sort_order
32
- @search_columns = search_columns
33
- end
34
-
35
26
  # List documents.
36
27
  #
37
28
  # ==== Examples
@@ -39,43 +30,34 @@ class ZohoSign::Template::ListService < ZohoSign::BaseService
39
30
  # service = ZohoSign::Template::ListService.call.first
40
31
  # service.request_name
41
32
  #
33
+ # If you don't provide the `limit` argument, multiple API requests will be made untill all records have been returned.
34
+ # You could be rate limited, so use wisely.
35
+ #
42
36
  # ZohoSign::Template::ListService.call(offset: 11, limit: 10).each { _1 }
43
- # ZohoSign::Template::ListService.call(sort_column: 'template_name', sort_order: 'ASC').each { _1 }
44
- # ZohoSign::Template::ListService.call(search_columns: { template_name: 'Eric Template' }).each { _1 }
37
+ #
38
+ # Sort by column.
39
+ #
40
+ # ZohoSign::Template::ListService.call(sort_column: 'template_name', sort_order: 'ASC').map { _1 }
41
+ #
42
+ # Filter by column.
43
+ #
44
+ # ZohoSign::Template::ListService.call(search_columns: { template_name: 'Eric Template' }).map { _1 }
45
+ #
46
+ # Columns to sort and filter by are `template_name`, `owner_first_name` and `modified_time`.
45
47
  #
46
48
  # GET /api/v1/templates
47
- def call
48
- self
49
- end
50
-
51
- def each
52
- return to_enum(:each) unless block_given?
53
- return if invalid?
54
-
55
- total = 0
56
-
57
- catch :list_end do
58
- loop do
59
- @response = connection.get('templates', data: params.to_json)
60
- validate(:response)
61
-
62
- unless success?
63
- raise exception_for(response, errors) if bang?
64
-
65
- throw :list_end
66
- end
67
-
68
- response.body['templates'].each do |hash|
69
- yield ZohoSign::Template::Facade.new(hash)
70
- total += 1
71
- throw :list_end if total >= limit
72
- end
73
-
74
- break unless response.body.dig('page_context', 'has_more_rows')
49
+ def initialize(offset: 1, limit: Float::INFINITY, sort_column: 'template_name', sort_order: 'DESC', search_columns: {})
50
+ @sort_column = sort_column
51
+ @sort_order = sort_order
52
+ @search_columns = search_columns
75
53
 
76
- @_params[:page_context][:start_index] += max_limit_per_request
77
- end
78
- end
54
+ super(
55
+ path: 'templates',
56
+ list_key: 'templates',
57
+ facade_klass: ZohoSign::Template::Facade,
58
+ limit: limit,
59
+ offset: offset
60
+ )
79
61
  end
80
62
 
81
63
  private
@@ -91,8 +73,4 @@ class ZohoSign::Template::ListService < ZohoSign::BaseService
91
73
  }
92
74
  }
93
75
  end
94
-
95
- def max_limit_per_request
96
- @_max_limit_per_request ||= limit.infinite? ? 100 : [limit, 100].min
97
- end
98
76
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZohoSign
4
- VERSION = '0.1.4'
4
+ VERSION = '0.1.6'
5
5
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_call-zoho_sign
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kobus Joubert
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-03-31 00:00:00.000000000 Z
11
+ date: 2025-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: active_call
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0.2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '0.2'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: active_call-api
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -38,34 +24,6 @@ dependencies:
38
24
  - - "~>"
39
25
  - !ruby/object:Gem::Version
40
26
  version: '0.1'
41
- - !ruby/object:Gem::Dependency
42
- name: faraday
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2.0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2.0'
55
- - !ruby/object:Gem::Dependency
56
- name: faraday-retry
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.0'
69
27
  - !ruby/object:Gem::Dependency
70
28
  name: faraday-multipart
71
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +38,6 @@ dependencies:
80
38
  - - "~>"
81
39
  - !ruby/object:Gem::Version
82
40
  version: '1.1'
83
- - !ruby/object:Gem::Dependency
84
- name: faraday-logging-color_formatter
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '0.2'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '0.2'
97
41
  description: Zoho Sign exposes the Zoho Sign API endpoints through service objects.
98
42
  email:
99
43
  - kobus@translate3d.com
@@ -112,6 +56,7 @@ files:
112
56
  - lib/zoho_sign/access_token/facade.rb
113
57
  - lib/zoho_sign/access_token/get_service.rb
114
58
  - lib/zoho_sign/base_service.rb
59
+ - lib/zoho_sign/concerns/enumerable.rb
115
60
  - lib/zoho_sign/current_user/facade.rb
116
61
  - lib/zoho_sign/current_user/get_service.rb
117
62
  - lib/zoho_sign/document/action/embed_token/facade.rb
@@ -123,6 +68,8 @@ files:
123
68
  - lib/zoho_sign/document/list_service.rb
124
69
  - lib/zoho_sign/document/update_service.rb
125
70
  - lib/zoho_sign/error.rb
71
+ - lib/zoho_sign/grant_token/facade.rb
72
+ - lib/zoho_sign/grant_token/get_service.rb
126
73
  - lib/zoho_sign/template/document/create_service.rb
127
74
  - lib/zoho_sign/template/document/facade.rb
128
75
  - lib/zoho_sign/template/facade.rb