telapi 1.0.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.
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +162 -0
- data/Rakefile +1 -0
- data/lib/telapi.rb +24 -0
- data/lib/telapi/account.rb +14 -0
- data/lib/telapi/application.rb +88 -0
- data/lib/telapi/available_phone_number.rb +24 -0
- data/lib/telapi/call.rb +214 -0
- data/lib/telapi/caller_id.rb +16 -0
- data/lib/telapi/carrier.rb +16 -0
- data/lib/telapi/conference.rb +206 -0
- data/lib/telapi/configuration.rb +40 -0
- data/lib/telapi/error.rb +22 -0
- data/lib/telapi/fraud.rb +79 -0
- data/lib/telapi/inbound_xml.rb +36 -0
- data/lib/telapi/incoming_phone_number.rb +86 -0
- data/lib/telapi/message.rb +47 -0
- data/lib/telapi/network.rb +50 -0
- data/lib/telapi/notification.rb +29 -0
- data/lib/telapi/recording.rb +69 -0
- data/lib/telapi/resource.rb +18 -0
- data/lib/telapi/resource_collection.rb +38 -0
- data/lib/telapi/transcription.rb +44 -0
- data/lib/telapi/version.rb +3 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/telapi_helpers.rb +38 -0
- data/spec/telapi/account_spec.rb +17 -0
- data/spec/telapi/application_spec.rb +69 -0
- data/spec/telapi/available_phone_number_spec.rb +27 -0
- data/spec/telapi/call_spec.rb +173 -0
- data/spec/telapi/caller_id_spec.rb +17 -0
- data/spec/telapi/carrier_spec.rb +17 -0
- data/spec/telapi/conference_spec.rb +174 -0
- data/spec/telapi/configuration_spec.rb +38 -0
- data/spec/telapi/error_spec.rb +32 -0
- data/spec/telapi/fraud_spec.rb +55 -0
- data/spec/telapi/inbound_xml_spec.rb +49 -0
- data/spec/telapi/incoming_phone_number_spec.rb +69 -0
- data/spec/telapi/message_spec.rb +41 -0
- data/spec/telapi/network_spec.rb +80 -0
- data/spec/telapi/notification_spec.rb +34 -0
- data/spec/telapi/recording_spec.rb +72 -0
- data/spec/telapi/resource_collection_spec.rb +64 -0
- data/spec/telapi/resource_spec.rb +25 -0
- data/spec/telapi/transcription_spec.rb +41 -0
- data/telapi-ruby.gemspec +32 -0
- metadata +227 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module Telapi
|
2
|
+
# Wraps TelAPI SMS Message functionality
|
3
|
+
class Message < Resource
|
4
|
+
class << self
|
5
|
+
MAX_BODY_LENGTH = 160
|
6
|
+
|
7
|
+
# Returns a resource collection containing Telapi::Message objects
|
8
|
+
# See http://www.telapi.com/docs/api/rest/sms/list/
|
9
|
+
#
|
10
|
+
# Optional params is a hash containing:
|
11
|
+
# +To+:: mobile phone number
|
12
|
+
# +From+:: TelAPI or mobile phone number
|
13
|
+
# +DateSent+:: date in the following format: YYYY-MM-DD
|
14
|
+
# +Page+:: integer greater than 0
|
15
|
+
# +PageSize+:: integer greater than 0
|
16
|
+
def list(optional_params = {})
|
17
|
+
response = Network.get(['SMS', 'Messages'], optional_params)
|
18
|
+
ResourceCollection.new(response, 'sms_messages', self)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a specific Telapi::Message object given its id
|
22
|
+
# See http://www.telapi.com/docs/api/rest/sms/view/
|
23
|
+
def get(id)
|
24
|
+
response = Network.get(['SMS', 'Messages', id])
|
25
|
+
Message.new(response)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Creates an SMS Message, returning a Telapi::Message object
|
29
|
+
# See http://www.telapi.com/docs/api/rest/sms/send/
|
30
|
+
#
|
31
|
+
# Required params:
|
32
|
+
# +to+:: mobile phone number
|
33
|
+
# +from+:: TelAPI or mobile phone number
|
34
|
+
# +body+:: plain text up to 160 characters in length
|
35
|
+
#
|
36
|
+
# Optional params:
|
37
|
+
# +status_callback+:: valid URL
|
38
|
+
def create(to, from, body, status_callback=nil)
|
39
|
+
raise RangeError, "Body must be between 0 and #{MAX_BODY_LENGTH} characters" if body.length>MAX_BODY_LENGTH || body.length==0
|
40
|
+
opts = { :To => to, :From => from, :Body => body, :StatusCallback => status_callback }
|
41
|
+
response = Network.post(['SMS', 'Messages'], opts)
|
42
|
+
Message.new(response)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Telapi
|
4
|
+
# Internal object for network operations; wraps HTTParty
|
5
|
+
module Network #:nodoc:
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def get(path_components=[], query=nil)
|
10
|
+
options = default_options.merge(:query => query)
|
11
|
+
handle_response(HTTParty.get api_uri(path_components), options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def post(path_components=[], body)
|
15
|
+
options = default_options.merge(:body => body)
|
16
|
+
handle_response(HTTParty.post api_uri(path_components), options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(path_components=[])
|
20
|
+
handle_response(HTTParty.delete api_uri(path_components), default_options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# path_components is an array of uri fragments, e.g ['Calls', '1234abc']
|
24
|
+
def api_uri(path_components=[])
|
25
|
+
[ Telapi.config.base_uri, 'Accounts', Telapi.config.account_sid, path_components ].flatten.join('/') + response_format
|
26
|
+
end
|
27
|
+
|
28
|
+
def response_format
|
29
|
+
@api_format ||= '.json'
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_options
|
33
|
+
{
|
34
|
+
:basic_auth => {
|
35
|
+
:username => (Telapi.config.account_sid || raise(InvalidConfiguration, 'account_sid')),
|
36
|
+
:password => (Telapi.config.auth_token || raise(InvalidConfiguration, 'auth_token'))
|
37
|
+
},
|
38
|
+
:ssl_ca_path => Telapi.config.ssl_ca_path
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def handle_response(response)
|
45
|
+
raise Telapi::ApiError.new(response.parsed_response) unless response.success?
|
46
|
+
response
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Telapi
|
2
|
+
# Wraps TelAPI Notification functionality
|
3
|
+
class Notification < Resource
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Returns a resource collection containing Telapi::Notification objects
|
7
|
+
# See http://www.telapi.com/docs/api/rest/notifications/list/
|
8
|
+
#
|
9
|
+
# Also, notifications can be scoped to a call, see Telapi::Call::notifications
|
10
|
+
#
|
11
|
+
# Optional params is a hash containing:
|
12
|
+
# +Log+:: 0 (error), 1 (warning), or 2 (info)
|
13
|
+
# +Page+:: integer greater than 0
|
14
|
+
# +PageSize+:: integer greater than 0
|
15
|
+
def list(optional_params = {})
|
16
|
+
response = Network.get(['Notifications'], optional_params)
|
17
|
+
ResourceCollection.new(response, 'notifications', self)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a Telapi::Notification object given its id
|
21
|
+
# See http://www.telapi.com/docs/api/rest/notifications/view/
|
22
|
+
def get(id)
|
23
|
+
response = Network.get(['Notifications', id])
|
24
|
+
Notification.new(response)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Telapi
|
2
|
+
# Wraps TelAPI Recording functionality
|
3
|
+
class Recording < Resource
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Returns a resource collection containing Telapi::Recording objects
|
7
|
+
# See http://www.telapi.com/docs/api/rest/recordings/list/
|
8
|
+
#
|
9
|
+
# Also, recordings can be scoped to a call, see Telapi::Call::recordings
|
10
|
+
#
|
11
|
+
# Optional params is a hash containing:
|
12
|
+
# +DateCreated+:: date in the following format: YYYY-MM-DD
|
13
|
+
# +Page+:: integer greater than 0
|
14
|
+
# +PageSize+:: integer greater than 0
|
15
|
+
def list(optional_params = {})
|
16
|
+
response = Network.get(['Recordings'], optional_params)
|
17
|
+
ResourceCollection.new(response, 'recordings', self)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a Telapi::Recording object given its id
|
21
|
+
# See http://www.telapi.com/docs/api/rest/recordings/view/
|
22
|
+
def get(id)
|
23
|
+
response = Network.get(['Recordings', id])
|
24
|
+
Recording.new(response)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Transcribes a recording and returns a Telapi::Transcription object
|
28
|
+
# See http://www.telapi.com/docs/api/rest/transcriptions/transcribe-recording/
|
29
|
+
#
|
30
|
+
# Required params:
|
31
|
+
# +id+:: recording id
|
32
|
+
#
|
33
|
+
# Optional params is a hash containing:
|
34
|
+
# +TranscribeCallback+:: valid URL
|
35
|
+
# +CallbackMethod+:: (POST) or GET
|
36
|
+
# +Quality+:: (auto), silver, gold, or platinum
|
37
|
+
def transcribe(id, optional_params = {})
|
38
|
+
response = Network.post(['Recordings', id, 'Transcriptions'], optional_params)
|
39
|
+
Transcription.new(response)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns a resource collection containing Telapi::Transcription objects
|
43
|
+
# See http://www.telapi.com/docs/api/rest/transcriptions/list/
|
44
|
+
#
|
45
|
+
# Required params:
|
46
|
+
# +id+:: recording id
|
47
|
+
#
|
48
|
+
# Optional params is a hash containing:
|
49
|
+
# +Page+:: integer greater than 0
|
50
|
+
# +PageSize+:: integer greater than 0
|
51
|
+
def transcriptions(id, optional_params = {})
|
52
|
+
response = Network.get(['Recordings', id, 'Transcriptions'], optional_params)
|
53
|
+
ResourceCollection.new(response, 'transcriptions', Transcription)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# See ::transcribe
|
59
|
+
def transcribe(optional_params = {})
|
60
|
+
self.class.transcribe(self.sid, optional_params)
|
61
|
+
end
|
62
|
+
|
63
|
+
# See ::transcriptions
|
64
|
+
def transcriptions(optional_params = {})
|
65
|
+
self.class.transcriptions(self.sid, optional_params)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'recursive_open_struct'
|
2
|
+
|
3
|
+
module Telapi
|
4
|
+
# Base class provides basic behavior for Telapi domain objects
|
5
|
+
# You don't typically instantiate this class directly
|
6
|
+
class Resource < RecursiveOpenStruct
|
7
|
+
include Network
|
8
|
+
|
9
|
+
def initialize(attributes={})
|
10
|
+
super
|
11
|
+
delete_field('subresource_uris') if respond_to?(:subresource_uris)
|
12
|
+
end
|
13
|
+
|
14
|
+
def attributes
|
15
|
+
marshal_dump
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Telapi
|
4
|
+
# This class wraps Resource objects and provides Enumerable functionality.
|
5
|
+
#
|
6
|
+
# Note that TelAPI collections are automatically separated into pages of results,
|
7
|
+
# see http://www.telapi.com/docs/api/rest/overview/response/.
|
8
|
+
#
|
9
|
+
# Currently this container class does not automatically handle the retrieving of
|
10
|
+
# a previous/next page of results. However, all of the Resource classes that provide
|
11
|
+
# a +list+ method allow you to specify the current page and size.
|
12
|
+
class ResourceCollection
|
13
|
+
include Enumerable
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
attr_reader :items, :page, :num_pages, :page_size, :total, :start, :end
|
17
|
+
|
18
|
+
def initialize(attributes, collection_node_name, resource_type)
|
19
|
+
@page = attributes['page']
|
20
|
+
@num_pages = attributes['num_pages']
|
21
|
+
@page_size = attributes['page_size']
|
22
|
+
@total = attributes['total']
|
23
|
+
@start = attributes['start']
|
24
|
+
@end = attributes['end']
|
25
|
+
@items = []
|
26
|
+
|
27
|
+
attributes[collection_node_name].each do |item|
|
28
|
+
@items << resource_type.send(:new, item)
|
29
|
+
end if attributes[collection_node_name]
|
30
|
+
end
|
31
|
+
|
32
|
+
def_delegators :@items, :[], :empty?, :last
|
33
|
+
|
34
|
+
def each
|
35
|
+
@items.each { |i| yield i }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Telapi
|
2
|
+
# Wraps TelAPI Transcription functionality
|
3
|
+
class Transcription < Resource
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Returns a resource collection containing Telapi::Transcription objects
|
7
|
+
# See http://www.telapi.com/docs/api/rest/transcriptions/list/
|
8
|
+
#
|
9
|
+
# Also, Transcriptions can be scoped to a recording, see Telapi::Recording::transcriptions
|
10
|
+
#
|
11
|
+
# Optional params is a hash containing:
|
12
|
+
# +Page+:: integer greater than 0
|
13
|
+
# +PageSize+:: integer greater than 0
|
14
|
+
def list(optional_params = {})
|
15
|
+
response = Network.get(['Transcriptions'], optional_params)
|
16
|
+
ResourceCollection.new(response, 'transcriptions', self)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a Telapi::Transcription object given its id
|
20
|
+
# See http://www.telapi.com/docs/api/rest/transcriptions/view/
|
21
|
+
def get(id)
|
22
|
+
response = Network.get(['Transcriptions', id])
|
23
|
+
Transcription.new(response)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Transcribes any audio url, returning a Telapi::Transcription object
|
27
|
+
# See http://www.telapi.com/docs/api/rest/transcriptions/transcribe-audio-url/
|
28
|
+
#
|
29
|
+
# Required params:
|
30
|
+
# +audio_url+:: valid url
|
31
|
+
#
|
32
|
+
# Optional params is a hash containing:
|
33
|
+
# +TranscribeCallback+:: valid URL
|
34
|
+
# +CallbackMethod+:: (POST) or GET
|
35
|
+
# +Quality+:: (auto), silver, gold, or platinum
|
36
|
+
def transcribe_audio(audio_url, optional_params = {})
|
37
|
+
opts = { :AudioUrl => audio_url }.merge(optional_params)
|
38
|
+
response = Network.post(['Transcriptions'], opts)
|
39
|
+
Transcription.new(response)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
|
6
|
+
require 'fakeweb'
|
7
|
+
require 'support/telapi_helpers'
|
8
|
+
require 'telapi'
|
9
|
+
|
10
|
+
FakeWeb.allow_net_connect = false
|
11
|
+
|
12
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
+
config.run_all_when_everything_filtered = true
|
16
|
+
config.include TelapiHelpers
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module TelapiHelpers #:nodoc:
|
2
|
+
def klass
|
3
|
+
described_class
|
4
|
+
end
|
5
|
+
|
6
|
+
def stub_telapi_request(body = '{"sid": "a1b2c3"}', opts={})
|
7
|
+
options = {:body => body, :content_type => "application/json"}.merge(opts)
|
8
|
+
FakeWeb.register_uri(:any, /.*telapi.com.*/, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def stub_telapi_request_with_error_response
|
12
|
+
stub_telapi_request(
|
13
|
+
'{"status": 403,
|
14
|
+
"message": "Invalid credentials supplied",
|
15
|
+
"code": 10004,
|
16
|
+
"more_info": "http://www.telapi.com/docs/api/rest/overview/errors/10004"}',
|
17
|
+
:status => 400
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_account_sid_and_auth_token
|
22
|
+
Telapi.config do |config|
|
23
|
+
config.account_sid = 'a1b2c3'
|
24
|
+
config.auth_token = 'x5y6z7'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_config
|
29
|
+
Telapi.config do |config|
|
30
|
+
config.account_sid = nil
|
31
|
+
config.auth_token = nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def api_should_use(verb_symbol, response={})
|
36
|
+
Telapi::Network.should_receive(verb_symbol).and_return(response)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Telapi::Account do
|
4
|
+
before do
|
5
|
+
stub_telapi_request
|
6
|
+
set_account_sid_and_auth_token
|
7
|
+
end
|
8
|
+
|
9
|
+
it { should be_kind_of(Telapi::Resource) }
|
10
|
+
|
11
|
+
describe ".get" do
|
12
|
+
it "calls api via http get and returns an Account resource" do
|
13
|
+
api_should_use(:get)
|
14
|
+
klass.get.should be_a(klass)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Telapi::Application do
|
4
|
+
before do
|
5
|
+
stub_telapi_request
|
6
|
+
set_account_sid_and_auth_token
|
7
|
+
end
|
8
|
+
|
9
|
+
it { should be_kind_of(Telapi::Resource) }
|
10
|
+
|
11
|
+
describe ".list" do
|
12
|
+
before { stub_telapi_request('{ "applications": [] }') }
|
13
|
+
|
14
|
+
it "calls api via http get and returns a ResourceCollection" do
|
15
|
+
api_should_use(:get)
|
16
|
+
klass.list.should be_a(Telapi::ResourceCollection)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when Applications exist" do
|
20
|
+
before { stub_telapi_request('{ "applications": [{ "friendly_name": "ExampleApplication" }] }') }
|
21
|
+
|
22
|
+
it "has a collection of Application objects" do
|
23
|
+
klass.list.first.should be_a(klass)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".get" do
|
29
|
+
it "calls api via http get and returns an Application resource" do
|
30
|
+
api_should_use(:get)
|
31
|
+
klass.get('abc123').should be_a(klass)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".create" do
|
36
|
+
it "calls api via http post and returns an Application resource" do
|
37
|
+
api_should_use(:post)
|
38
|
+
klass.create('My App').should be_a(klass)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ".update" do
|
43
|
+
it "calls api via http post and returns an Application resource" do
|
44
|
+
api_should_use(:post)
|
45
|
+
klass.update('123', :FriendlyName => 'new name').should be_a(klass)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#update" do
|
50
|
+
it "proxies to Application.update" do
|
51
|
+
klass.should_receive(:update)
|
52
|
+
klass.get('abc123').update(:FriendlyName => 'another name')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".delete" do
|
57
|
+
it "calls api via http delete and returns an Application resource" do
|
58
|
+
api_should_use(:delete)
|
59
|
+
klass.delete('123').should be_a(klass)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#delete" do
|
64
|
+
it "proxies to Application.delete" do
|
65
|
+
klass.should_receive(:delete)
|
66
|
+
klass.get('abc123').delete
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|