calendly 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a6dc0f127f4092b13891a3e4515f513973f23fc287ed6ee5b4b2cfd76f46f68
4
- data.tar.gz: bc724082ae45976974c064899a63080a2ab1b9fea521fa301706c7e732efd9e3
3
+ metadata.gz: 3656dc7886aad2a35932152a25f601d2160bed7f53b4ead91e67eb4cb82bb433
4
+ data.tar.gz: 337d5637a69e30e1dcc943ac1332f38b1675e3d55e0c09049d9308661b4edbe3
5
5
  SHA512:
6
- metadata.gz: 885928fabc15c7a08c6a670255b5da769a5e59637d2832e863dd7b54a2146217544a3fdfd2461714ce4e9819adbbcc95deb12eaece81fa45167893b97f0101d1
7
- data.tar.gz: 1a010d94d5feaa3c2103dc10608cb20364fadcaddc0cfa51f5b7e39ed062bbd218d6c40e1d86e84f384035230500f7141b30cc9cfd95006abe5160f05f6039d1
6
+ metadata.gz: 32d0c18ebb375a99fb1b23b4365f99ba5957ebbbfed497690ef7d6db8bb0e0ada413853a927892963af62cc21afe39ad6f8d5740831af2e4e881fcc8e9bb5017
7
+ data.tar.gz: 81a59436778d27892dd325496bc234bea9380fba303b872a2d04ba6ea4b18d73b94d3a13133f7b90f2a68f19a994263ef464a60332239df3f61e064a6d116841
@@ -23,12 +23,11 @@ Metrics/BlockNesting:
23
23
  Max: 2
24
24
 
25
25
  Layout/LineLength:
26
- AllowURI: true
27
- Enabled: false
26
+ Max: 120
28
27
 
29
28
  Metrics/MethodLength:
30
29
  CountComments: false
31
- Max: 15
30
+ Max: 20
32
31
 
33
32
  Metrics/ParameterLists:
34
33
  Max: 4
@@ -39,10 +38,10 @@ Metrics/AbcSize:
39
38
 
40
39
  Style/CollectionMethods:
41
40
  PreferredMethods:
42
- map: 'collect'
43
- reduce: 'inject'
44
- find: 'detect'
45
- find_all: 'select'
41
+ map: "collect"
42
+ reduce: "inject"
43
+ find: "detect"
44
+ find_all: "select"
46
45
 
47
46
  Style/Documentation:
48
47
  Enabled: false
@@ -60,10 +59,13 @@ Style/ExpandPathArguments:
60
59
  Enabled: false
61
60
 
62
61
  Style/HashSyntax:
63
- EnforcedStyle: hash_rockets
62
+ EnforcedStyle: ruby19
64
63
 
65
64
  Style/Lambda:
66
65
  Enabled: false
67
66
 
68
67
  Style/RaiseArgs:
69
- EnforcedStyle: compact
68
+ EnforcedStyle: compact
69
+
70
+ Style/AsciiComments:
71
+ Enabled: false
@@ -1,23 +1,49 @@
1
- # 0.1.0
1
+ # CHANGELOG
2
+
3
+ ## 0.3.0
4
+
5
+ - remove zeitwerk dependency. (refs #16)
6
+
7
+ ## 0.2.0
8
+
9
+ - save fetched data in cache. (refs #14)
10
+
11
+ ## 0.1.3
12
+
13
+ - support webhook APIs (refs #9)
14
+ - `GET /webhook_subscriptions`
15
+ - `GET /webhook_subscriptions/{webhook_uuid}`
16
+ - `POST /webhook_subscriptions`
17
+ - `DELETE /webhook_subscriptions/{webhook_uuid}`
18
+
19
+ ## 0.1.2
20
+
21
+ - fix rubocop warnings.
22
+
23
+ ## 0.1.1
24
+
25
+ - add tests to make coverage 100%.
26
+
27
+ ## 0.1.0
2
28
 
3
29
  - define methods to access associated resources with each model.
4
30
  - rename methods:
5
31
  - `Calendly::Client#events` to `Calendly::Client#scheduled_events`
6
32
 
7
- # 0.0.7.alpha
33
+ ## 0.0.7.alpha
8
34
 
9
35
  - support APIs
10
36
  - `POST /organizations/{uuid}/invitations`
11
37
  - `DELETE /organizations/{org_uuid}/invitations/{invitation_uuid}`
12
38
  - `DELETE /organization_memberships/{uuid}`
13
39
 
14
- # 0.0.6.alpha
40
+ ## 0.0.6.alpha
15
41
 
16
42
  - support APIs
17
43
  - `GET /organizations/{uuid}/invitations`
18
44
  - `GET /organizations/{organization_uuid}/invitations/{invitation_uuid}`
19
45
 
20
- # 0.0.5.alpha
46
+ ## 0.0.5.alpha
21
47
 
22
48
  - support APIs
23
49
  - `GET /organization_memberships`
@@ -26,24 +52,24 @@
26
52
  - Invitee#event to Invitee#event_uri
27
53
  - Event#event_type to Event#event_type_uri
28
54
 
29
- # 0.0.4.alpha
55
+ ## 0.0.4.alpha
30
56
 
31
57
  - support APIs
32
58
  - `GET /scheduled_events/{event_uuid}/invitees`
33
59
  - `GET /scheduled_events/{event_uuid}/invitees/{invitee_uuid}`
34
60
 
35
- # 0.0.3.alpha
61
+ ## 0.0.3.alpha
36
62
 
37
63
  - support APIs
38
64
  - `GET /scheduled_events`
39
65
  - `GET /scheduled_events/{uuid}`
40
66
 
41
- # 0.0.2.alpha
67
+ ## 0.0.2.alpha
42
68
 
43
69
  - support APIs
44
70
  - `GET /event_types`
45
71
 
46
- # 0.0.1.alpha
72
+ ## 0.0.1.alpha
47
73
 
48
74
  - Initial release
49
75
  - support APIs
data/README.md CHANGED
@@ -5,37 +5,7 @@
5
5
  [![Gem Version](https://badge.fury.io/rb/calendly.svg)](http://badge.fury.io/rb/calendly)
6
6
  [![license](https://img.shields.io/github/license/koshilife/calendly-api-ruby-client)](https://github.com/koshilife/calendly-api-ruby-client/blob/master/LICENSE.txt)
7
7
 
8
- ## About
9
-
10
- These client libraries are created for [Calendly v2 APIs](https://calendly.stoplight.io/docs/gh/calendly/api-docs).
11
-
12
- As of August 2020, Calendly v2 API is currently undergoing an upgrade.
13
- This library is trying to follow and support for the upgrade.
14
-
15
- As of now the supported statuses each Calendly API are as below.
16
-
17
- ## Supported statuses each Calendly API
18
-
19
- - User
20
- - [x] Get basic information about a user
21
- - EventType
22
- - [ ] Get Event Type (This endpoint hasn't been released yet.)
23
- - [x] User Event Types
24
- - Organization
25
- - [x] Get Organization Invitation
26
- - [x] Get Organization Invitations
27
- - [x] Get Organization Membership
28
- - [x] Get a list of Organization Memberships
29
- - [x] Invite a person to Organization
30
- - [x] Remove a User from an Organization
31
- - [x] Revoke Organization Invitation
32
- - ScheduledEvent
33
- - [x] Get Event
34
- - [x] Get Invitee of an Event
35
- - [x] Get List of Event Invitees
36
- - [x] Get List of User Events
37
- - Webhook V2
38
- - These endpoints havn't been released yet.
8
+ These client libraries are created for [Calendly v2 APIs](https://calendly.stoplight.io/).
39
9
 
40
10
  ## Installation
41
11
 
@@ -55,6 +25,8 @@ Or install it yourself as:
55
25
 
56
26
  ## Usage
57
27
 
28
+ ### Basic
29
+
58
30
  The APIs client needs access token.
59
31
  This client setup step is below.
60
32
 
@@ -116,7 +88,50 @@ invitation.status
116
88
 
117
89
  # cancel the invitation
118
90
  invitation.delete
91
+ ```
92
+
93
+ ### Webhook
94
+
95
+ The webhook usage is below.
96
+
97
+ ```ruby
98
+ events = ['invitee.created', 'invitee.canceled']
99
+ own_member = client.me.organization_membership
100
+ org = own_member.organization
101
+
102
+ # create user scope webhook
103
+ url = 'https://example.com/received_event'
104
+ user_webhook = own_member.create_user_scope_webhook(url, events)
105
+ # => #<Calendly::WebhookSubscription uuid:USER_WEBHOOK_001>
106
+
107
+ # list of user scope webhooks
108
+ own_member.user_scope_webhooks
109
+ # => [#<Calendly::WebhookSubscription uuid:USER_WEBHOOK_001>]
110
+
111
+ # delete the webhook
112
+ user_webhook.delete
113
+ # => true
119
114
 
115
+
116
+ # create organization scope webhook
117
+ url = 'https://example.com/received_event'
118
+ org_webhook = org.create_webhook(url, events)
119
+ # => #<Calendly::WebhookSubscription uuid:ORG_WEBHOOK_001>
120
+
121
+ # list of organization scope webhooks
122
+ org.webhooks
123
+ # => [#<Calendly::WebhookSubscription uuid:ORG_WEBHOOK_001>]
124
+
125
+ # delete the webhook
126
+ org_webhook.delete
127
+ # => true
128
+ ```
129
+
130
+ ### Logging
131
+
132
+ This library supports a configurable logger.
133
+
134
+ ```ruby
120
135
  # if the log level set :debug, you can get the request/response information.
121
136
  Calendly.configuration.logger.level = :debug
122
137
  invitation = my_org.create_invitation('foobar@example.com')
@@ -124,6 +139,8 @@ invitation = my_org.create_invitation('foobar@example.com')
124
139
  # D, [2020-08-10T10:48:16] DEBUG -- : Response status:201, body:{"resource":{"created_at":"2020-08-10T10:48:16.051159Z","email":"foobar@example.com","last_sent_at":"2020-08-10T10:48:16.096518Z","organization":"https://api.calendly.com/organizations/ORG001","status":"pending","updated_at":"2020-08-10T10:48:16.051159Z","uri":"https://api.calendly.com/organizations/ORG001/invitations/INV001"}}
125
140
  ```
126
141
 
142
+ More in-depth method documentation can be found at [RubyDoc.info](https://www.rubydoc.info/gems/calendly/).
143
+
127
144
  ## Contributing
128
145
 
129
146
  Bug reports and pull requests are welcome on [GitHub](https://github.com/koshilife/calendly-api-ruby-client). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
3
5
 
4
6
  Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
8
10
  end
9
11
 
10
- task :default => :test
12
+ task default: :test
@@ -29,7 +29,6 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ['lib']
30
30
 
31
31
  spec.add_runtime_dependency 'oauth2', '>= 1.4.4'
32
- spec.add_runtime_dependency 'zeitwerk', '>= 2.3.0'
33
32
 
34
33
  spec.add_development_dependency 'bundler'
35
34
  spec.add_development_dependency 'codecov'
@@ -1,9 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'zeitwerk'
4
- loader = Zeitwerk::Loader.for_gem
5
- loader.collapse('**/models')
6
- loader.setup
3
+ Dir[
4
+ File.join(
5
+ File.dirname(__FILE__),
6
+ 'calendly',
7
+ '**',
8
+ '*'
9
+ )
10
+ ].sort.each do |f|
11
+ next if File.directory? f
12
+
13
+ require f
14
+ end
7
15
 
8
16
  # module for Calendly apis client
9
17
  module Calendly
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'calendly/error'
4
+
3
5
  module Calendly
4
6
  # Calendly apis client error object.
5
- class ApiError < Calendly::Error
7
+ class ApiError < Error
6
8
  # @return [Faraday::Response]
7
9
  attr_reader :response
8
10
  # @return [Integer]
@@ -25,9 +27,9 @@ module Calendly
25
27
  "\#<#{self.class}:#{object_id} title:#{title}, status:#{status}>"
26
28
  end
27
29
 
28
- private
30
+ private
29
31
 
30
- def set_attributes_from_response
32
+ def set_attributes_from_response # rubocop:disable Metrics/CyclomaticComplexity
31
33
  return unless response
32
34
  return unless response.respond_to? :body
33
35
 
@@ -4,14 +4,15 @@ require 'oauth2'
4
4
 
5
5
  module Calendly
6
6
  # Calendly apis client.
7
- class Client
7
+ class Client # rubocop:disable Metrics/ClassLength
8
+ include Loggable
8
9
  API_HOST = 'https://api.calendly.com'
9
10
  AUTH_API_HOST = 'https://auth.calendly.com'
10
11
 
11
12
  # @param [String] token a Calendly's access token.
13
+ # @raise [Calendly::Error] if the token is empty.
12
14
  def initialize(token = nil)
13
15
  @config = Calendly.configuration
14
- @logger = @config.logger
15
16
  @token = token || Calendly.configuration.token
16
17
 
17
18
  check_not_empty @token, 'token'
@@ -38,8 +39,8 @@ module Calendly
38
39
  #
39
40
  # Refresh access token.
40
41
  #
41
- # @raise [Calendly::Error] if the client_id is empty.
42
- # @raise [Calendly::Error] if the client_secret is empty.
42
+ # @raise [Calendly::Error] if Calendly.configuration.client_id is empty.
43
+ # @raise [Calendly::Error] if Calendly.configuration.client_secret is empty.
43
44
  # @raise [Calendly::ApiError] if the api returns error code.
44
45
  # @since 0.0.7
45
46
  def refresh!
@@ -58,11 +59,21 @@ module Calendly
58
59
  # @raise [Calendly::ApiError] if the api returns error code.
59
60
  # @since 0.0.1
60
61
  def current_user
61
- user
62
+ return @cached_current_user if @cached_current_user
63
+
64
+ @cached_current_user = user
62
65
  end
63
66
 
64
67
  alias me current_user
65
68
 
69
+ # @since 0.2.0
70
+ def current_user!
71
+ @cached_current_user = nil
72
+ current_user
73
+ end
74
+
75
+ alias me! current_user!
76
+
66
77
  #
67
78
  # Get basic information about a user
68
79
  #
@@ -95,7 +106,7 @@ module Calendly
95
106
  check_not_empty user_uri, 'user_uri'
96
107
 
97
108
  opts_keys = %i[count page_token sort]
98
- params = { user: user_uri }
109
+ params = {user: user_uri}
99
110
  params = merge_options opts, opts_keys, params
100
111
  body = request :get, 'event_types', params: params
101
112
 
@@ -124,12 +135,12 @@ module Calendly
124
135
  # @param [String] user_uri the specified user (user's uri).
125
136
  # @param [Hash] opts the optional request parameters.
126
137
  # @option opts [Integer] :count Number of rows to return.
127
- # @option opts [String] :invitee_email Return events scheduled with the specified invitee email
138
+ # @option opts [String] :invitee_email Return events scheduled with the specified invitee email.
128
139
  # @option opts [String] :max_start_time Upper bound (inclusive) for an event's start time to filter by.
129
140
  # @option opts [String] :min_start_time Lower bound (inclusive) for an event's start time to filter by.
130
141
  # @option opts [String] :page_token Pass this to get the next portion of collection.
131
142
  # @option opts [String] :sort Order results by the specified field and directin. Accepts comma-separated list of {field}:{direction} values.
132
- # @option opts [String] :status Whether the scheduled event is active or canceled
143
+ # @option opts [String] :status Whether the scheduled event is active or canceled.
133
144
  # @return [Array<Array<Calendly::Event>, Hash>]
134
145
  # - [Array<Calendly::Event>] events
135
146
  # - [Hash] next_params the parameters to get next data. if thre is no next it returns nil.
@@ -140,7 +151,7 @@ module Calendly
140
151
  check_not_empty user_uri, 'user_uri'
141
152
 
142
153
  opts_keys = %i[count invitee_email max_start_time min_start_time page_token sort status]
143
- params = { user: user_uri }
154
+ params = {user: user_uri}
144
155
  params = merge_options opts, opts_keys, params
145
156
  body = request :get, 'scheduled_events', params: params
146
157
 
@@ -227,7 +238,7 @@ module Calendly
227
238
  check_not_empty org_uri, 'org_uri'
228
239
 
229
240
  opts_keys = %i[count email page_token]
230
- params = { organization: org_uri }
241
+ params = {organization: org_uri}
231
242
  params = merge_options opts, opts_keys, params
232
243
  body = request :get, 'organization_memberships', params: params
233
244
 
@@ -254,7 +265,7 @@ module Calendly
254
265
  check_not_empty user_uri, 'user_uri'
255
266
 
256
267
  opts_keys = %i[count email page_token]
257
- params = { user: user_uri }
268
+ params = {user: user_uri}
258
269
  params = merge_options opts, opts_keys, params
259
270
  body = request :get, 'organization_memberships', params: params
260
271
 
@@ -273,15 +284,15 @@ module Calendly
273
284
  # @since 0.0.7
274
285
  def delete_membership(uuid)
275
286
  check_not_empty uuid, 'uuid'
276
- request :delete, "organization_memberships/#{uuid}", expected_status: 204
287
+ request :delete, "organization_memberships/#{uuid}"
277
288
  true
278
289
  end
279
290
 
280
291
  #
281
292
  # Returns an Organization Invitation.
282
293
  #
283
- # @param [String] org_uuid the specified organization (organization's uri).
284
- # @param [String] inv_uuid the specified invitation (organization invitation's uri).
294
+ # @param [String] org_uuid the specified organization (organization's uuid).
295
+ # @param [String] inv_uuid the specified invitation (organization invitation's uuid).
285
296
  # @return [Calendly::OrganizationInvitation]
286
297
  # @raise [Calendly::Error] if the org_uuid arg is empty.
287
298
  # @raise [Calendly::Error] if the inv_uuid arg is empty.
@@ -298,7 +309,7 @@ module Calendly
298
309
  #
299
310
  # Get Organization Invitations.
300
311
  #
301
- # @param [String] uuid the specified organization (organization's uri).
312
+ # @param [String] uuid the specified organization (organization's uuid).
302
313
  # @param [Hash] opts the optional request parameters.
303
314
  # @option opts [Integer] :count Number of rows to return.
304
315
  # @option opts [String] :email Filter by email.
@@ -326,7 +337,7 @@ module Calendly
326
337
  #
327
338
  # Invite a person to an Organization.
328
339
  #
329
- # @param [String] uuid the specified organization (organization's uri).
340
+ # @param [String] uuid the specified organization (organization's uuid).
330
341
  # @param [String] email Email of the person being invited.
331
342
  # @return [Calendly::OrganizationInvitation]
332
343
  # @raise [Calendly::Error] if the uuid arg is empty.
@@ -339,8 +350,7 @@ module Calendly
339
350
  body = request(
340
351
  :post,
341
352
  "organizations/#{uuid}/invitations",
342
- body: { email: email },
343
- expected_status: 201
353
+ body: {email: email}
344
354
  )
345
355
  OrganizationInvitation.new body[:resource], self
346
356
  end
@@ -348,8 +358,8 @@ module Calendly
348
358
  #
349
359
  # Revoke Organization Invitation.
350
360
  #
351
- # @param [String] org_uuid the specified organization (organization's uri).
352
- # @param [String] inv_uuid the specified invitation (organization invitation's uri).
361
+ # @param [String] org_uuid the specified organization (organization's uuid).
362
+ # @param [String] inv_uuid the specified invitation (organization invitation's uuid).
353
363
  # @return [true]
354
364
  # @raise [Calendly::Error] if the org_uuid arg is empty.
355
365
  # @raise [Calendly::Error] if the inv_uuid arg is empty.
@@ -358,40 +368,134 @@ module Calendly
358
368
  def delete_invitation(org_uuid, inv_uuid)
359
369
  check_not_empty org_uuid, 'org_uuid'
360
370
  check_not_empty inv_uuid, 'inv_uuid'
361
- request(
362
- :delete,
363
- "organizations/#{org_uuid}/invitations/#{inv_uuid}",
364
- expected_status: 204
365
- )
371
+ request :delete, "organizations/#{org_uuid}/invitations/#{inv_uuid}"
366
372
  true
367
373
  end
368
374
 
369
- private
375
+ #
376
+ # Get a webhook subscription for an organization or user with a specified UUID.
377
+ #
378
+ # @param [String] uuid the specified webhook (webhook's uuid).
379
+ # @return [Calendly::WebhookSubscription]
380
+ # @raise [Calendly::Error] if the uuid arg is empty.
381
+ # @raise [Calendly::ApiError] if the api returns error code.
382
+ # @since 0.1.3
383
+ def webhook(uuid)
384
+ check_not_empty uuid, 'uuid'
385
+ body = request :get, "webhook_subscriptions/#{uuid}"
386
+ WebhookSubscription.new body[:resource], self
387
+ end
370
388
 
371
- def debug_log(msg)
372
- return unless @logger
389
+ #
390
+ # Get List of organization scope Webhooks.
391
+ #
392
+ # @param [String] org_uri the specified organization (organization's uri).
393
+ # @param [Hash] opts the optional request parameters.
394
+ # @option opts [Integer] :count Number of rows to return.
395
+ # @option opts [String] :page_token Pass this to get the next portion of collection.
396
+ # @option opts [String] :sort Order results by the specified field and directin. Accepts comma-separated list of {field}:{direction} values.
397
+ # @return [Array<Array<Calendly::WebhookSubscription>, Hash>]
398
+ # - [Array<Calendly::WebhookSubscription>] webhooks
399
+ # - [Hash] next_params the parameters to get next data. if thre is no next it returns nil.
400
+ # @raise [Calendly::Error] if the org_uri arg is empty.
401
+ # @raise [Calendly::ApiError] if the api returns error code.
402
+ # @since 0.1.3
403
+ def webhooks(org_uri, opts = {})
404
+ check_not_empty org_uri, 'org_uri'
373
405
 
374
- @logger.debug msg
406
+ opts_keys = %i[count page_token sort]
407
+ params = {organization: org_uri, scope: 'organization'}
408
+ params = merge_options opts, opts_keys, params
409
+ body = request :get, 'webhook_subscriptions', params: params
410
+ items = body[:collection] || []
411
+ evs = items.map { |item| WebhookSubscription.new item, self }
412
+ [evs, next_page_params(body)]
375
413
  end
376
414
 
377
- def request(method, path, params: nil, body: nil, expected_status: nil)
415
+ #
416
+ # Get List of user scope Webhooks.
417
+ #
418
+ # @param [String] org_uri the specified organization (organization's uri).
419
+ # @param [String] user_uri the specified user (user's uri).
420
+ # @param [Hash] opts the optional request parameters.
421
+ # @option opts [Integer] :count Number of rows to return.
422
+ # @option opts [String] :page_token Pass this to get the next portion of collection.
423
+ # @option opts [String] :sort Order results by the specified field and directin. Accepts comma-separated list of {field}:{direction} values.
424
+ # @return [Array<Array<Calendly::WebhookSubscription>, Hash>]
425
+ # - [Array<Calendly::WebhookSubscription>] webhooks
426
+ # - [Hash] next_params the parameters to get next data. if thre is no next it returns nil.
427
+ # @raise [Calendly::Error] if the org_uri arg is empty.
428
+ # @raise [Calendly::Error] if the user_uri arg is empty.
429
+ # @raise [Calendly::ApiError] if the api returns error code.
430
+ # @since 0.1.3
431
+ def user_scope_webhooks(org_uri, user_uri, opts = {})
432
+ check_not_empty org_uri, 'org_uri'
433
+ check_not_empty user_uri, 'user_uri'
434
+
435
+ opts_keys = %i[count page_token sort]
436
+ params = {organization: org_uri, user: user_uri, scope: 'user'}
437
+ params = merge_options opts, opts_keys, params
438
+ body = request :get, 'webhook_subscriptions', params: params
439
+ items = body[:collection] || []
440
+ evs = items.map { |item| WebhookSubscription.new item, self }
441
+ [evs, next_page_params(body)]
442
+ end
443
+
444
+ #
445
+ # Create a webhook subscription for an organization or user.
446
+ #
447
+ # @param [String] url Canonical reference (unique identifier) for the resource.
448
+ # @param [Array<String>] events List of user events to subscribe to. options: invitee.created or invitee.canceled
449
+ # @param [String] org_uri The unique reference to the organization that the webhook will be tied to.
450
+ # @param [String] user_uri The unique reference to the user that the webhook will be tied to.
451
+ # @return [Calendly::WebhookSubscription]
452
+ # @raise [Calendly::Error] if the url arg is empty.
453
+ # @raise [Calendly::Error] if the events arg is empty.
454
+ # @raise [Calendly::Error] if the org_uri arg is empty.
455
+ # @raise [Calendly::ApiError] if the api returns error code.
456
+ # @since 0.1.3
457
+ def create_webhook(url, events, org_uri, user_uri = nil)
458
+ check_not_empty url, 'url'
459
+ check_not_empty events, 'events'
460
+ check_not_empty org_uri, 'org_uri'
461
+
462
+ params = {url: url, events: events, organization: org_uri}
463
+ if user_uri
464
+ params[:scope] = 'user'
465
+ params[:user] = user_uri
466
+ else
467
+ params[:scope] = 'organization'
468
+ end
469
+ body = request(:post, 'webhook_subscriptions', body: params)
470
+ WebhookSubscription.new body[:resource], self
471
+ end
472
+
473
+ #
474
+ # Delete a webhook subscription for an organization or user with a specified UUID.
475
+ #
476
+ # @param [String] uuid the specified webhook (webhook's uuid).
477
+ # @return [true]
478
+ # @raise [Calendly::Error] if the uuid arg is empty.
479
+ # @raise [Calendly::ApiError] if the api returns error code.
480
+ # @since 0.1.3
481
+ def delete_webhook(uuid)
482
+ check_not_empty uuid, 'uuid'
483
+ request :delete, "webhook_subscriptions/#{uuid}"
484
+ true
485
+ end
486
+
487
+ private
488
+
489
+ def request(method, path, params: nil, body: nil)
378
490
  debug_log "Request #{method.to_s.upcase} #{API_HOST}/#{path} params:#{params}, body:#{body}"
379
491
  res = access_token.request(method, path, params: params, body: body)
380
492
  debug_log "Response status:#{res.status}, body:#{res.body}"
381
- validate_status_code res, expected_status
382
493
  parse_as_json res
383
494
  rescue OAuth2::Error => e
384
495
  res = e.response.response
385
496
  raise ApiError.new res, e
386
497
  end
387
498
 
388
- def validate_status_code(res, expected_status)
389
- return unless expected_status
390
- return if expected_status == res.status
391
-
392
- raise ApiError.new res, message: 'unexpected http status returned.'
393
- end
394
-
395
499
  def parse_as_json(res)
396
500
  return if blank? res.body
397
501
 
@@ -401,12 +505,13 @@ module Calendly
401
505
  end
402
506
 
403
507
  def check_not_empty(value, name)
404
- raise Calendly::Error, "#{name} is required." if blank? value
508
+ raise Error.new("#{name} is required.") if blank? value
405
509
  end
406
510
 
407
511
  def blank?(value)
408
512
  return true if value.nil?
409
513
  return true if value.to_s.empty?
514
+ return true if value.is_a?(Array) && value.empty?
410
515
 
411
516
  false
412
517
  end