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.
Files changed (49) hide show
  1. data/.gitignore +20 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +162 -0
  5. data/Rakefile +1 -0
  6. data/lib/telapi.rb +24 -0
  7. data/lib/telapi/account.rb +14 -0
  8. data/lib/telapi/application.rb +88 -0
  9. data/lib/telapi/available_phone_number.rb +24 -0
  10. data/lib/telapi/call.rb +214 -0
  11. data/lib/telapi/caller_id.rb +16 -0
  12. data/lib/telapi/carrier.rb +16 -0
  13. data/lib/telapi/conference.rb +206 -0
  14. data/lib/telapi/configuration.rb +40 -0
  15. data/lib/telapi/error.rb +22 -0
  16. data/lib/telapi/fraud.rb +79 -0
  17. data/lib/telapi/inbound_xml.rb +36 -0
  18. data/lib/telapi/incoming_phone_number.rb +86 -0
  19. data/lib/telapi/message.rb +47 -0
  20. data/lib/telapi/network.rb +50 -0
  21. data/lib/telapi/notification.rb +29 -0
  22. data/lib/telapi/recording.rb +69 -0
  23. data/lib/telapi/resource.rb +18 -0
  24. data/lib/telapi/resource_collection.rb +38 -0
  25. data/lib/telapi/transcription.rb +44 -0
  26. data/lib/telapi/version.rb +3 -0
  27. data/spec/spec_helper.rb +17 -0
  28. data/spec/support/telapi_helpers.rb +38 -0
  29. data/spec/telapi/account_spec.rb +17 -0
  30. data/spec/telapi/application_spec.rb +69 -0
  31. data/spec/telapi/available_phone_number_spec.rb +27 -0
  32. data/spec/telapi/call_spec.rb +173 -0
  33. data/spec/telapi/caller_id_spec.rb +17 -0
  34. data/spec/telapi/carrier_spec.rb +17 -0
  35. data/spec/telapi/conference_spec.rb +174 -0
  36. data/spec/telapi/configuration_spec.rb +38 -0
  37. data/spec/telapi/error_spec.rb +32 -0
  38. data/spec/telapi/fraud_spec.rb +55 -0
  39. data/spec/telapi/inbound_xml_spec.rb +49 -0
  40. data/spec/telapi/incoming_phone_number_spec.rb +69 -0
  41. data/spec/telapi/message_spec.rb +41 -0
  42. data/spec/telapi/network_spec.rb +80 -0
  43. data/spec/telapi/notification_spec.rb +34 -0
  44. data/spec/telapi/recording_spec.rb +72 -0
  45. data/spec/telapi/resource_collection_spec.rb +64 -0
  46. data/spec/telapi/resource_spec.rb +25 -0
  47. data/spec/telapi/transcription_spec.rb +41 -0
  48. data/telapi-ruby.gemspec +32 -0
  49. 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
@@ -0,0 +1,3 @@
1
+ module Telapi
2
+ VERSION = "1.0.0"
3
+ end
@@ -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