Skip to content

Commit

Permalink
Merge pull request #58 from koshilife/feature/#57-support-list-event-…
Browse files Browse the repository at this point in the history
…type-available-times

Support list event type available times
  • Loading branch information
koshilife committed Aug 3, 2022
2 parents 8182d7e + affd166 commit e5f3419
Show file tree
Hide file tree
Showing 13 changed files with 312 additions and 3 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# CHANGELOG

## 0.13.0 - 2022-08-03

- supported List Event Type Available Times API. (#57)
- changed were followings:
- Client
- (Add method) event_type_available_times
- EventType model
- (Add method) available_times

## 0.12.0 - 2022-07-16

- supported Routing Form APIs. (#55)
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,21 @@ me.scheduling_url
#
event_types = me.event_types
# => [#<Calendly::EventType uuid="ET001", name="15 Minute Meeting", type="StandardEventType", slug="15min", active=true, kind="solo", scheduling_url="https://calendly.com/foobar/15min", ..>, #<Calendly::EventType uuid="ET002", name="30 Minute Meeting", type="StandardEventType", slug="30min", active=true, kind="solo", scheduling_url="https://calendly.com/foobar/30min", ..>]
event_types.first.scheduling_url

event_type = event_types.first
event_type.scheduling_url
# => "https://calendly.com/foobar/15min"

#
# get available times for the event type
#
available_times = event_type.available_times
available_times.map(&:start_time)
# => [2022-08-04 01:00:00 UTC, 2022-08-04 01:15:00 UTC, 2022-08-04 01:30:00 UTC]

# you can specify the date range
event_type.available_times(start_time: "2022-08-04T10:30:00Z", end_time: "2022-08-05T10:30:00Z")

#
# get scheduled events
#
Expand Down
1 change: 1 addition & 0 deletions calendly.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'faraday', '>= 1.0.0', '< 3.0.0'
spec.add_runtime_dependency 'oauth2', '~> 1.4', '>= 1.4.4'

spec.add_development_dependency 'activesupport'
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'codecov'
spec.add_development_dependency 'minitest'
Expand Down
30 changes: 30 additions & 0 deletions lib/calendly/client.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require 'time'
require 'oauth2'
require 'calendly/loggable'

Expand Down Expand Up @@ -159,6 +160,35 @@ def event_types_by_user(user_uri, options: nil)
[ev_types, next_page_params(body)]
end

#
# Returns a list of available times for an event type within a specified date range.
# Date range can be no greater than 1 week (7 days).
#
# @param [String] event_type_uri The uri associated with the event type.
# @param [String] start_time Start time of the requested availability range.
# @param [String] end_time End time of the requested availability range.
# @return [Array<Calendly::EventTypeAvailableTime>] The set of available times for the event type matching the criteria.
# @raise [Calendly::Error] if the event_type_uri arg is empty.
# @raise [Calendly::ApiError] if the api returns error code.
# @since 0.13.0
def event_type_available_times(event_type_uri, start_time: nil, end_time: nil)
check_not_empty event_type_uri, 'event_type_uri'

start_time_buffer = 60 # For working around an invalid request which be caused by specifying a past time
max_date_range = 60 * 60 * 24 * 7 # 7 days

# If start_time is undefined, set it to now.
start_time ||= (Time.now + start_time_buffer).utc.iso8601
# If end_time is undefined, set it to in the max date range from start_time.
end_time ||= (Time.parse(start_time) + max_date_range).utc.iso8601

params = {event_type: event_type_uri, start_time: start_time, end_time: end_time}
body = request :get, 'event_type_available_times', params: params

items = body[:collection] || []
items.map { |item| EventTypeAvailableTime.new item, self }
end

#
# Returns a single Event by its URI.
#
Expand Down
14 changes: 14 additions & 0 deletions lib/calendly/models/event_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ def fetch
client.event_type uuid
end

#
# Returns a list of available times for an event type within a specified date range.
# Date range can be no greater than 1 week (7 days).
#
# @param [String] start_time Start time of the requested availability range.
# @param [String] end_time End time of the requested availability range.
# @return [Array<Calendly::EventTypeAvailableTime>] The set of available times for the event type matching the criteria.
# @raise [Calendly::Error] if the uri is empty.
# @raise [Calendly::ApiError] if the api returns error code.
# @since 0.13.0
def available_times(start_time: nil, end_time: nil)
client.event_type_available_times uri, start_time: start_time, end_time: end_time
end

#
# Create an associated scheduling link.
#
Expand Down
33 changes: 33 additions & 0 deletions lib/calendly/models/event_type_available_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Calendly
# An available meeting time slot for the given event type.
class EventTypeAvailableTime
include ModelUtils
TIME_FIELDS = %i[start_time].freeze

# Indicates that the open time slot is "available".
# @return [String]
attr_accessor :status

# Total remaining invitees for this available time.
# For Group Event Type, more than one invitee can book in this available time.
# For all other Event Types, only one invitee can book in this available time.
# @return [Integer]
attr_accessor :invitees_remaining

# The moment the event was scheduled to start in UTC time.
# @return [Time]
attr_accessor :start_time

# The URL of the user’s scheduling site where invitees book this event type.
# @return [Time]
attr_accessor :scheduling_url

private

def inspect_attributes
super + %i[start_time invitees_remaining]
end
end
end
2 changes: 1 addition & 1 deletion lib/calendly/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Calendly
VERSION = '0.12.0'
VERSION = '0.13.0'
end
27 changes: 27 additions & 0 deletions test/assert_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,33 @@ def assert_event_type201(ev_type)
assert_equal [], ev_type.custom_questions
end

def assert_available_times001(available_time)
assert available_time.is_a? Calendly::EventTypeAvailableTime
assert available_time.client.is_a? Calendly::Client
assert_equal 'available', available_time.status
assert_equal 1, available_time.invitees_remaining
assert_equal Time.parse('2022-08-04T01:15:00Z').to_i, available_time.start_time.to_i
assert_equal 'https://calendly.com/foobar/15min/2022-08-04T01:15:00Z', available_time.scheduling_url
end

def assert_available_times002(available_time)
assert available_time.is_a? Calendly::EventTypeAvailableTime
assert available_time.client.is_a? Calendly::Client
assert_equal 'available', available_time.status
assert_equal 2, available_time.invitees_remaining
assert_equal Time.parse('2022-08-05T05:30:00Z').to_i, available_time.start_time.to_i
assert_equal 'https://calendly.com/foobar/15min/2022-08-05T05:30:00Z', available_time.scheduling_url
end

def assert_available_times003(available_time)
assert available_time.is_a? Calendly::EventTypeAvailableTime
assert available_time.client.is_a? Calendly::Client
assert_equal 'available', available_time.status
assert_equal 3, available_time.invitees_remaining
assert_equal Time.parse('2022-08-10T01:15:00Z').to_i, available_time.start_time.to_i
assert_equal 'https://calendly.com/foobar/15min/2022-08-10T01:15:00Z', available_time.scheduling_url
end

def assert_event001(ev)
assert ev.client.is_a? Calendly::Client
assert_equal 'EV001', ev.id
Expand Down
81 changes: 81 additions & 0 deletions test/client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,87 @@ def test_that_it_raises_an_argument_error_on_event_types_by_user
assert_required_error proc_arg_is_empty, 'user_uri'
end

#
# test for event_type_available_times
#

def test_that_it_returns_available_times_by_specifying_even_type
now = Time.parse('2022-08-03T01:50:10Z')
travel_to(now)

event_type_uri = "#{HOST}/event_types/ET001"
expected_start_time = '2022-08-03T01:51:10Z' # now + 1 minute
expected_end_time = '2022-08-10T01:51:10Z' # start_time + 7 days
params = {event_type: event_type_uri, start_time: expected_start_time, end_time: expected_end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @client.event_type_available_times event_type_uri
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_returns_available_times_by_specifying_even_type_and_start_time
event_type_uri = "#{HOST}/event_types/ET001"
start_time = Time.parse('2022-08-04T09:00:00Z').utc.iso8601
expected_end_time = '2022-08-11T09:00:00Z' # start_time + 7 days
params = {event_type: event_type_uri, start_time: start_time, end_time: expected_end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @client.event_type_available_times event_type_uri, start_time: start_time
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_returns_available_times_by_specifying_even_type_and_end_time
now = Time.parse('2022-08-03T01:50:10Z')
travel_to(now)

event_type_uri = "#{HOST}/event_types/ET001"
expected_start_time = '2022-08-03T01:51:10Z' # now + 1 minute
end_time = Time.parse('2022-08-05T09:00:00Z').utc.iso8601
params = {event_type: event_type_uri, start_time: expected_start_time, end_time: end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @client.event_type_available_times event_type_uri, end_time: end_time
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_returns_available_times_by_specifying_even_type_and_start_time_and_end_time
event_type_uri = 'https://api.calendly.com/event_type_available_times'
start_time = Time.parse('2022-08-04T09:00:00Z').utc.iso8601
end_time = Time.parse('2022-08-05T09:00:00Z').utc.iso8601
params = {event_type: event_type_uri, start_time: start_time, end_time: end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @client.event_type_available_times event_type_uri, start_time: start_time, end_time: end_time
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_raises_an_argument_error_on_event_type_available_times
proc_arg_is_empty = proc do
@client.event_type_available_times ''
end
assert_required_error proc_arg_is_empty, 'event_type_uri'
end

#
# test for scheduled_event
#
Expand Down
12 changes: 12 additions & 0 deletions test/models/event_type_available_type_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

require 'test_helper'

module Calendly
# test for Calendly::EventTypeAvailableTime
class EventTypeAvailableTimeTest < BaseTest
def test_it_returns_inspect_string
assert EventTypeAvailableTime.new.inspect.start_with? '#<Calendly::EventTypeAvailableTime:'
end
end
end
66 changes: 66 additions & 0 deletions test/models/event_type_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,72 @@ def test_that_it_returns_an_associated_invitee
assert_event_type001 @event_type.fetch
end

def test_that_it_returns_available_times
now = Time.parse('2022-08-03T01:50:10Z')
travel_to(now)

expected_start_time = '2022-08-03T01:51:10Z' # now + 1 minute
expected_end_time = '2022-08-10T01:51:10Z' # start_time + 7 days
params = {event_type: @et_uri, start_time: expected_start_time, end_time: expected_end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @event_type.available_times
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_returns_available_times_by_specifying_start_time
start_time = Time.parse('2022-08-04T09:00:00Z').utc.iso8601
expected_end_time = '2022-08-11T09:00:00Z' # start_time + 7 days
params = {event_type: @et_uri, start_time: start_time, end_time: expected_end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @event_type.available_times start_time: start_time
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_returns_available_times_by_specifying_end_time
now = Time.parse('2022-08-03T01:50:10Z')
travel_to(now)

expected_start_time = '2022-08-03T01:51:10Z' # now + 1 minute
end_time = Time.parse('2022-08-05T09:00:00Z').utc.iso8601
params = {event_type: @et_uri, start_time: expected_start_time, end_time: end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @event_type.available_times end_time: end_time
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_returns_available_times_by_specifying_start_time_and_end_time
start_time = Time.parse('2022-08-04T09:00:00Z').utc.iso8601
end_time = Time.parse('2022-08-05T09:00:00Z').utc.iso8601
params = {event_type: @et_uri, start_time: start_time, end_time: end_time}

url = "#{HOST}/event_type_available_times?#{URI.encode_www_form(params)}"
res_body = load_test_data 'event_type_available_times_001.json'
add_stub_request :get, url, res_body: res_body

available_times = @event_type.available_times start_time: start_time, end_time: end_time
assert_available_times001 available_times[0]
assert_available_times002 available_times[1]
assert_available_times003 available_times[2]
end

def test_that_it_creates_schedule_link
req_body = {
max_event_count: 3,
Expand Down
4 changes: 3 additions & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
require 'codecov'
SimpleCov.formatter = SimpleCov::Formatter::Codecov
end
require 'active_support'
require 'active_support/core_ext'
require 'minitest/autorun'
require 'webmock/minitest'
require 'calendly'
Expand All @@ -17,7 +19,7 @@
class MyLogger < Logger; end

module Calendly
class BaseTest < Minitest::Test
class BaseTest < ActiveSupport::TestCase
include AssertHelper

HOST = Calendly::Client::API_HOST
Expand Down

0 comments on commit e5f3419

Please sign in to comment.