twilio-ruby 3.11.5 → 4.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 (114) hide show
  1. checksums.yaml +13 -5
  2. data/.gitignore +1 -1
  3. data/.travis.yml +20 -9
  4. data/AUTHORS.md +32 -25
  5. data/CHANGES.md +203 -0
  6. data/Gemfile +8 -1
  7. data/{LICENSE → LICENSE.md} +4 -2
  8. data/Makefile +1 -2
  9. data/README.md +70 -39
  10. data/Rakefile +8 -10
  11. data/docs/faq.rst +3 -3
  12. data/docs/getting-started.rst +17 -12
  13. data/docs/index.rst +15 -0
  14. data/docs/usage/accounts.rst +6 -6
  15. data/docs/usage/addresses.rst +101 -0
  16. data/docs/usage/applications.rst +10 -10
  17. data/docs/usage/basics.rst +17 -4
  18. data/docs/usage/caller-ids.rst +4 -2
  19. data/docs/usage/conferences.rst +11 -11
  20. data/docs/usage/errors.rst +7 -7
  21. data/docs/usage/messages.rst +48 -20
  22. data/docs/usage/notifications.rst +6 -4
  23. data/docs/usage/phone-calls.rst +33 -14
  24. data/docs/usage/phone-numbers.rst +45 -31
  25. data/docs/usage/queues.rst +8 -8
  26. data/docs/usage/recordings.rst +12 -10
  27. data/docs/usage/sip.rst +15 -14
  28. data/docs/usage/taskrouter-tokens.rst +98 -0
  29. data/docs/usage/taskrouter.rst +226 -0
  30. data/docs/usage/token-generation.rst +19 -4
  31. data/docs/usage/transcriptions.rst +3 -2
  32. data/docs/usage/twiml.rst +7 -7
  33. data/docs/usage/validation.rst +39 -3
  34. data/examples/examples.rb +44 -20
  35. data/examples/print-call-log.rb +1 -1
  36. data/lib/rack/twilio_webhook_authentication.rb +47 -0
  37. data/lib/twilio-ruby/rest/accounts.rb +2 -1
  38. data/lib/twilio-ruby/rest/addresses/dependent_phone_numbers.rb +6 -0
  39. data/lib/twilio-ruby/rest/addresses.rb +12 -0
  40. data/lib/twilio-ruby/rest/base_client.rb +127 -0
  41. data/lib/twilio-ruby/rest/call_feedback.rb +28 -0
  42. data/lib/twilio-ruby/rest/call_feedback_summary.rb +13 -0
  43. data/lib/twilio-ruby/rest/calls.rb +10 -5
  44. data/lib/twilio-ruby/rest/client.rb +44 -109
  45. data/lib/twilio-ruby/rest/conferences/participants.rb +2 -2
  46. data/lib/twilio-ruby/rest/incoming_phone_numbers.rb +1 -1
  47. data/lib/twilio-ruby/rest/instance_resource.rb +2 -16
  48. data/lib/twilio-ruby/rest/list_resource.rb +20 -30
  49. data/lib/twilio-ruby/rest/lookups/phone_numbers.rb +17 -0
  50. data/lib/twilio-ruby/rest/lookups_client.rb +99 -0
  51. data/lib/twilio-ruby/rest/messages.rb +5 -0
  52. data/lib/twilio-ruby/rest/next_gen_list_resource.rb +36 -0
  53. data/lib/twilio-ruby/rest/outgoing_caller_ids.rb +1 -1
  54. data/lib/twilio-ruby/rest/queues/members.rb +1 -1
  55. data/lib/twilio-ruby/rest/sip.rb +1 -3
  56. data/lib/twilio-ruby/rest/sms/messages.rb +23 -0
  57. data/lib/twilio-ruby/rest/task_router/activities.rb +8 -0
  58. data/lib/twilio-ruby/rest/task_router/events.rb +8 -0
  59. data/lib/twilio-ruby/rest/task_router/reservations.rb +8 -0
  60. data/lib/twilio-ruby/rest/task_router/statistics.rb +26 -0
  61. data/lib/twilio-ruby/rest/task_router/task_queues.rb +17 -0
  62. data/lib/twilio-ruby/rest/task_router/task_queues_statistics.rb +15 -0
  63. data/lib/twilio-ruby/rest/task_router/tasks.rb +15 -0
  64. data/lib/twilio-ruby/rest/task_router/workers.rb +13 -0
  65. data/lib/twilio-ruby/rest/task_router/workers_statistics.rb +8 -0
  66. data/lib/twilio-ruby/rest/task_router/workflow_statistics.rb +7 -0
  67. data/lib/twilio-ruby/rest/task_router/workflows.rb +11 -0
  68. data/lib/twilio-ruby/rest/task_router/workspace_statistics.rb +7 -0
  69. data/lib/twilio-ruby/rest/task_router/workspaces.rb +17 -0
  70. data/lib/twilio-ruby/rest/task_router_client.rb +176 -0
  71. data/lib/twilio-ruby/rest/tokens.rb +7 -0
  72. data/lib/twilio-ruby/rest/usage/records.rb +2 -2
  73. data/lib/twilio-ruby/rest/utils.rb +35 -11
  74. data/lib/twilio-ruby/task_router/capability.rb +87 -0
  75. data/lib/twilio-ruby/task_router.rb +0 -0
  76. data/lib/twilio-ruby/twiml/response.rb +1 -0
  77. data/lib/twilio-ruby/util/capability.rb +10 -7
  78. data/lib/twilio-ruby/util/client_config.rb +29 -0
  79. data/lib/twilio-ruby/util/configuration.rb +7 -0
  80. data/lib/twilio-ruby/util/request_validator.rb +18 -3
  81. data/lib/twilio-ruby/version.rb +1 -1
  82. data/lib/twilio-ruby.rb +48 -0
  83. data/spec/rack/twilio_webhook_authentication_spec.rb +110 -0
  84. data/spec/rest/account_spec.rb +51 -20
  85. data/spec/rest/address_spec.rb +11 -0
  86. data/spec/rest/call_feedback_spec.rb +12 -0
  87. data/spec/rest/call_feedback_summary_spec.rb +9 -0
  88. data/spec/rest/call_spec.rb +8 -4
  89. data/spec/rest/client_spec.rb +209 -51
  90. data/spec/rest/conference_spec.rb +4 -2
  91. data/spec/rest/instance_resource_spec.rb +4 -4
  92. data/spec/rest/lookups/phone_number_spec.rb +8 -0
  93. data/spec/rest/message_spec.rb +2 -2
  94. data/spec/rest/numbers_spec.rb +25 -13
  95. data/spec/rest/queue_spec.rb +4 -2
  96. data/spec/rest/recording_spec.rb +4 -2
  97. data/spec/rest/sms/message_spec.rb +37 -0
  98. data/spec/rest/sms/messages_spec.rb +31 -0
  99. data/spec/rest/task_router/reservation_spec.rb +9 -0
  100. data/spec/rest/task_router/task_queue_spec.rb +9 -0
  101. data/spec/rest/token_spec.rb +7 -0
  102. data/spec/rest/utils_spec.rb +45 -0
  103. data/spec/spec_helper.rb +12 -3
  104. data/spec/support/fakeweb.rb +2 -0
  105. data/spec/task_router_spec.rb +114 -0
  106. data/spec/twilio_spec.rb +15 -0
  107. data/spec/util/capability_spec.rb +167 -118
  108. data/spec/util/client_config_spec.rb +21 -0
  109. data/spec/util/configuration_spec.rb +15 -0
  110. data/spec/util/request_validator_spec.rb +31 -3
  111. data/spec/util/url_encode_spec.rb +2 -2
  112. data/twilio-ruby.gemspec +28 -27
  113. metadata +93 -71
  114. data/CHANGES +0 -47
data/docs/usage/twiml.rst CHANGED
@@ -18,7 +18,7 @@ which returns raw TwiML.
18
18
  require 'twilio-ruby'
19
19
 
20
20
  Twilio::TwiML::Response.new do |r|
21
- r.Say "Hello"
21
+ r.Say "Hello"
22
22
  end.text
23
23
 
24
24
  .. code-block:: xml
@@ -35,14 +35,14 @@ All attributes are keyword arguments.
35
35
  require 'twilio-ruby'
36
36
 
37
37
  Twilio::TwiML::Response.new do |r|
38
- r.Play "https://api.twilio.com/cowbell.mp3", :loop => 5
38
+ r.Play "https://api.twilio.com/cowbell.mp3", loop: 5
39
39
  end.text
40
40
 
41
41
  .. code-block:: xml
42
42
 
43
43
  <?xml version="1.0" encoding="utf-8"?>
44
44
  <Response>
45
- <Play loop="3">https://api.twilio.com/cowbell.mp3</Play>
45
+ <Play loop="3">https://api.twilio.com/cowbell.mp3</Play>
46
46
  <Response>
47
47
 
48
48
  Any example of nesting nouns in verbs
@@ -52,10 +52,10 @@ Any example of nesting nouns in verbs
52
52
  require 'twilio-ruby'
53
53
 
54
54
  Twilio::TwiML::Response.new do |r|
55
- r.Say "hello"
56
- r.Gather :finish_on_key => 4 do |g|
57
- g.Say "world"
58
- end
55
+ r.Say "hello"
56
+ r.Gather finishOnKey: => 4 do |g|
57
+ g.Say "world"
58
+ end
59
59
  end.text
60
60
 
61
61
  which returns the following
@@ -48,12 +48,11 @@ actually from Twilio.
48
48
  signature = "HpS7PBa1Agvt4OtO+wZp75IuQa0=" # will look something like that
49
49
 
50
50
  if @validator.validate(url, post_vars, signature)
51
- puts "Confirmed to have come from Twilio."
51
+ puts "Confirmed to have come from Twilio."
52
52
  else
53
- puts "NOT VALID. It might have been spoofed!"
53
+ puts "NOT VALID. It might have been spoofed!"
54
54
  end
55
55
 
56
-
57
56
  Trailing Slashes
58
57
  ==================
59
58
 
@@ -69,3 +68,40 @@ https://mycompany.com/twilio and you may have built the hash using
69
68
  https://mycompany.com/twilio/. More information can be found in our
70
69
  documentation on validating requests.
71
70
 
71
+ Rack Middleware
72
+ ===============
73
+
74
+ If you are serving up your site using a Rack based framework, such as Sinatra or
75
+ Rails, you can use the Rack middleware that is included in the gem to protect
76
+ from spoofing attempts.
77
+
78
+ To use the middleware, you need to set it up with your Twilio Auth Token and a
79
+ set of paths to watch. For example, here is how you would use the middleware in
80
+ a Sinatra application:
81
+
82
+ .. code-block:: ruby
83
+
84
+ require 'sinatra'
85
+ require 'twilio-ruby'
86
+
87
+ auth_token = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'
88
+
89
+ use Rack::TwilioWebhookAuthentication, auth_token, /\/messages/
90
+
91
+ post '/messages' do
92
+ # response with TwiML
93
+ end
94
+
95
+ Now, any POST request to /messages in your application that doesn't validate as
96
+ a Twilio request, will automatically respond with a 403 status code and your
97
+ action will not be hit.
98
+
99
+ If you use subaccounts and need to validate with different auth tokens, you can pass a block to the middleware instead of an auth token. The block will be passed the Account Sid making the call.
100
+
101
+ .. code-block:: ruby
102
+
103
+ use Rack::TwilioWebhookAuthentication, nil, /\/messages/ do |account_sid|
104
+ # lookup auth_token from account_sid
105
+ end
106
+
107
+ Ensure you pass `nil` for the auth_token when passing a block, otherwise the block will not be called.
data/examples/examples.rb CHANGED
@@ -8,7 +8,7 @@
8
8
  ################ ACCOUNTS ################
9
9
 
10
10
  # shortcut to grab your account object (account_sid is inferred from the client's auth credentials)
11
- @account = @client.account
11
+ @account = @client.account
12
12
 
13
13
  # list your (sub)accounts
14
14
  @client.accounts.list
@@ -19,12 +19,16 @@
19
19
  puts @account.friendly_name
20
20
 
21
21
  # update an account's friendly name
22
- @client.accounts.get(@account_sid).update(:friendly_name => 'A Fabulous Friendly Name')
22
+ @client.accounts.get(@account_sid).update(friendly_name: 'A Fabulous Friendly Name')
23
23
 
24
24
  ################ CALLS ################
25
25
 
26
26
  # print a list of calls (all parameters optional)
27
- @account.calls.list({:page => 0, :page_size => 1000, :start_time => '2010-09-01'}).each do |call|
27
+ @account.calls.list(
28
+ page: 0,
29
+ page_size: 1000,
30
+ start_time: '2010-09-01'
31
+ ).each do |call|
28
32
  puts call.sid
29
33
  end
30
34
 
@@ -34,18 +38,23 @@ end
34
38
  end
35
39
 
36
40
  # make a new outgoing call. returns a call object just like calls.get
37
- @call = @account.calls.create({:from => '+14159341234', :to => '+18004567890', :url => 'http://example.com/call-handler'})
41
+ @call = @account.calls.create(
42
+ from: '+14159341234',
43
+ to: '+18004567890',
44
+ url: 'http://example.com/call-handler'
45
+ )
38
46
 
39
47
  # cancel the call if not already in progress
40
- @account.calls.get(@call.sid).update({:status => 'canceled'})
48
+ @account.calls.get(@call.sid).update(status: 'canceled')
41
49
  # or equivalently
42
- @call.update({:status => 'canceled'})
50
+ @call.update(status: 'canceled')
43
51
  # or simply
44
52
  @call.cancel
45
53
 
46
54
  # redirect and then terminate a call
47
- @account.calls.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:url => 'http://example.com/call-redirect'})
48
- @account.calls.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:status => 'completed'})
55
+ @call = @account.calls.get('CA386025c9bf5d6052a1d1ea42b4d16662')
56
+ @call.update(url: 'http://example.com/call-redirect')
57
+ @call.update(status: 'completed')
49
58
  # or, use the aliases...
50
59
  @call.redirect_to('http://example.com/call-redirect')
51
60
  @call.hangup
@@ -53,7 +62,7 @@ end
53
62
  ################ SMS MESSAGES ################
54
63
 
55
64
  # print a list of messages
56
- @account.messages.list({:date_sent => '2010-09-01'}).each do |message|
65
+ @account.messages.list(date_sent: '2010-09-01').each do |message|
57
66
  puts message.body
58
67
  end
59
68
 
@@ -61,10 +70,18 @@ end
61
70
  puts @account.messages.get('SMXXXXXXXX').body
62
71
 
63
72
  # send an sms
64
- @account.messages.create(:from => '+14159341234', :to => '+16105557069', :body => 'Hey there!')
73
+ @account.messages.create(
74
+ from: '+14159341234',
75
+ to: '+16105557069',
76
+ body: 'Hey there!'
77
+ )
65
78
 
66
79
  # send an mms
67
- @account.messages.create(:from => '+14159341234', :to => '+16105557069', :media_urls => 'http://example.com/media.png')
80
+ @account.messages.create(
81
+ from: '+14159341234',
82
+ to: '+16105557069',
83
+ media_urls: 'http://example.com/media.png'
84
+ )
68
85
 
69
86
  ################ PHONE NUMBERS ################
70
87
 
@@ -72,22 +89,28 @@ puts @account.messages.get('SMXXXXXXXX').body
72
89
  @account.available_phone_numbers.list
73
90
 
74
91
  # print some available numbers
75
- @numbers = @account.available_phone_numbers.get('US').local.list({:contains => 'AWESOME'})
76
- @numbers.each {|num| puts num.phone_number}
92
+ @numbers = @account.available_phone_numbers.get('US').local.list(
93
+ contains: 'AWESOME'
94
+ )
95
+ @numbers.each { |num| puts num.phone_number }
77
96
 
78
97
  # buy the first one
79
- @account.incoming_phone_numbers.create(:phone_number => @numbers[0].phone_number)
98
+ @account.incoming_phone_numbers.create(phone_number: @numbers[0].phone_number)
80
99
 
81
100
  # update an existing phone number's voice url
82
- @account.incoming_phone_numbers.get('PNdba508c5616a7f5e141789f44f022cc3').update({:voice_url => 'http://example.com/voice'})
101
+ number = @account.incoming_phone_numbers.get('PNdba508c5616a7f5e141789f44f022cc3')
102
+ number.update(voice_url: 'http://example.com/voice')
83
103
 
84
104
  # decommission an existing phone number
85
- numbers = @account.incoming_phone_numbers.list(:friendly_name => 'A Fabulous Friendly Name')
105
+ numbers = @account.incoming_phone_numbers.list(
106
+ friendly_name: 'A Fabulous Friendly Name'
107
+ )
86
108
  numbers[0].delete
87
109
  ################ CONFERENCES ################
88
110
 
89
111
  # get a particular conference's participants object and stash it
90
- @participants = @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39').participants
112
+ conference = @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39')
113
+ @participants = conference.participants
91
114
 
92
115
  # list participants
93
116
  @participants.list.each do |p|
@@ -95,17 +118,18 @@ numbers[0].delete
95
118
  end
96
119
 
97
120
  # update a conference participant
98
- @participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:muted => 'true'})
121
+ @participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').update(muted: 'true')
99
122
  # or an easier way
100
123
  @participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').mute
101
124
 
102
125
  # and, since we're lazy loading, this would only incur one http request
103
- @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39').participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:muted => 'true'})
126
+ @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39').participants
127
+ .get('CA386025c9bf5d6052a1d1ea42b4d16662').update(muted: 'true')
104
128
 
105
129
  ################ QUEUES ###################
106
130
 
107
131
  # create a new queue
108
- @queue = @account.queues.create(:friendly_name => 'MyQueue', :max_size => 50)
132
+ @queue = @account.queues.create(friendly_name: 'MyQueue', max_size: 50)
109
133
 
110
134
  # get a list of queues for this account
111
135
  @queues = @account.queues.list
@@ -13,7 +13,7 @@ auth_token = '62ea81de3a5b414154eb263595357c69'
13
13
  # set up a client
14
14
  client = Twilio::REST::Client.new(account_sid, auth_token)
15
15
 
16
- calls = client.account.calls.list
16
+ calls = client.calls.list
17
17
 
18
18
  begin
19
19
  calls.each do |call|
@@ -0,0 +1,47 @@
1
+ module Rack
2
+ # Middleware that authenticates webhooks from Twilio using the request
3
+ # validator.
4
+ #
5
+ # The middleware takes an auth token with which to set up the request
6
+ # validator and any number of paths. When a path matches the incoming request
7
+ # path, the request will be checked for authentication.
8
+ #
9
+ # Example:
10
+ #
11
+ # require 'rack'
12
+ # use Rack::TwilioWebhookAuthentication, ENV['AUTH_TOKEN'], /\/messages/
13
+ #
14
+ # The above appends this middleware to the stack, using an auth token saved in
15
+ # the ENV and only against paths that match /\/messages/. If the request
16
+ # validates then it gets passed on to the action as normal. If the request
17
+ # doesn't validate then the middleware responds immediately with a 403 status.
18
+
19
+ class TwilioWebhookAuthentication
20
+ def initialize(app, auth_token, *paths, &auth_token_lookup)
21
+ @app = app
22
+ @auth_token = auth_token
23
+ define_singleton_method(:get_auth_token, auth_token_lookup) if block_given?
24
+ @path_regex = Regexp.union(paths)
25
+ end
26
+
27
+ def call(env)
28
+ return @app.call(env) unless env["PATH_INFO"].match(@path_regex)
29
+ request = Rack::Request.new(env)
30
+ original_url = request.url
31
+ params = request.post? ? request.POST : {}
32
+ auth_token = @auth_token || get_auth_token(params['AccountSid'])
33
+ validator = Twilio::Util::RequestValidator.new(auth_token)
34
+ signature = env['HTTP_X_TWILIO_SIGNATURE'] || ""
35
+ if validator.validate(original_url, params, signature)
36
+ @app.call(env)
37
+ else
38
+ [
39
+ 403,
40
+ {'Content-Type' => 'text/plain'},
41
+ ["Twilio Request Validation Failed."]
42
+ ]
43
+ end
44
+ end
45
+ end
46
+
47
+ end
@@ -8,7 +8,8 @@ module Twilio
8
8
  resource :sandbox, :available_phone_numbers, :incoming_phone_numbers,
9
9
  :calls, :outgoing_caller_ids, :conferences, :sms, :recordings,
10
10
  :transcriptions, :notifications, :applications, :connect_apps,
11
- :authorized_connect_apps, :queues, :usage, :messages, :media, :sip
11
+ :authorized_connect_apps, :queues, :usage, :messages, :media, :sip,
12
+ :tokens, :addresses
12
13
  end
13
14
  end
14
15
  end
@@ -0,0 +1,6 @@
1
+ module Twilio
2
+ module REST
3
+ class DependentPhoneNumbers < ListResource; end
4
+ class DependentPhoneNumber < InstanceResource; end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module Twilio
2
+ module REST
3
+ class Addresses < ListResource; end
4
+
5
+ class Address < InstanceResource
6
+ def initialize(path, client, params={})
7
+ super path, client, params
8
+ resource :dependent_phone_numbers
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,127 @@
1
+ module Twilio
2
+ module REST
3
+ class BaseClient
4
+ include Twilio::Util
5
+ include Twilio::REST::Utils
6
+
7
+ HTTP_HEADERS = {
8
+ 'Accept' => 'application/json',
9
+ 'Accept-Charset' => 'utf-8',
10
+ 'User-Agent' => "twilio-ruby/#{Twilio::VERSION}" \
11
+ " (#{RUBY_ENGINE}/#{RUBY_PLATFORM}" \
12
+ " #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
13
+ }
14
+
15
+ ##
16
+ # Override the default host for a REST Client (api.twilio.com)
17
+ def self.host(host=nil)
18
+ return @host unless host
19
+ @host = host
20
+ end
21
+
22
+ attr_reader :account_sid, :last_request, :last_response
23
+
24
+ def initialize(*args)
25
+ options = args.last.is_a?(Hash) ? args.pop : {}
26
+ options[:host] ||= self.class.host
27
+ @config = Twilio::Util::ClientConfig.new options
28
+
29
+ @account_sid = args[0] || Twilio.account_sid
30
+ @auth_token = args[1] || Twilio.auth_token
31
+ if @account_sid.nil? || @auth_token.nil?
32
+ raise ArgumentError, 'Account SID and auth token are required'
33
+ end
34
+
35
+ set_up_connection
36
+ set_up_subresources
37
+ end
38
+
39
+ ##
40
+ # Define #get, #put, #post and #delete helper methods for sending HTTP
41
+ # requests to Twilio. You shouldn't need to use these methods directly,
42
+ # but they can be useful for debugging. Each method returns a hash
43
+ # obtained from parsing the JSON object in the response body.
44
+ [:get, :put, :post, :delete].each do |method|
45
+ method_class = Net::HTTP.const_get method.to_s.capitalize
46
+ define_method method do |path, *args|
47
+ params = twilify(args[0])
48
+ params = {} if params.empty?
49
+ # build the full path unless already given
50
+ path = build_full_path(path, params, method) unless args[1]
51
+ request = method_class.new(path, HTTP_HEADERS)
52
+ request.basic_auth(@account_sid, @auth_token)
53
+ request.form_data = params if [:post, :put].include?(method)
54
+ connect_and_send(request)
55
+ end
56
+ end
57
+
58
+ protected
59
+
60
+ ##
61
+ # Builds up full request path
62
+ # Needs implementation in child classes
63
+ def build_full_path(path, params, method)
64
+ raise NotImplementedError
65
+ end
66
+
67
+ ##
68
+ # Set up and cache a Net::HTTP object to use when making requests. This is
69
+ # a private method documented for completeness.
70
+ def set_up_connection # :doc:
71
+ connection_class = Net::HTTP::Proxy @config.proxy_addr,
72
+ @config.proxy_port, @config.proxy_user, @config.proxy_pass
73
+ @connection = connection_class.new @config.host, @config.port
74
+ set_up_ssl
75
+ @connection.open_timeout = @config.timeout
76
+ @connection.read_timeout = @config.timeout
77
+ end
78
+
79
+ ##
80
+ # Set up the ssl properties of the <tt>@connection</tt> Net::HTTP object.
81
+ # This is a private method documented for completeness.
82
+ def set_up_ssl # :doc:
83
+ @connection.use_ssl = @config.use_ssl
84
+ if @config.ssl_verify_peer
85
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
86
+ @connection.ca_file = @config.ssl_ca_file
87
+ else
88
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
89
+ end
90
+ end
91
+
92
+ ##
93
+ # Set up sub resources attributes.
94
+ def set_up_subresources # :doc:
95
+ # To be overridden
96
+ end
97
+
98
+ ##
99
+ # Send an HTTP request using the cached <tt>@connection</tt> object and
100
+ # return the JSON response body parsed into a hash. Also save the raw
101
+ # Net::HTTP::Request and Net::HTTP::Response objects as
102
+ # <tt>@last_request</tt> and <tt>@last_response</tt> to allow for
103
+ # inspection later.
104
+ def connect_and_send(request) # :doc:
105
+ @last_request = request
106
+ retries_left = @config.retry_limit
107
+ begin
108
+ response = @connection.request request
109
+ @last_response = response
110
+ if response.kind_of? Net::HTTPServerError
111
+ raise Twilio::REST::ServerError
112
+ end
113
+ rescue Exception
114
+ raise if request.class == Net::HTTP::Post
115
+ if retries_left > 0 then retries_left -= 1; retry else raise end
116
+ end
117
+ if response.body and !response.body.empty?
118
+ object = MultiJson.load response.body
119
+ end
120
+ if response.kind_of? Net::HTTPClientError
121
+ raise Twilio::REST::RequestError.new object['message'], object['code']
122
+ end
123
+ object
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,28 @@
1
+ module Twilio
2
+ module REST
3
+ class Feedback < ListResource;
4
+
5
+ ##
6
+ # Get this feedback object.
7
+ #
8
+ # Overridden because GETS to /Feedback
9
+ # returns an instance, not a list.
10
+ def get(params={}, full_path=false)
11
+ raise "Can't fetch feedback without a REST Client" unless @client
12
+ response = @client.get @path, params, full_path
13
+ path = full_path ? @path.split('.')[0] : @path
14
+ @instance_class.new path, @client, response
15
+ end
16
+
17
+ ##
18
+ # Creates a new Feedback object.
19
+ def create(params={})
20
+ raise "Can't create feedback without a REST Client" unless @client
21
+ response = @client.post @path, params
22
+ @instance_class.new @path, @client, response
23
+ end
24
+ end
25
+
26
+ class FeedbackInstance < InstanceResource; end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ module Twilio
2
+ module REST
3
+ class FeedbackSummary < ListResource
4
+ def initialize(path, client)
5
+ @path, @client = path, client
6
+ @instance_class = Twilio::REST::FeedbackSummaryInstance
7
+ @list_key, @instance_id_key = 'feedback_summary', 'sid'
8
+ end
9
+ end
10
+
11
+ class FeedbackSummaryInstance < InstanceResource; end
12
+ end
13
+ end
@@ -1,27 +1,32 @@
1
1
  module Twilio
2
2
  module REST
3
3
  class Calls < ListResource
4
+ def initialize(path, client)
5
+ super
6
+ resource :feedback_summary
7
+ end
8
+
4
9
  def make(from, to, url)
5
- create :from => from, :to => to, :url => url
10
+ create from: from, to: to, url: url
6
11
  end
7
12
  end
8
13
 
9
14
  class Call < InstanceResource
10
15
  def initialize(path, client, params={})
11
16
  super path, client, params
12
- resource :recordings, :notifications
17
+ resource :recordings, :notifications, :feedback
13
18
  end
14
19
 
15
20
  def redirect_to(url)
16
- update :url => url
21
+ update url: url
17
22
  end
18
23
 
19
24
  def cancel
20
- update :status => 'canceled'
25
+ update status: 'canceled'
21
26
  end
22
27
 
23
28
  def hangup
24
- update :status => 'completed'
29
+ update status: 'completed'
25
30
  end
26
31
  end
27
32
  end