twilio_resource 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ Description
2
+ -----------
3
+
4
+ TwilioResource is a wrapper around the [Twilio API](http://www.twilio.com/docs/api/2008-08-01/rest/)
5
+ using Rails' ActiveResource. This allows you to treat Twilio objects
6
+ as if they're local ActiveRecord models:
7
+
8
+ phone = TwilioResource::LocalIncomingPhoneNumber.new(:url => 'http://www.example.com',
9
+ :area_code => '206',
10
+ :method => 'GET',
11
+ :friendly_name =g> "My First Phone Number",
12
+ :account_id => Twilio::Base.user)
13
+ phone.save
14
+
15
+
16
+ The wrapper doesn't support the entire Twilio API, but it should be
17
+ simple enough to add new functionality as needed by following the
18
+ models that are already built.
19
+
20
+ Supported Functionality
21
+ =======================
22
+ - Requesting, listing, and deleting new local and toll-free numbers
23
+ - Placing and listing calls made to a phone number
24
+
25
+ Todo
26
+ ----
27
+ - Conference resource
28
+ - Redirecting calls
29
+ - Support data returned in xml attributes
30
+ - SMS resource
31
+ - Recordings, Transcriptions, and Notifications
32
+ - Wrap more exceptions
33
+ - Add documentation on supported attributes to the ActiveResource models
34
+
35
+ Setup
36
+ =====
37
+
38
+ Before you start using TwilioResource, you have to give it your Twilio
39
+ login credentials. You can do this in your Rails initializer:
40
+
41
+ require 'twilio_resource'
42
+ TwilioResource.setup('token', 'sid')
43
+
44
+ Examples
45
+ ========
46
+
47
+ Requesting a new phone number:
48
+
49
+ phone = TwilioResource::LocalIncomingPhoneNumber.new(:url => 'http://www.example.com',
50
+ :area_code => '206',
51
+ :method => 'GET',
52
+ :friendly_name => "My First Phone Number",
53
+ :account_id => Twilio::Base.user)
54
+ phone.save
55
+
56
+ Requesting a new toll-free phone number:
57
+
58
+ phone = TwilioResource::TollFreeIncomingPhoneNumber.new(:url => 'http://www.example.com',
59
+ :area_code => '206',
60
+ :method => 'GET',
61
+ :friendly_name => "My First Phone Number",
62
+ :account_id => Twilio::Base.user)
63
+ phone.save
64
+
65
+ Retrieving a list of completed calls to a given phone number:
66
+
67
+ TwilioResource::Call.find(:all, :params => {
68
+ :account_id => Twilio::Base.user,
69
+ :status => Twilio::Call::COMPLETE,
70
+ :called => '2065551212'})
71
+
72
+ Placing a call:
73
+
74
+ TwilioResource::Call.new({
75
+ :account_id => Twilio::Base.user,
76
+ :caller => '2065551111',
77
+ :called => '2065551212',
78
+ :url => 'http://example.com/call.xml'})
@@ -0,0 +1,27 @@
1
+ require 'logger'
2
+ require 'activeresource'
3
+
4
+ require 'twilio_resource/twilio_format'
5
+ require 'twilio_resource/exceptions'
6
+
7
+ module TwilioResource
8
+
9
+ class << self
10
+ attr_accessor :logger
11
+ end
12
+
13
+ # Sets up the credentials the ActiveResources will use to access the
14
+ # twilio API. Optionally takes a +logger+, which defaults to +STDOUT+.
15
+ def self.setup(sid, token, logger = nil)
16
+ @logger = logger || Logger.new(STDOUT)
17
+ TwilioResource::Base.sid = sid
18
+ TwilioResource::Base.token = token
19
+ end
20
+ end
21
+
22
+ require 'twilio_resource/base'
23
+ require 'twilio_resource/account'
24
+ require 'twilio_resource/call'
25
+ require 'twilio_resource/incoming_phone_number'
26
+ require 'twilio_resource/local_incoming_phone_number'
27
+ require 'twilio_resource/toll_free_incoming_phone_number'
@@ -0,0 +1,6 @@
1
+
2
+ # Encapsulates a Twilio account. Not much to do here. Documentation
3
+ # can be found at
4
+ # http://www.twilio.com/docs/api/2008-08-01/rest/account
5
+ class TwilioResource::Account < TwilioResource::Base
6
+ end
@@ -0,0 +1,83 @@
1
+ # Encapsulates the changes that need to be made to active_resource's
2
+ # defaults in order to communicate with Twilio. There are a few main
3
+ # issues with ActiveResource's defaults:
4
+ #
5
+ # 1. Twilio's urls don't take an extension. ActiveResource requires
6
+ # endpoints to have an extension corresponding to the type of data,
7
+ # for example: +resource.xml+ or +resource.json+. Twilio's are
8
+ # always xml, but have no extension.
9
+ #
10
+ # 2. Twilio uses capitalized names in their URLs. For instance,
11
+ # instead of '/account/1/calls/1', they use '/Account/1/Calls/1'.
12
+ #
13
+ # 3. Twilio takes form encoded params, like token=blah&sid=foo, but
14
+ # returns data in XML. These changes are encapsulated in
15
+ # ActiveResource::Formats::TwilioFormat.
16
+ #
17
+ # All of the Twilio ActiveResource classes inherit from this class.
18
+ class TwilioResource::Base < ActiveResource::Base
19
+
20
+ class << self
21
+ attr_accessor :sid
22
+ attr_accessor :token
23
+
24
+ alias_method :user, :sid
25
+ alias_method :user=, :sid=
26
+ alias_method :password, :token
27
+ alias_method :password=, :token=
28
+ end
29
+
30
+ # Have to override this to make empty extensions work (without the dot)
31
+ def self.element_path(id, prefix_options = {}, query_options = nil)
32
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
33
+ extension = format.extension.blank? ? "" : ".#{format.extension}"
34
+ path = "#{prefix(prefix_options)}#{collection_name}/#{id}#{extension}#{query_string(query_options)}"
35
+ TwilioResource.logger.info("Request: #{path}")
36
+ path
37
+ end
38
+
39
+ # Have to override this to make empty extensions work (without the dot)
40
+ def self.collection_path(prefix_options = {}, query_options = nil)
41
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
42
+ extension = format.extension.blank? ? "" : ".#{format.extension}"
43
+ path = "#{prefix(prefix_options)}#{collection_name}#{extension}#{query_string(query_options)}"
44
+ TwilioResource.logger.info("Request: #{path}")
45
+ path
46
+ end
47
+
48
+ # Have to override this to make empty extensions work (without the dot)
49
+ def self.custom_method_collection_url(method_name, options = {})
50
+ prefix_options, query_options = split_options(options)
51
+ extension = format.extension.blank? ? "" : ".#{format.extension}"
52
+ path = "#{prefix(prefix_options)}#{collection_name}/#{method_name}#{extension}#{query_string(query_options)}"
53
+ TwilioResource.logger.info("Request: #{path}")
54
+ path
55
+ end
56
+
57
+ # Twilio uses capitalized path names
58
+ def self.element_name
59
+ super.camelize
60
+ end
61
+
62
+ def self.query_string(params)
63
+ # camelize all the param keys, because that's what Twilio expects
64
+ fixed_params_list = params.map {|k, v| [k.to_s.camelize, v]}.flatten
65
+ fixed_params_hash = Hash[*fixed_params_list] # Hash really needs a decent #map
66
+ super(fixed_params_hash)
67
+ end
68
+
69
+ # we should wrap the exceptions we can
70
+ def save(*params)
71
+ begin
72
+ super(*params)
73
+ rescue => e
74
+ raise TwilioResource::Exception.find_exception(e)
75
+ end
76
+
77
+ end
78
+
79
+
80
+ self.site = "https://api.twilio.com"
81
+ self.prefix = '/2008-08-01/'
82
+ self.format = :twilio
83
+ end
@@ -0,0 +1,20 @@
1
+
2
+ # Encapsulates a Twilio call resource. Documentation:
3
+ # - http://www.twilio.com/docs/api/2008-08-01/rest/call
4
+ # - http://www.twilio.com/docs/api/2008-08-01/rest/making_calls
5
+ class TwilioResource::Call < TwilioResource::Base
6
+ self.prefix = superclass.prefix_source + 'Accounts/:account_id/'
7
+
8
+ NOT_DIALED = 0
9
+ IN_PROGRESS = 1
10
+ COMPLETE = 2
11
+
12
+ # Returns the status of the call. Can be
13
+ # TwilioResource::Call::NOT_DIALED,
14
+ # TwilioResource::Call::IN_PROGRESS, or
15
+ # TwilioResource::Call::COMPLETE
16
+ def status
17
+ attributes["status"].to_i if attributes["status"]
18
+ end
19
+
20
+ end
@@ -0,0 +1,39 @@
1
+ module TwilioResource
2
+ end
3
+
4
+ # Wraps Twilio exceptions with a ruby exception class. Currently supports:
5
+ #
6
+ # - Error 21452 - No Phone Numbers Found
7
+ class TwilioResource::Exception < StandardError
8
+
9
+ # Given a twilio error xml response, returns the corresponding
10
+ # exception if it is mapped, or the xml response otherwise.
11
+ def self.find_exception(e)
12
+ new_exception = if e.respond_to?(:response)
13
+ exception_data = Hash.from_xml(e.response.body)
14
+
15
+
16
+ code = exception_data['twilio_response'] &&
17
+ exception_data['twilio_response']['rest_exception'] &&
18
+ exception_data['twilio_response']['rest_exception']['code']
19
+ exception_klass = twilio_exceptions[code.to_i] if code
20
+ exception_klass.nil? ? e : exception_klass.new
21
+ else
22
+ e
23
+ end
24
+ end
25
+
26
+ # Hash mapping error codes to exception classes.
27
+ def self.twilio_exceptions
28
+ {
29
+ 21452 => TwilioResource::NoPhoneNumbersFoundException,
30
+ }
31
+ end
32
+
33
+ end
34
+
35
+ class TwilioResource::NoPhoneNumbersFoundException < TwilioResource::Exception
36
+ def message
37
+ "No phone numbers found"
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ # Represents a Twilio-controlled phone number that can receive
2
+ # incoming phone calls. Documentation is at
3
+ # http://www.twilio.com/docs/api/2008-08-01/rest/incoming-phone-numbers
4
+ class TwilioResource::IncomingPhoneNumber < TwilioResource::Base
5
+ self.prefix = superclass.prefix_source + 'Accounts/:account_id/'
6
+ end
@@ -0,0 +1,14 @@
1
+ # Represents a Twilio-controlled "local" phone number that can receive
2
+ # incoming phone calls. If there are no numbers available in the
3
+ # specified area code, #save will throw a
4
+ # TwilioResource::NoPhoneNumbersFoundException. Documentation is at
5
+ # http://www.twilio.com/docs/api/2008-08-01/rest/incoming-phone-numbers
6
+ class TwilioResource::LocalIncomingPhoneNumber < TwilioResource::IncomingPhoneNumber
7
+
8
+ self.prefix = superclass.prefix_source + 'IncomingPhoneNumbers/'
9
+
10
+ def self.collection_name
11
+ 'Local'
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ # Represents a Twilio-controlled toll-free phone number that can receive
2
+ # incoming phone calls. If there are no numbers available in the
3
+ # specified area code, #save will throw a
4
+ # TwilioResource::NoPhoneNumbersFoundException. Documentation is at
5
+ # http://www.twilio.com/docs/api/2008-08-01/rest/incoming-phone-numbers
6
+ class TwilioResource::TollFreeIncomingPhoneNumber < TwilioResource::IncomingPhoneNumber
7
+
8
+ self.prefix = superclass.prefix_source + 'IncomingPhoneNumbers/'
9
+
10
+ def self.collection_name
11
+ 'TollFree'
12
+ end
13
+
14
+ end
@@ -0,0 +1,56 @@
1
+ module ActiveResource
2
+ module Formats
3
+ module TwilioFormat
4
+ extend self
5
+
6
+ def extension
7
+ ""
8
+ end
9
+
10
+ def mime_type
11
+ 'application/x-www-form-urlencoded'
12
+ end
13
+
14
+ # twilio uses camelcase for all of its params, and uses a query string for posts.
15
+ def encode(hash, options = {})
16
+ camelized_hash = ActiveSupport::OrderedHash.new
17
+ hash.each do |k, v|
18
+ camelized_hash[k.camelize] = v
19
+ end
20
+
21
+ TwilioResource.logger.info("Request: #{camelized_hash.to_query}")
22
+ camelized_hash.to_query
23
+ end
24
+
25
+ def decode(xml)
26
+ TwilioResource.logger.debug("Response: #{xml}")
27
+ from_xml_data(Hash.from_xml(xml))
28
+ end
29
+
30
+ private
31
+ # Manipulate from_xml Hash, because twilio doesn't format their
32
+ # xml in the way active_resource expects it.
33
+ def from_xml_data(data)
34
+ if data.is_a?(Hash) && data['twilio_response']
35
+ from_xml_data(data['twilio_response'])
36
+ else
37
+ data.each do |k, v|
38
+ # convert array-like things to actual arrays. twilio
39
+ # paginates their arrays, so it's easy to detect here. If
40
+ # it's the empty set, initialize it to an array so
41
+ # active_resource doesn't throw a fit.
42
+ if v["page"]
43
+ array_data = v[k.singularize]
44
+ data[k] = [array_data].flatten.compact
45
+ elsif v.blank?
46
+ data[k] = []
47
+ end
48
+ end
49
+ # now we have "calls" => [c1, c2, ...], but active_resource
50
+ # expects [c1, c2, c3]
51
+ data.values.first
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+ require 'twilio_mock'
3
+
4
+ class TwilioResource::AccountTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ TwilioMock.setup_remote_fixtures
9
+ end
10
+
11
+ def test_find_account
12
+ TwilioResource::Base.user = 1
13
+ account = TwilioResource::Account.find(1)
14
+ assert_equal "2", account.status
15
+ end
16
+
17
+ end
data/test/call_test.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+ require 'twilio_mock'
3
+
4
+ class TwilioResource::CallTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ TwilioMock.setup_remote_fixtures
9
+ end
10
+
11
+ def test_find_all
12
+ calls = TwilioResource::Call.find(:all, :params => {:account_id => 1})
13
+ assert_equal 2, calls.length
14
+ end
15
+
16
+ # what the hell, twilio? who uses capitalization to distinguish
17
+ # between param types? you, that's who.
18
+ def test_find_by_status
19
+ calls = TwilioResource::Call.find(:all, :params => {:account_id => 1, :status => TwilioResource::Call::COMPLETE})
20
+ assert_equal TwilioResource::Call::COMPLETE, calls.first.status
21
+ end
22
+
23
+ def test_find_by_start_time
24
+ calls = TwilioResource::Call.find(:all, :params => {:account_id => 1, :start_time => '2009-09-01'})
25
+ assert_equal 1, calls.length
26
+ end
27
+
28
+ def test_no_results
29
+ calls = TwilioResource::Call.find(:all, :params => {:account_id => 1, :status => TwilioResource::Call::COMPLETE, :start_time => '2009-09-01'})
30
+ assert_equal 0, calls.length
31
+ end
32
+
33
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+ require 'twilio_mock'
3
+
4
+ class TwilioResource::IncomingPhoneNumberTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ TwilioMock.setup_remote_fixtures
9
+ end
10
+
11
+ def test_find
12
+ local_number = TwilioResource::IncomingPhoneNumber.find(1, :params => {:account_id => 1})
13
+ assert_equal '4158675309', local_number.phone_number
14
+ end
15
+
16
+ def test_delete_from_class
17
+ assert TwilioResource::IncomingPhoneNumber.delete(1, :account_id => 1)
18
+ end
19
+
20
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+ require 'twilio_mock'
3
+
4
+ class TwilioResource::LocalIncomingPhoneNumberTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ TwilioMock.setup_remote_fixtures
9
+ end
10
+
11
+ def test_provision_local_number
12
+ phone = TwilioResource::LocalIncomingPhoneNumber.new(:url => "http://example.com/calls",
13
+ :area_code => "206",
14
+ :method => 'POST',
15
+ :friendly_name => "My Local Number",
16
+ :account_id => 1)
17
+ assert_equal "AreaCode=206&FriendlyName=My+Local+Number&Method=POST&Url=http%3A%2F%2Fexample.com%2Fcalls", phone.encode
18
+ phone.save
19
+
20
+ assert_equal '2064567890', phone.phone_number
21
+ end
22
+
23
+ def test_save_with_unavailable_number_throws_exception
24
+ TwilioResource::Base.user = 2
25
+ phone = TwilioResource::LocalIncomingPhoneNumber.new(:url => "http://example.com/calls",
26
+ :area_code => "815",
27
+ :method => 'POST',
28
+ :friendly_name => "My Local Number",
29
+ :account_id => TwilioResource::Base.user)
30
+ assert_equal "AreaCode=815&FriendlyName=My+Local+Number&Method=POST&Url=http%3A%2F%2Fexample.com%2Fcalls", phone.encode
31
+ assert_raises TwilioResource::NoPhoneNumbersFoundException do
32
+ phone.save
33
+ end
34
+
35
+ end
36
+
37
+ # test find, update
38
+
39
+ end
@@ -0,0 +1,7 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'activeresource'
4
+ require 'twilio_resource'
5
+
6
+ TwilioResource.setup('1', '1')
7
+ TwilioResource.logger.level = Logger::WARN
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+ require 'twilio_mock'
3
+
4
+ class TwilioResource::TollFreeIncomingPhoneNumberTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ TwilioMock.setup_remote_fixtures
9
+ end
10
+
11
+ def test_provision_toll_free_number
12
+ TwilioResource::Base.user = 1
13
+ phone = TwilioResource::TollFreeIncomingPhoneNumber.new(:url => "http://example.com/calls",
14
+ :method => 'POST',
15
+ :friendly_name => "My Local Number",
16
+ :account_id => TwilioResource::Base.user)
17
+ assert_equal "FriendlyName=My+Local+Number&Method=POST&Url=http%3A%2F%2Fexample.com%2Fcalls", phone.encode
18
+ phone.save
19
+
20
+ assert_equal '8774567890', phone.phone_number
21
+ end
22
+
23
+ # test find, update
24
+
25
+ end
@@ -0,0 +1,334 @@
1
+ require 'active_resource/http_mock'
2
+
3
+ class TwilioMock
4
+
5
+ def self.setup_remote_fixtures
6
+ ActiveResource::HttpMock.respond_to do |mock|
7
+ mock.get '/2008-08-01/Accounts/1', auth_get(1), main_account
8
+ mock.post '/2008-08-01/Accounts/1/IncomingPhoneNumbers/Local', auth_post(1), local_number_provision_success
9
+ mock.post '/2008-08-01/Accounts/2/IncomingPhoneNumbers/Local', auth_post(2), no_local_number, 400
10
+ mock.post '/2008-08-01/Accounts/1/IncomingPhoneNumbers/TollFree', auth_post(1), toll_free_number_provision_success
11
+
12
+ mock.get '/2008-08-01/Accounts/1/Calls', auth_get(1), all_calls
13
+ mock.get '/2008-08-01/Accounts/1/Calls?StartTime=2009-09-01', auth_get(1), recent_calls
14
+ mock.get '/2008-08-01/Accounts/1/Calls?Status=2', auth_get(1), succeeded_recent_calls
15
+ mock.get '/2008-08-01/Accounts/1/Calls?StartTime=2009-09-01&Status=2', auth_get(1), no_calls
16
+
17
+ mock.get '/2008-08-01/Accounts/1/IncomingPhoneNumbers/1', auth_get(1), phone_number_data
18
+ mock.delete '/2008-08-01/Accounts/1/IncomingPhoneNumbers/1', auth_delete(1), phone_number_delete_success
19
+ mock.delete '/2008-08-01/Accounts/2/IncomingPhoneNumbers/2', auth_delete(2), "", 404
20
+
21
+ end
22
+
23
+ end
24
+
25
+ def self.auth_delete(account_id)
26
+ old_account_id = TwilioResource::Base.user
27
+ TwilioResource::Base.user = account_id
28
+ auth = TwilioResource::Account.connection.send(:build_request_headers, {}, :delete)
29
+ TwilioResource::Base.user = old_account_id
30
+ auth
31
+ end
32
+
33
+ def self.auth_post(account_id)
34
+ old_account_id = TwilioResource::Base.user
35
+ TwilioResource::Base.user = account_id
36
+ auth = TwilioResource::Account.connection.send(:build_request_headers, {}, :post)
37
+ TwilioResource::Base.user = old_account_id
38
+ auth
39
+ end
40
+
41
+ def self.auth_get(account_id)
42
+ old_account_id = TwilioResource::Base.user
43
+ TwilioResource::Base.user = account_id
44
+ auth = TwilioResource::Account.connection.send(:build_request_headers, {}, :get)
45
+ TwilioResource::Base.user = old_account_id
46
+ auth
47
+ end
48
+
49
+ def self.phone_number_data
50
+ <<END
51
+ <TwilioResponse>
52
+ <IncomingPhoneNumber>
53
+ <Sid>PNe536dfda7c6184afab78d980cb8cdf43</Sid>
54
+ <AccountSid>AC35542fc30a091bed0c1ed511e1d9935d</AccountSid>
55
+ <FriendlyName>My Home Phone Number</FriendlyName>
56
+ <PhoneNumber>4158675309</PhoneNumber>
57
+ <Url>http://mycompany.com/handleMainLineCall.asp</Url>
58
+ <Method>GET</Method>
59
+ <DateCreated>Tue, 01 Apr 2008 11:26:32 -0700</DateCreated>
60
+ <DateUpdated>Tue, 01 Apr 2008 11:26:32 -0700</DateUpdated>
61
+ </IncomingPhoneNumber>
62
+ </TwilioResponse>
63
+ END
64
+ end
65
+
66
+ def self.main_account
67
+ <<END
68
+ <TwilioResponse>
69
+ <Account>
70
+ <Sid>AC309475e5fede1b49e100272a8640f438</Sid>
71
+ <FriendlyName>My Twilio Account</FriendlyName>
72
+ <Status>2</Status>
73
+ <StatusText>Active</StatusText>
74
+ <DateCreated>Wed, 02 Apr 2008 17:33:38 -0700</DateCreated>
75
+ <DateUpdated>Wed, 02 Apr 2008 17:34:18 -0700</DateUpdated>
76
+ <AuthToken>3a2630a909aadbf60266234756fb15a0</AuthToken>
77
+ </Account>
78
+ </TwilioResponse>
79
+ END
80
+ end
81
+
82
+ def self.phone_number_delete_success
83
+ <<END
84
+ <TwilioResponse />
85
+ END
86
+ end
87
+
88
+ def self.all_calls
89
+ <<END
90
+ <TwilioResponse>
91
+ <Calls page="0" numpages="1" pagesize="50" total="38" start="0" end="37">
92
+ <Call>
93
+ <Sid>CA42ed11f93dc08b952027ffbc406d0868</Sid>
94
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
95
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
96
+ <CallSegmentSid/>
97
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
98
+ <Called>4159633717</Called>
99
+ <Caller>4156767925</Caller>
100
+ <PhoneNumberSid>PN01234567890123456789012345678900</PhoneNumberSid>
101
+ <Status>2</Status>
102
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
103
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
104
+ <Duration>14</Duration>
105
+ <Price/>
106
+ <Flags>1</Flags>
107
+ </Call>
108
+ <Call>
109
+ <Sid>CA751e8fa0a0105cf26a0d7a9775fb4bfb</Sid>
110
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
111
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
112
+ <CallSegmentSid/>
113
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
114
+ <Called>2064287985</Called>
115
+ <Caller>4156767925</Caller>
116
+ <PhoneNumberSid>PNd59c2ba27ef48264773edb90476d1674</PhoneNumberSid>
117
+ <Status>2</Status>
118
+ <StartTime>Thu, 03 Apr 2008 01:37:05 -0400</StartTime>
119
+ <EndTime>Thu, 03 Apr 2008 01:37:40 -0400</EndTime>
120
+ <Duration>35</Duration>
121
+ <Price/>
122
+ <Flags>1</Flags>
123
+ </Call>
124
+ </Calls>
125
+ </TwilioResponse>
126
+ END
127
+ end
128
+
129
+ def self.succeeded_calls
130
+ <<END
131
+ <TwilioResponse>
132
+ <Calls page="0" numpages="1" pagesize="50" total="38" start="0" end="37">
133
+ <Call>
134
+ <Sid>CA42ed11f93dc08b952027ffbc406d0868</Sid>
135
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
136
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
137
+ <CallSegmentSid/>
138
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
139
+ <Called>4159633717</Called>
140
+ <Caller>4156767925</Caller>
141
+ <PhoneNumberSid>PN01234567890123456789012345678900</PhoneNumberSid>
142
+ <Status>2</Status>
143
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
144
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
145
+ <Duration>14</Duration>
146
+ <Price/>
147
+ <Flags>1</Flags>
148
+ </Call>
149
+ <Call>
150
+ <Sid>1000</Sid>
151
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
152
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
153
+ <CallSegmentSid>10001</CallSegmentSid>
154
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
155
+ <Called>4159633717</Called>
156
+ <Caller>4156767925</Caller>
157
+ <PhoneNumberSid>ABC123</PhoneNumberSid>
158
+ <Status>2</Status>
159
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
160
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
161
+ <Duration>14</Duration>
162
+ <Price/>
163
+ <Flags>1</Flags>
164
+ </Call>
165
+ <Call>
166
+ <Sid>1001</Sid>
167
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
168
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
169
+ <CallSegmentSid>10002</CallSegmentSid>
170
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
171
+ <Called>4159633717</Called>
172
+ <Caller>4156767925</Caller>
173
+ <PhoneNumberSid>ABC123</PhoneNumberSid>
174
+ <Status>2</Status>
175
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
176
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
177
+ <Duration>14</Duration>
178
+ <Price/>
179
+ <Flags>1</Flags>
180
+ </Call>
181
+ <Call>
182
+ <Sid>1002</Sid>
183
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
184
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
185
+ <CallSegmentSid>10003</CallSegmentSid>
186
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
187
+ <Called>4159633717</Called>
188
+ <Caller>4156767925</Caller>
189
+ <PhoneNumberSid>ABC123</PhoneNumberSid>
190
+ <Status>2</Status>
191
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
192
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
193
+ <Duration>14</Duration>
194
+ <Price/>
195
+ <Flags>1</Flags>
196
+ </Call>
197
+ <Call>
198
+ <Sid>1003</Sid>
199
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
200
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
201
+ <CallSegmentSid>10004</CallSegmentSid>
202
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
203
+ <Called>4159633717</Called>
204
+ <Caller>4156767925</Caller>
205
+ <PhoneNumberSid>UNKNOWN</PhoneNumberSid>
206
+ <Status>2</Status>
207
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
208
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
209
+ <Duration>14</Duration>
210
+ <Price/>
211
+ <Flags>1</Flags>
212
+ </Call>
213
+ <Call>
214
+ <Sid>AVENDORIDAVENDORIDAVENDORID</Sid>
215
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
216
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
217
+ <CallSegmentSid>10004</CallSegmentSid>
218
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
219
+ <Called>4159633717</Called>
220
+ <Caller>4156767925</Caller>
221
+ <PhoneNumberSid>ABC123</PhoneNumberSid>
222
+ <Status>2</Status>
223
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
224
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
225
+ <Duration>14</Duration>
226
+ <Price/>
227
+ <Flags>1</Flags>
228
+ </Call>
229
+ </Calls>
230
+ </TwilioResponse>
231
+ END
232
+ end
233
+
234
+ def self.recent_calls
235
+ <<END
236
+ <TwilioResponse>
237
+ <Calls page="0" numpages="1" pagesize="50" total="38" start="0" end="37">
238
+ <Call>
239
+ <Sid>CA42ed11f93dc08b952027ffbc406d0868</Sid>
240
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
241
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
242
+ <CallSegmentSid/>
243
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
244
+ <Called>4159633717</Called>
245
+ <Caller>4156767925</Caller>
246
+ <PhoneNumberSid>PN01234567890123456789012345678900</PhoneNumberSid>
247
+ <Status>1</Status>
248
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
249
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
250
+ <Duration>14</Duration>
251
+ <Price/>
252
+ <Flags>1</Flags>
253
+ </Call>
254
+ </Calls>
255
+ </TwilioResponse>
256
+ END
257
+ end
258
+
259
+
260
+ def self.succeeded_recent_calls
261
+ <<END
262
+ <TwilioResponse>
263
+ <Calls page="0" numpages="1" pagesize="50" total="38" start="0" end="37">
264
+ <Call>
265
+ <Sid>CA42ed11f93dc08b952027ffbc406d0868</Sid>
266
+ <DateCreated>Sat, 07 Feb 2009 13:15:19 -0800</DateCreated>
267
+ <DateUpdated>Sat, 07 Feb 2009 13:15:19 -0800</DateUpdated>
268
+ <CallSegmentSid>8142ed11f93dc08b952027ffbc406d0868</CallSegmentSid>
269
+ <AccountSid>AC309475e5fede1b49e100272a8640f438</AccountSid>
270
+ <Called>4159633717</Called>
271
+ <Caller>4156767925</Caller>
272
+ <PhoneNumberSid>PN01234567890123456789012345678900</PhoneNumberSid>
273
+ <Status>2</Status>
274
+ <StartTime>Thu, 03 Apr 2008 04:36:33 -0400</StartTime>
275
+ <EndTime>Thu, 03 Apr 2008 04:36:47 -0400</EndTime>
276
+ <Duration>14</Duration>
277
+ <Price/>
278
+ <Flags>1</Flags>
279
+ </Call>
280
+ </Calls>
281
+ </TwilioResponse>
282
+ END
283
+ end
284
+
285
+ def self.no_calls
286
+ <<END
287
+ <TwilioResponse>
288
+ <Calls page="0" numpages="1" pagesize="50" total="38" start="0" end="37">
289
+ </Calls>
290
+ </TwilioResponse>
291
+ END
292
+ end
293
+
294
+ def self.local_number_provision_success
295
+ <<END
296
+ <TwilioResponse>
297
+ <IncomingPhoneNumber>
298
+ <Sid>PNe536dfda7c6184afab78d980cb8cdf43</Sid>
299
+ <AccountSid>AC35542fc30a091bed0c1ed511e1d9935d</AccountSid>
300
+ <FriendlyName>My Local Number</FriendlyName>
301
+ <PhoneNumber>2064567890</PhoneNumber>
302
+ <Url>http://example.com/calls</Url>
303
+ <Method>GET</Method>
304
+ <DateCreated>Tue, 01 Apr 2008 11:26:32 -0700</DateCreated>
305
+ <DateUpdated>Tue, 01 Apr 2008 11:26:32 -0700</DateUpdated>
306
+ </IncomingPhoneNumber>
307
+ </TwilioResponse>
308
+ END
309
+ end
310
+
311
+ def self.toll_free_number_provision_success
312
+ <<END
313
+ <TwilioResponse>
314
+ <IncomingPhoneNumber>
315
+ <Sid>PNe536dfda7c6184afab78d980cb8cdf43</Sid>
316
+ <AccountSid>AC35542fc30a091bed0c1ed511e1d9935d</AccountSid>
317
+ <FriendlyName>My Toll Free Number</FriendlyName>
318
+ <PhoneNumber>8774567890</PhoneNumber>
319
+ <Url>http://example.com/calls</Url>
320
+ <Method>GET</Method>
321
+ <DateCreated>Tue, 01 Apr 2008 11:26:32 -0700</DateCreated>
322
+ <DateUpdated>Tue, 01 Apr 2008 11:26:32 -0700</DateUpdated>
323
+ </IncomingPhoneNumber>
324
+ </TwilioResponse>
325
+ END
326
+ end
327
+
328
+ def self.no_local_number
329
+ <<END
330
+ <TwilioResponse><RestException><Status>400</Status><Message>No phone numbers found</Message><Code>21452</Code><MoreInfo>http://www.twilio.com/docs/errors/21452</MoreInfo></RestException></TwilioResponse>
331
+ END
332
+ end
333
+
334
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twilio_resource
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Justin Weiss
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-16 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activeresource
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 2
31
+ version: 2.3.2
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description:
35
+ email: justin@uberweiss.org
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.md
42
+ files:
43
+ - lib/twilio_resource/account.rb
44
+ - lib/twilio_resource/base.rb
45
+ - lib/twilio_resource/call.rb
46
+ - lib/twilio_resource/exceptions.rb
47
+ - lib/twilio_resource/incoming_phone_number.rb
48
+ - lib/twilio_resource/local_incoming_phone_number.rb
49
+ - lib/twilio_resource/toll_free_incoming_phone_number.rb
50
+ - lib/twilio_resource/twilio_format.rb
51
+ - lib/twilio_resource.rb
52
+ - test/account_test.rb
53
+ - test/call_test.rb
54
+ - test/incoming_phone_number_test.rb
55
+ - test/local_incoming_phone_number_test.rb
56
+ - test/test_helper.rb
57
+ - test/toll_free_incoming_phone_number_test.rb
58
+ - test/twilio_mock.rb
59
+ - README.md
60
+ has_rdoc: true
61
+ homepage: http://github.com/justinweiss/twilio_resource
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.6
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: An ActiveResource API wrapper for Twilio
90
+ test_files:
91
+ - test/account_test.rb
92
+ - test/call_test.rb
93
+ - test/incoming_phone_number_test.rb
94
+ - test/local_incoming_phone_number_test.rb
95
+ - test/toll_free_incoming_phone_number_test.rb