calendlyr 0.7.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +9 -5
  3. data/.gitignore +2 -1
  4. data/CHANGELOG.md +66 -0
  5. data/README.md +31 -79
  6. data/calendlyr.gemspec +6 -7
  7. data/docs/resources/data_compliance.md +1 -1
  8. data/docs/resources/event_types/availability_schedule.md +28 -0
  9. data/docs/resources/event_types/event_type.md +18 -7
  10. data/docs/resources/events/cancellation.md +1 -1
  11. data/docs/resources/events/event.md +2 -2
  12. data/docs/resources/events/invitee.md +17 -0
  13. data/docs/resources/locations/location.md +16 -0
  14. data/docs/resources/organizations/organization.md +0 -9
  15. data/docs/resources/share.md +2 -9
  16. data/docs/resources/webhooks/invitee_payload.md +1 -1
  17. data/docs/resources/webhooks/payload.md +1 -1
  18. data/docs/resources/webhooks/subscription.md +1 -1
  19. data/lib/calendlyr/client.rb +20 -45
  20. data/lib/calendlyr/collection.rb +18 -3
  21. data/lib/calendlyr/error.rb +17 -26
  22. data/lib/calendlyr/object.rb +77 -14
  23. data/lib/calendlyr/objects/event_type.rb +0 -4
  24. data/lib/calendlyr/objects/event_types/availability_schedule.rb +8 -0
  25. data/lib/calendlyr/objects/events/invitee.rb +1 -1
  26. data/lib/calendlyr/objects/location.rb +4 -0
  27. data/lib/calendlyr/objects/organization.rb +0 -4
  28. data/lib/calendlyr/objects/share.rb +0 -5
  29. data/lib/calendlyr/resource.rb +34 -7
  30. data/lib/calendlyr/resources/event_types.rb +37 -0
  31. data/lib/calendlyr/resources/{event.rb → events.rb} +6 -1
  32. data/lib/calendlyr/resources/{group.rb → groups.rb} +1 -1
  33. data/lib/calendlyr/resources/locations.rb +8 -0
  34. data/lib/calendlyr/resources/{organization.rb → organizations.rb} +1 -1
  35. data/lib/calendlyr/resources/{routing_form.rb → routing_forms.rb} +1 -1
  36. data/lib/calendlyr/resources/{share.rb → shares.rb} +1 -1
  37. data/lib/calendlyr/resources/{user.rb → users.rb} +1 -1
  38. data/lib/calendlyr/resources/{webhook.rb → webhooks.rb} +1 -5
  39. data/lib/calendlyr/version.rb +1 -1
  40. data/lib/calendlyr.rb +15 -15
  41. data/test/calendlyr/client_test.rb +25 -0
  42. data/test/calendlyr/collection_test.rb +64 -0
  43. data/test/calendlyr/object_test.rb +32 -1
  44. data/test/calendlyr/objects/event_type_test.rb +0 -15
  45. data/test/calendlyr/objects/event_types/availability_schedule_test.rb +20 -0
  46. data/test/calendlyr/objects/events/cancellation_test.rb +1 -1
  47. data/test/calendlyr/objects/events/guest_test.rb +1 -1
  48. data/test/calendlyr/objects/events/invitee_no_show_test.rb +1 -1
  49. data/test/calendlyr/objects/events/invitee_test.rb +10 -3
  50. data/test/calendlyr/objects/location_test.rb +22 -0
  51. data/test/calendlyr/objects/organization_test.rb +0 -8
  52. data/test/calendlyr/objects/organizations/invitation_test.rb +1 -1
  53. data/test/calendlyr/objects/share_test.rb +3 -9
  54. data/test/calendlyr/resource_test.rb +178 -2
  55. data/test/calendlyr/resources/data_compliance_test.rb +1 -4
  56. data/test/calendlyr/resources/event_types_test.rb +48 -0
  57. data/test/calendlyr/resources/events_test.rb +19 -0
  58. data/test/calendlyr/resources/locations_test.rb +18 -0
  59. data/test/calendlyr/resources/webhooks_test.rb +0 -8
  60. data/test/fixtures/event_invitees/retrieve.json +11 -1
  61. data/test/fixtures/event_type_availability_schedules/list.json +17 -0
  62. data/test/fixtures/event_type_availability_schedules/update.json +3 -0
  63. data/test/fixtures/event_types/create.json +30 -0
  64. data/test/fixtures/event_types/update.json +30 -0
  65. data/test/fixtures/events/create_invitee.json +37 -0
  66. data/test/fixtures/events/retrieve.json +12 -2
  67. data/test/fixtures/locations/list.json +16 -0
  68. data/test/fixtures/objects/event.json +10 -2
  69. data/test/fixtures/objects/event_types/availability_schedule.json +6 -0
  70. data/test/fixtures/objects/location.json +5 -0
  71. data/test/test_helper.rb +9 -7
  72. metadata +47 -65
  73. data/docs/resources/event_types/available_time.md +0 -21
  74. data/docs/resources/event_types/membership.md +0 -29
  75. data/docs/resources/scheduling_link.md +0 -26
  76. data/lib/calendlyr/objects/event_types/available_time.rb +0 -4
  77. data/lib/calendlyr/objects/event_types/membership.rb +0 -11
  78. data/lib/calendlyr/objects/scheduling_link.rb +0 -9
  79. data/lib/calendlyr/resources/event_type.rb +0 -28
  80. data/lib/calendlyr/resources/outgoing_communication.rb +0 -8
  81. data/lib/calendlyr/resources/scheduling_link.rb +0 -8
  82. data/test/calendlyr/objects/event_types/available_time_test.rb +0 -20
  83. data/test/calendlyr/objects/event_types/membership_test.rb +0 -32
  84. data/test/calendlyr/objects/scheduling_link_test.rb +0 -17
  85. data/test/calendlyr/resources/event_types/membership_test.rb +0 -22
  86. data/test/calendlyr/resources/outgoing_communications_test.rb +0 -16
  87. data/test/calendlyr/resources/scheduling_links_test.rb +0 -15
  88. data/test/fixtures/event_type_available_times/list.json +0 -22
  89. data/test/fixtures/objects/event_types/available_time.json +0 -6
  90. data/test/fixtures/objects/event_types/membership.json +0 -65
  91. data/test/fixtures/objects/scheduling_links/event_type.json +0 -5
  92. data/test/fixtures/outgoing_communications/list.json +0 -26
  93. data/test/fixtures/scheduling_links/create.json +0 -7
  94. data/test/fixtures/webhooks/sample.json +0 -105
@@ -1,33 +1,23 @@
1
1
  module Calendlyr
2
2
  class Error < StandardError; end
3
3
 
4
- class PermissionDenied < StandardError; end
5
-
6
- class BadRequest < StandardError; end
7
-
8
- class PaymentRequired < StandardError; end
9
-
10
- class Unauthenticated < StandardError; end
11
-
12
- class NotFound < StandardError; end
13
-
14
- class ExternalCalendarError < StandardError; end
15
-
16
- class InternalServerError < StandardError; end
17
-
18
- class TooManyRequests < StandardError; end
4
+ class PaymentRequired < Error; end
5
+
6
+ ERROR_TYPES = {
7
+ "400" => "BadRequest",
8
+ "401" => "Unauthenticated",
9
+ "403" => "PermissionDenied",
10
+ "404" => "NotFound",
11
+ "424" => "ExternalCalendarError",
12
+ "429" => "TooManyRequests",
13
+ "500" => "InternalServerError"
14
+ }
15
+
16
+ ERROR_TYPES.values.each do |error_class|
17
+ Calendlyr.const_set(error_class, Class.new(Error))
18
+ end
19
19
 
20
20
  class ResponseErrorHandler
21
- ERROR_TYPES = {
22
- "400" => BadRequest,
23
- "401" => Unauthenticated,
24
- "403" => PermissionDenied,
25
- "404" => NotFound,
26
- "424" => ExternalCalendarError,
27
- "429" => TooManyRequests,
28
- "500" => InternalServerError
29
- }
30
-
31
21
  def initialize(code, body)
32
22
  @code = code
33
23
  @body = body
@@ -44,7 +34,8 @@ module Calendlyr
44
34
  def error_type
45
35
  return PaymentRequired if @code == "403" && @body["message"].include?("upgrade")
46
36
 
47
- ERROR_TYPES[@code]
37
+ klass = "Calendlyr::#{Calendlyr::ERROR_TYPES[@code]}"
38
+ Calendlyr.const_get(klass)
48
39
  end
49
40
 
50
41
  def too_many_requests_error
@@ -1,31 +1,94 @@
1
- require "ostruct"
2
-
3
1
  module Calendlyr
4
- class Object < OpenStruct
2
+ class Object
5
3
  def self.get_slug(path)
6
4
  path.split("/").last
7
5
  end
8
6
 
9
- def initialize(attributes)
10
- super(to_ostruct(attributes.merge(uuid: extract_uuid(attributes))))
7
+ private_class_method :get_slug
8
+
9
+ def initialize(attributes = nil, add_uuid: true, **kwargs)
10
+ attrs = (attributes || {}).merge(kwargs).dup
11
+ if add_uuid && !attrs.key?(:uuid) && !attrs.key?("uuid")
12
+ attrs = attrs.merge(uuid: extract_uuid(attrs))
13
+ end
14
+
15
+ @attributes = attrs.each_with_object({}) do |(key, value), hash|
16
+ hash[key.to_s] = wrap(value)
17
+ end
11
18
  end
12
19
 
13
- def to_ostruct(obj)
14
- if obj.is_a?(Hash)
15
- OpenStruct.new(obj.map { |key, val| [key, to_ostruct(val)] }.to_h)
16
- elsif obj.is_a?(Array)
17
- obj.map { |o| to_ostruct(o) }
18
- else # Assumed to be a primitive value
19
- obj
20
+ def method_missing(name, *args, &block)
21
+ if args.empty? && block.nil?
22
+ return @attributes[name.to_s] if @attributes.key?(name.to_s)
23
+
24
+ return nil
20
25
  end
26
+
27
+ super
21
28
  end
22
29
 
30
+ def respond_to_missing?(name, include_private = false)
31
+ @attributes.key?(name.to_s) || super
32
+ end
33
+
34
+ def to_h
35
+ @attributes.each_with_object({}) do |(key, value), hash|
36
+ hash[key.to_sym] = unwrap(value)
37
+ end
38
+ end
39
+
40
+ def inspect
41
+ attributes = @attributes.map do |key, value|
42
+ "#{key}=#{value.inspect}"
43
+ end.join(" ")
44
+ "#<#{self.class} #{attributes}>"
45
+ end
46
+
47
+ def ==(other)
48
+ other.is_a?(self.class) && to_h == other.to_h
49
+ end
50
+
51
+ def eql?(other)
52
+ self == other
53
+ end
54
+
55
+ def hash
56
+ to_h.hash
57
+ end
58
+
59
+ private
60
+
23
61
  def extract_uuid(attrs)
24
- attrs["uri"] ? get_slug(attrs["uri"]) : nil
62
+ uri = attrs["uri"] || attrs[:uri]
63
+ uri ? get_slug(uri) : nil
25
64
  end
26
65
 
66
+ protected
67
+
27
68
  def get_slug(path)
28
- Calendlyr::Object.get_slug(path)
69
+ self.class.send(:get_slug, path)
70
+ end
71
+
72
+ private
73
+
74
+ def wrap(value)
75
+ if value.is_a?(Hash)
76
+ self.class.new(value, add_uuid: false)
77
+ elsif value.is_a?(Array)
78
+ value.map { |item| wrap(item) }
79
+ else
80
+ value
81
+ end
82
+ end
83
+
84
+ def unwrap(value)
85
+ if value.is_a?(self.class)
86
+ value.to_h
87
+ elsif value.is_a?(Array)
88
+ value.map { |item| unwrap(item) }
89
+ else
90
+ value
91
+ end
29
92
  end
30
93
  end
31
94
  end
@@ -7,9 +7,5 @@ module Calendlyr
7
7
  def create_share(**params)
8
8
  client.shares.create(**params.merge(event_type: uri))
9
9
  end
10
-
11
- def available_times(start_time:, end_time:, **params)
12
- client.event_types.list_available_times(**params.merge(event_type: uri, start_time: start_time, end_time: end_time))
13
- end
14
10
  end
15
11
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Calendlyr
4
+ module EventTypes
5
+ class AvailabilitySchedule < Object
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  module Calendlyr
2
2
  class Events::Invitee < Object
3
3
  def cancel(reason: nil)
4
- client.events.cancel(uuid: uuid, reason: reason)
4
+ client.events.cancel(uuid: get_slug(event), reason: reason)
5
5
  end
6
6
 
7
7
  def create_no_shows
@@ -0,0 +1,4 @@
1
+ module Calendlyr
2
+ class Location < Object
3
+ end
4
+ end
@@ -43,10 +43,6 @@ module Calendlyr
43
43
  client.webhooks.create(**params.merge(organization: uri, url: url, events: events, scope: scope))
44
44
  end
45
45
 
46
- def sample_webhook_data(event:, scope:, **params)
47
- client.webhooks.sample_webhook_data(event: event, scope: scope, organization: uri, **params)
48
- end
49
-
50
46
  # Invitations
51
47
  def invite_user(email:, **params)
52
48
  client.organizations.invite(**params.merge(organization_uuid: uuid, email: email))
@@ -1,9 +1,4 @@
1
1
  module Calendlyr
2
2
  class Share < Object
3
- def associated_scheduling_links
4
- scheduling_links.map do |scheduling_link|
5
- SchedulingLink.new(scheduling_link.to_h.merge(client: client))
6
- end
7
- end
8
3
  end
9
4
  end
@@ -8,6 +8,8 @@ module Calendlyr
8
8
  attr_reader :client
9
9
 
10
10
  ERROR_CODES = %w[400 401 403 404 424 429 500]
11
+ MAX_RETRIES = 3
12
+ RETRY_BACKOFF = [1, 2, 4]
11
13
 
12
14
  def initialize(client)
13
15
  @client = client
@@ -23,6 +25,14 @@ module Calendlyr
23
25
  handle_response request(url, Net::HTTP::Post, body: body)
24
26
  end
25
27
 
28
+ def patch_request(url, body:)
29
+ handle_response request(url, Net::HTTP::Patch, body: body)
30
+ end
31
+
32
+ def put_request(url, body:)
33
+ handle_response request(url, Net::HTTP::Put, body: body)
34
+ end
35
+
26
36
  def delete_request(url, params: {})
27
37
  handle_response request(url, Net::HTTP::Delete, params: params)
28
38
  end
@@ -37,30 +47,47 @@ module Calendlyr
37
47
 
38
48
  http = Net::HTTP.new(uri.host, uri.port)
39
49
  http.use_ssl = true
40
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
50
+ http.open_timeout = client.open_timeout
51
+ http.read_timeout = client.read_timeout
41
52
 
42
53
  request = req_type.new(uri)
43
54
  request["Content-Type"] = "application/json"
44
55
  request["Authorization"] = "Bearer #{client.token}"
45
56
  request.body = body.to_json if body.any?
46
57
 
47
- http.request(request)
58
+ attempts = 0
59
+
60
+ loop do
61
+ response = http.request(request)
62
+ return response unless response.code == "429"
63
+ return response if attempts >= MAX_RETRIES
64
+
65
+ sleep retry_after_seconds(response, attempts)
66
+ attempts += 1
67
+ end
48
68
  end
49
69
 
50
70
  def handle_response(response)
51
- return true unless response.read_body
71
+ body_string = response.body.to_s
52
72
 
53
73
  body = begin
54
- JSON.parse(response.read_body)
55
- rescue
74
+ body_string.empty? ? {} : JSON.parse(body_string)
75
+ rescue JSON::ParserError
56
76
  {}
57
77
  end
58
78
 
59
79
  if ERROR_CODES.include? response.code
60
80
  raise ResponseErrorHandler.new(response.code, body).error
61
- else
62
- body
63
81
  end
82
+
83
+ body
84
+ end
85
+
86
+ def retry_after_seconds(response, attempt)
87
+ retry_after = response["Retry-After"]
88
+ return retry_after.to_i if retry_after&.match?(/^\d+$/)
89
+
90
+ RETRY_BACKOFF.fetch(attempt)
64
91
  end
65
92
  end
66
93
  end
@@ -0,0 +1,37 @@
1
+ module Calendlyr
2
+ class EventTypesResource < Resource
3
+ def list(**params)
4
+ response = get_request("event_types", params: params)
5
+ Collection.from_response(response, type: EventType, client: client)
6
+ end
7
+
8
+ def retrieve(uuid:)
9
+ EventType.new get_request("event_types/#{uuid}").dig("resource").merge(client: client)
10
+ end
11
+
12
+ def create_one_off(name:, host:, duration:, date_setting:, location:, **params)
13
+ body = {name: name, host: host, duration: duration, date_setting: date_setting, location: location}.merge(params)
14
+ EventType.new post_request("one_off_event_types", body: body).dig("resource").merge(client: client)
15
+ end
16
+
17
+ def create(name:, duration:, pooling_type:, **params)
18
+ body = {name: name, duration: duration, pooling_type: pooling_type}.merge(params)
19
+ EventType.new post_request("event_types", body: body).dig("resource").merge(client: client)
20
+ end
21
+
22
+ def update(uuid:, **params)
23
+ EventType.new patch_request("event_types/#{uuid}", body: params).dig("resource").merge(client: client)
24
+ end
25
+
26
+ # Availability Schedules
27
+ def list_availability_schedules(event_type_uuid:, **params)
28
+ response = get_request("event_type_availability_schedules", params: {event_type_uuid: event_type_uuid}.merge(params))
29
+ Collection.from_response(response, type: EventTypes::AvailabilitySchedule, client: client)
30
+ end
31
+
32
+ def update_availability_schedule(event_type_uuid:, availability_schedules:, **params)
33
+ body = {event_type_uuid: event_type_uuid, availability_schedules: availability_schedules}.merge(params)
34
+ patch_request("event_type_availability_schedules", body: body)
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class EventResource < Resource
2
+ class EventsResource < Resource
3
3
  def list(**params)
4
4
  response = get_request("scheduled_events", params: params)
5
5
  Collection.from_response(response, type: Event, client: client)
@@ -23,6 +23,11 @@ module Calendlyr
23
23
  Events::Invitee.new get_request("scheduled_events/#{event_uuid}/invitees/#{invitee_uuid}").dig("resource").merge(client: client)
24
24
  end
25
25
 
26
+ def create_invitee(event_type:, start_time:, invitee:, **params)
27
+ body = {event_type: event_type, start_time: start_time, invitee: invitee}.merge(params)
28
+ Events::Invitee.new post_request("invitees", body: body).dig("invitee").merge(client: client)
29
+ end
30
+
26
31
  # Invitee No Show
27
32
  def retrieve_invitee_no_show(uuid:)
28
33
  Events::InviteeNoShow.new get_request("invitee_no_shows/#{uuid}").dig("resource").merge(client: client)
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class GroupResource < Resource
2
+ class GroupsResource < Resource
3
3
  def list(organization:, **params)
4
4
  response = get_request("groups", params: params.merge(organization: organization))
5
5
  Collection.from_response(response, type: Group, client: client)
@@ -0,0 +1,8 @@
1
+ module Calendlyr
2
+ class LocationsResource < Resource
3
+ def list(**params)
4
+ response = get_request("locations", params: params)
5
+ Collection.from_response(response, type: Location, client: client)
6
+ end
7
+ end
8
+ end
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class OrganizationResource < Resource
2
+ class OrganizationsResource < Resource
3
3
  def activity_log(organization: nil, **params)
4
4
  response = get_request("activity_log_entries", params: {organization: organization}.merge(params).compact)
5
5
  Collection.from_response(response, type: ActivityLog, client: client)
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class RoutingFormResource < Resource
2
+ class RoutingFormsResource < Resource
3
3
  def list(organization:, **params)
4
4
  response = get_request("routing_forms", params: {organization: organization}.merge(params))
5
5
  Collection.from_response(response, type: RoutingForm, client: client)
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class ShareResource < Resource
2
+ class SharesResource < Resource
3
3
  def create(event_type:, **params)
4
4
  body = {event_type: event_type}.merge(params)
5
5
  Share.new post_request("shares", body: body).dig("resource").merge(client: client)
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class UserResource < Resource
2
+ class UsersResource < Resource
3
3
  def me
4
4
  retrieve(uuid: "me")
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Calendlyr
2
- class WebhookResource < Resource
2
+ class WebhooksResource < Resource
3
3
  def list(organization:, scope:, **params)
4
4
  response = get_request("webhook_subscriptions", params: params.merge(organization: organization, scope: scope).compact)
5
5
  Collection.from_response(response, type: Webhooks::Subscription, client: client)
@@ -17,9 +17,5 @@ module Calendlyr
17
17
  def delete(webhook_uuid:)
18
18
  delete_request("webhook_subscriptions/#{webhook_uuid}")
19
19
  end
20
-
21
- def sample_webhook_data(event:, organization:, scope:, **params)
22
- Object.new get_request("sample_webhook_data", params: params.merge(event: event, organization: organization, scope: scope)).merge(client: client)
23
- end
24
20
  end
25
21
  end
@@ -1,3 +1,3 @@
1
1
  module Calendlyr
2
- VERSION = "0.7.4"
2
+ VERSION = "0.10.0"
3
3
  end
data/lib/calendlyr.rb CHANGED
@@ -7,29 +7,30 @@ module Calendlyr
7
7
  autoload :Resource, "calendlyr/resource"
8
8
 
9
9
  # Errors
10
+ autoload :ERROR_TYPES, "calendlyr/error"
10
11
  autoload :BadRequest, "calendlyr/error"
11
12
  autoload :Error, "calendlyr/error"
12
- autoload :ExternalCalendarEror, "calendlyr/error"
13
+ autoload :ExternalCalendarError, "calendlyr/error"
13
14
  autoload :InternalServerError, "calendlyr/error"
14
15
  autoload :NotFound, "calendlyr/error"
15
16
  autoload :PaymentRequired, "calendlyr/error"
16
17
  autoload :PermissionDenied, "calendlyr/error"
17
- autoload :ResponseErrorHandler, "calendlyr/error"
18
18
  autoload :Unauthenticated, "calendlyr/error"
19
+ autoload :TooManyRequests, "calendlyr/error"
20
+ autoload :ResponseErrorHandler, "calendlyr/error"
19
21
 
20
22
  # High-level categories of Calendly API calls
21
23
  autoload :AvailabilityResource, "calendlyr/resources/availability"
22
24
  autoload :DataComplianceResource, "calendlyr/resources/data_compliance"
23
- autoload :EventResource, "calendlyr/resources/event"
24
- autoload :EventTypeResource, "calendlyr/resources/event_type"
25
- autoload :GroupResource, "calendlyr/resources/group"
26
- autoload :OrganizationResource, "calendlyr/resources/organization"
27
- autoload :OutgoingCommunicationResource, "calendlyr/resources/outgoing_communication"
28
- autoload :RoutingFormResource, "calendlyr/resources/routing_form"
29
- autoload :SchedulingLinkResource, "calendlyr/resources/scheduling_link"
30
- autoload :ShareResource, "calendlyr/resources/share"
31
- autoload :UserResource, "calendlyr/resources/user"
32
- autoload :WebhookResource, "calendlyr/resources/webhook"
25
+ autoload :EventsResource, "calendlyr/resources/events"
26
+ autoload :EventTypesResource, "calendlyr/resources/event_types"
27
+ autoload :GroupsResource, "calendlyr/resources/groups"
28
+ autoload :OrganizationsResource, "calendlyr/resources/organizations"
29
+ autoload :LocationsResource, "calendlyr/resources/locations"
30
+ autoload :RoutingFormsResource, "calendlyr/resources/routing_forms"
31
+ autoload :SharesResource, "calendlyr/resources/shares"
32
+ autoload :UsersResource, "calendlyr/resources/users"
33
+ autoload :WebhooksResource, "calendlyr/resources/webhooks"
33
34
 
34
35
  # Classes used to return a nicer object wrapping the response data
35
36
  autoload :ActivityLog, "calendlyr/objects/activity_log"
@@ -37,8 +38,8 @@ module Calendlyr
37
38
  autoload :EventType, "calendlyr/objects/event_type"
38
39
  autoload :Group, "calendlyr/objects/group"
39
40
  autoload :Organization, "calendlyr/objects/organization"
41
+ autoload :Location, "calendlyr/objects/location"
40
42
  autoload :RoutingForm, "calendlyr/objects/routing_form"
41
- autoload :SchedulingLink, "calendlyr/objects/scheduling_link"
42
43
  autoload :Share, "calendlyr/objects/share"
43
44
  autoload :User, "calendlyr/objects/user"
44
45
 
@@ -56,8 +57,7 @@ module Calendlyr
56
57
  end
57
58
 
58
59
  module EventTypes
59
- autoload :AvailableTime, "calendlyr/objects/event_types/available_time"
60
- autoload :Membership, "calendlyr/objects/event_types/membership"
60
+ autoload :AvailabilitySchedule, "calendlyr/objects/event_types/availability_schedule"
61
61
  autoload :Profile, "calendlyr/objects/event_types/profile"
62
62
  end
63
63
 
@@ -8,4 +8,29 @@ class ClientTest < Minitest::Test
8
8
  def test_inspect
9
9
  assert_equal "#<Calendlyr::Client>", client.inspect
10
10
  end
11
+
12
+ def test_method_missing
13
+ assert_raises NoMethodError do
14
+ client.useers
15
+ end
16
+ end
17
+
18
+ def test_respond_to_missing?
19
+ assert client.respond_to?(:users)
20
+ refute client.respond_to?(:useers)
21
+ end
22
+
23
+ def test_default_timeouts
24
+ new_client = Calendlyr::Client.new(token: "fake")
25
+
26
+ assert_equal 30, new_client.open_timeout
27
+ assert_equal 30, new_client.read_timeout
28
+ end
29
+
30
+ def test_custom_timeouts
31
+ new_client = Calendlyr::Client.new(token: "fake", open_timeout: 10, read_timeout: 15)
32
+
33
+ assert_equal 10, new_client.open_timeout
34
+ assert_equal 15, new_client.read_timeout
35
+ end
11
36
  end
@@ -0,0 +1,64 @@
1
+ require "test_helper"
2
+
3
+ class CollectionTest < Minitest::Test
4
+ def build_collection
5
+ data = [
6
+ Calendlyr::Object.new(name: "Alice"),
7
+ Calendlyr::Object.new(name: "Bob")
8
+ ]
9
+
10
+ Calendlyr::Collection.new(data: data, count: 2, next_page: nil, client: client)
11
+ end
12
+
13
+ def test_each_yields_items
14
+ collection = build_collection
15
+ names = []
16
+
17
+ collection.each do |item|
18
+ names << item.name
19
+ end
20
+
21
+ assert_equal %w[Alice Bob], names
22
+ end
23
+
24
+ def test_map_is_available_from_enumerable
25
+ collection = build_collection
26
+
27
+ assert_equal %w[Alice Bob], collection.map(&:name)
28
+ end
29
+
30
+ def test_collection_responds_to_select
31
+ collection = build_collection
32
+
33
+ assert collection.respond_to?(:select)
34
+ end
35
+
36
+ def test_count_without_block_returns_metadata_count
37
+ collection = Calendlyr::Collection.new(
38
+ data: [Calendlyr::Object.new(name: "Alice")],
39
+ count: 10,
40
+ next_page: nil,
41
+ client: client
42
+ )
43
+
44
+ assert_equal 10, collection.count
45
+ end
46
+
47
+ def test_count_with_block_uses_enumerable_count
48
+ collection = build_collection
49
+
50
+ assert_equal(1, collection.count { |item| item.name == "Alice" })
51
+ end
52
+
53
+ def test_count_with_argument_uses_enumerable_count
54
+ alice = Calendlyr::Object.new(name: "Alice")
55
+ collection = Calendlyr::Collection.new(
56
+ data: [alice, Calendlyr::Object.new(name: "Bob")],
57
+ count: 10,
58
+ next_page: nil,
59
+ client: client
60
+ )
61
+
62
+ assert_equal 1, collection.count(alice)
63
+ end
64
+ end
@@ -15,7 +15,38 @@ class ObjectTest < Minitest::Test
15
15
 
16
16
  def test_array
17
17
  object = Calendlyr::Object.new(foo: [{bar: :baz}], client: nil)
18
- assert_equal OpenStruct, object.foo.first.class
18
+ assert_equal Calendlyr::Object, object.foo.first.class
19
19
  assert_equal :baz, object.foo.first.bar
20
20
  end
21
+
22
+ def test_uuid_extraction_from_string_uri
23
+ object = Calendlyr::Object.new("uri" => "https://api.calendly.com/users/ABC123")
24
+
25
+ assert_equal "ABC123", object.uuid
26
+ end
27
+
28
+ def test_missing_attribute_returns_nil
29
+ object = Calendlyr::Object.new(name: "test")
30
+
31
+ assert_nil object.nonexistent
32
+ end
33
+
34
+ def test_respond_to_existing_attribute
35
+ object = Calendlyr::Object.new(name: "test")
36
+
37
+ assert object.respond_to?(:name)
38
+ end
39
+
40
+ def test_to_h_returns_deep_hash
41
+ object = Calendlyr::Object.new("profile" => {"age" => 30, "items" => [{"id" => 1}]})
42
+
43
+ assert_equal({profile: {age: 30, items: [{id: 1}]}, uuid: nil}, object.to_h)
44
+ end
45
+
46
+ def test_equals_other_object_with_same_attributes
47
+ first = Calendlyr::Object.new(name: "test")
48
+ second = Calendlyr::Object.new(name: "test")
49
+
50
+ assert_equal first, second
51
+ end
21
52
  end
@@ -7,13 +7,6 @@ class EventTypeObjectTest < Minitest::Test
7
7
  json = JSON.parse(fixture_file("objects/event_type")).merge(client: client)
8
8
  @event_type = Calendlyr::EventType.new(json)
9
9
 
10
- event_type_uri = "https://api.calendly.com/event_types/AAAAAAAAAAAAAAAA"
11
- @start_time = "2020-01-02T20:00:00.000000Z"
12
- @end_time = "2020-01-07T24:00:00.000000Z"
13
-
14
- response = {body: fixture_file("event_type_available_times/list"), status: 200}
15
- stub(path: "event_type_available_times?event_type=#{event_type_uri}&start_time=#{@start_time}&end_time=#{@end_time}", response: response)
16
-
17
10
  event_type_uri = "https://api.calendly.com/event_types/AAAAAAAAAAAAAAAA"
18
11
  response = {body: fixture_file("shares/create"), status: 201}
19
12
  stub(method: :post, path: "shares", body: {event_type: event_type_uri}, response: response)
@@ -32,12 +25,4 @@ class EventTypeObjectTest < Minitest::Test
32
25
  assert_instance_of Calendlyr::Share, share
33
26
  assert_equal 1, share.scheduling_links.size
34
27
  end
35
-
36
- def test_available_times
37
- available_times = @event_type.available_times(start_time: @start_time, end_time: @end_time)
38
-
39
- assert 3, available_times.data.size
40
- assert "available", available_times.data.first.status
41
- assert_instance_of Calendlyr::EventTypes::AvailableTime, available_times.data.first
42
- end
43
28
  end