Skip to content

Instantly share code, notes, and snippets.

@tit
Last active Sep 1, 2018
Embed
What would you like to do?
CallTools API Client
# http-cookie need for Max-Age
# @see https://github.com/nahi/httpclient/issues/242#issuecomment-69020815
require 'http-cookie'
require 'httpclient'
require 'json'
require 'symbolize_keys_recursively'
# CallTools
module CallTools
# CallTools API Client
#
# @author Sergey Blohin (sblohin@yandex.ru)
#
# @see https://calltools.ru/
# @see https://calltools.ru/guide_api/
# @see https://calltools.ru/lk/audioclips/all-speakers/
# @see https://calltools.ru/lk/pages/synth-valid-text/
# @see https://calltools.ru/lk/phones/all/
# @see https://calltools.ru/lk/users/profile/
#
# @example
# api_public_key = 'a1d7352426832e77c2a9f55e01106f1a'
# client = CallTools::Client.new api_public_key
#
# # add phone number to campaign
# # and return call_id
# campaign_id = 1_234_567_890
# phone_number = '+79185274526'
# call = client.add_call campaign_id, phone_number
# call_id = call[:call_id]
#
# # get call status by call_id
# call_result = client.call_result_by_call_id call_id
# call_status = call_result[:status]
#
# # remove phone number form campaign
# # if call status is `in_process`
# if call_status == 'is_process'
# client.remove_call_by_call_id campaign_id, phone_number
# end
class Client
# API Version
API_VERSION = 'v1'.freeze
public_constant :API_VERSION
# Base URL
BASE_URL = "https://calltools.ru/lk/cabapi_external/api/#{API_VERSION}".freeze
private_constant :BASE_URL
# HTTP STATUS OK
HTTP_STATUS_OK = 200
private_constant :HTTP_STATUS_OK
# Path Audio Upload
PATH_AUDIO_UPLOAD = '/audio/upload/'.freeze
private_constant :PATH_AUDIO_UPLOAD
# Path Def Codes By Phone
PATH_DEF_CODES_BY_PHONE = '/def_codes/by_phone/'.freeze
private_constant :PATH_DEF_CODES_BY_PHONE
# Path Phones Call
PATH_PHONES_CALL = '/phones/call/'.freeze
private_constant :PATH_PHONES_CALL
# Path Phones Call By ID
PATH_PHONES_CALL_BY_ID = '/phones/call_by_id/'.freeze
private_constant :PATH_PHONES_CALL_BY_ID
# Path Phones Calls By Phone
PATH_PHONES_CALLS_BY_PHONE = '/phones/calls_by_phone/'.freeze
private_constant :PATH_PHONES_CALLS_BY_PHONE
# Path Phones Remove Call
PATH_PHONES_REMOVE_CALL = '/phones/remove_call/'.freeze
private_constant :PATH_PHONES_REMOVE_CALL
# Path Users Balance
PATH_USERS_BALANCE = '/users/balance/'.freeze
private_constant :PATH_USERS_BALANCE
# @param [String] api_public_key
# @example
# .new(a1d7352426832e77c2a9f55e01106f1a)
def initialize(api_public_key)
@api_public_key = api_public_key
end
# Add Call To Campaign
#
# @param [Integer] campaign_id
# @param [String] phone_number phone_number in international format +79185274526
# @return [Hash] :balance, :call_id, :created, :phone
# @example
# .add_call(1234567890, '+79185274526')
def add_call(campaign_id, phone_number)
parameters = {
public_key: @api_public_key,
campaign_id: campaign_id,
phone: phone_number
}
post PATH_PHONES_CALL, parameters
end
# Add Call With Clip Generation
#
# @param [Integer] campaign_id
# @param [String] phone_number phone_number in international format +79185274526
# @param [String] text text generated by voice clip, you can also use special markup
# @param [String] speaker speaker voice, if not specified, use default from campaign settings
# @return [Hash] :call_id, :phone, :balance, :audioclip_id, :created, :callerid
# @example
# .add_call_with_clip_generation(1234567890, '+79185274526', 'Hello, Kitty', 'Tatyana')
def add_call_with_clip_generation(campaign_id, phone_number, text, speaker = nil)
parameters = {
public_key: @api_public_key,
campaign_id: campaign_id,
phone: phone_number,
text: text,
speaker: speaker
}
post PATH_PHONES_CALL, parameters
end
# Result by phone number
#
# @param [Integer] campaign_id
# @param [String] phone_number phone_number in international format +79185274526
# @param [Hash] date format is YYYY-MM-DD HH:MM:SS
# @option data [String] from_date_created
# @option data [String] from_date_created
# @option data [String] to_date_created
# @option data [String] from_date_updated
# @option data [String] to_date_updated
# @return [Array <Hash>]
# @example
# .calls_result_by_phone(1234567890, '+79185274526')
def calls_result_by_phone(campaign_id, phone_number, date = {})
parameters = {
public_key: @api_public_key,
campaign_id: campaign_id,
phone: phone_number,
from_created_date: date[:from_date_created],
to_created_date: date[:to_date_created],
from_updated_date: date[:from_date_updated],
to_updated_date: date[:to_date_updated]
}
get PATH_PHONES_CALLS_BY_PHONE, parameters
end
# Result By `call_id`
#
# @see #add_call
# @see #add_call_with_clip_generation
# @param [Integer] call_id
# @return [Hash]
# @example
# .call_result_by_call_id(1234567890)
def call_result_by_call_id(call_id)
parameters = {
public_key: @api_public_key,
call_id: call_id
}
response = get PATH_PHONES_CALL_BY_ID, parameters
response.first
end
# Remove Call By `phone_number`
#
# @param [Integer] campaign_id
# @param [String] phone_number phone_number in international format +79185274526
# @return [Hash] :call_id, :completed, :phone
# @example
# .remove_call_by_phone_number(1234567890, '+79185274526')
def remove_call_by_phone_number(campaign_id, phone_number)
parameters = {
public_key: @api_public_key,
campaign_id: campaign_id,
phone: phone_number
}
post PATH_PHONES_REMOVE_CALL, parameters
end
# Remove Call By `call_id`
#
# @see #add_call
# @see #add_call_with_clip_generation
# @param [Integer] campaign_id
# @param [Integer] call_id
# @return [Hash] :call_id, :completed, :phone
# @example
# .remove_call_by_call_id(1234567890, 1234567890)
def remove_call_by_call_id(campaign_id, call_id)
parameters = {
public_key: @api_public_key,
campaign_id: campaign_id,
call_id: call_id
}
post PATH_PHONES_REMOVE_CALL, parameters
end
# Get User Balance
#
# @param [TrueClass, FalseClass] accuracy
# @return [Integer, Float]
# @example
# .balance(true) #=> 42.666
# .balance(false) #=> 42
def balance(accuracy = false)
parameters = { public_key: @api_public_key }
response = get PATH_USERS_BALANCE, parameters
balance = response[:balance]
accuracy ? balance.to_f : balance.to_i
end
# Upload Audiofile
#
# @param [String] clip_name base filename or clip title
# @param [String] clip_filename full path to filename
# @param [String] speaker speaker name
# @param [String] text clip description
# @return [Hash] :length, :audioclip_id, :path
# @example
# .upload_audio('welcome_to_hell', '/path/to/filename.mp3', 'Maria', 'Welcome To Hell')
def upload_audio(clip_name, clip_filename, speaker = nil, text = nil)
parameters = {
public_key: @api_public_key,
clip_name: clip_name,
clip_file: File.open(clip_filename),
speaker: speaker,
text: text
}
post PATH_AUDIO_UPLOAD, parameters
end
# Definition Of The Region And Time Zone (Timezone) by `phone_number`
#
# @param [String] phone_number phone_number in international format +79185274526
# @return [Hash]
# @example
# .time_zone_by_phone_number('+79185274526')
def time_zone_by_phone_number(phone_number)
parameters = { phone: phone_number }
get PATH_DEF_CODES_BY_PHONE, parameters
end
private
# Call GET Request
#
# @param [String] path
# @param [Hash, NilClass] parameters
# @return [Hash]
# @example
# .get('/method/name/', {foo: 42, bar: 'bar'})
def get(path, parameters = nil)
request :get, path, parameters
end
# Call POST Request
#
# @param [String] path
# @param [Hash, NilClass] parameters
# @return [Hash]
# @example
# .post('/method/name/', {foo: 42, bar: 'bar'})
def post(path, parameters = nil)
request :post, path, parameters
end
# Call Request
#
# @param [Symbol] method
# @param [String] path
# @param [Hash] parameters
# @return [Hash]
# @example
# .request(:get, '/method/name/', {foo: 42, bar: 'bar'})
def request(method, path, parameters)
url = "#{BASE_URL}#{path}"
case method
when :get
response_validator HTTPClient.get url, parameters
when :post
response_validator HTTPClient.post url, parameters
else
raise method.to_s
end
end
# Check http.code is HTTP_STATUS_OK and http.body is JSON
#
# @param [HTTP::Message] response
# @return [Hash] http.body as JSON
# @example
# .response_validator(HTTPClient.get('http://httpbin.org/get'))
def response_validator(response)
status = response.status
source_body = response.body
# raise code if http.code is not HTTP_STATUS_OK
raise status.to_s unless status == HTTP_STATUS_OK
# raise source http.body if http.body is not JSON
begin
body = JSON.parse source_body
# { 'foo' => 42 } => { foo: 42 }
body.symbolize_keys_recursively!
rescue JSON::ParserError
raise source_body
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment