tropo-webapi-ruby 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ $: << File.expand_path(File.dirname(__FILE__))
2
+ require 'uri'
3
+ require 'json'
4
+ require 'time'
5
+ require 'tropo-webapi-ruby/tropo-webapi-ruby-helpers'
6
+ require 'tropo-webapi-ruby/tropo-webapi-ruby'
@@ -0,0 +1,228 @@
1
+ module Tropo
2
+ module Helpers
3
+ private
4
+
5
+ ##
6
+ # Method checks for presence of required elements and then builds the action
7
+ #
8
+ # @param [String] the name of the action to build
9
+ # @param [Hash] the elements to be used to build the action
10
+ # @return [Hash] provides the properply built hash for the action
11
+ def build_action(action, params)
12
+ raise ArgumentError, 'Action requires parameters' if params.nil?
13
+
14
+ case action
15
+ when 'ask'
16
+ has_params?(params, 'ask', 'name')
17
+ when 'choices'
18
+ if params[:mode]
19
+ if params[:mode] != 'dtmf' && params[:mode] != 'speech'
20
+ raise ArgumentError, "If mode is provided, only 'dtmf', 'speech' or 'any' is supported"
21
+ end
22
+ end
23
+ when 'conference'
24
+ has_params?(params, 'conference', ['name', 'id'])
25
+ when 'on'
26
+ has_params?(params, 'on', 'event')
27
+ when 'record'
28
+ has_params?(params, 'record', ['name', 'url'])
29
+ when 'start_recording'
30
+ has_params?(params, 'start_recording', ['name', 'url'])
31
+
32
+ # Camelcase this one to be Java friendly
33
+ action = 'startRecording'
34
+ when 'redirect'
35
+ has_params?(params, 'redirect', 'to')
36
+ raise ArgumentError, "Redirect should only be used alone and before the session is answered, use transfer instead" if @nested_hash
37
+ when 'say'
38
+ has_params?(params, 'say', 'value')
39
+ return build_elements(params)
40
+ when 'transfer'
41
+ has_params?(params, 'transfer', 'to')
42
+ end
43
+
44
+ if action == 'on'
45
+ build_elements(params)
46
+ else
47
+ { action.to_sym => build_elements(params) }
48
+ end
49
+ end
50
+
51
+ ##
52
+ # Checks to see if certain parameters are present, and if not raises an error
53
+ #
54
+ # @overload has_params?(params, action, names)
55
+ # @param [Hash] the parameter hash to be checked for the presence of a parameter
56
+ # @param [String] the action being checked
57
+ # @param [String] the name of the key in the params that must be present
58
+ # @overload has_params?(params, action, names)
59
+ # @param [Hash] the parameter hash to be checked for the presence of a parameter
60
+ # @param [String] the action being checked
61
+ # @param [Array] a list of names of the keys in the params that must be present
62
+ def has_params?(params, action, names)
63
+ if names.kind_of? Array
64
+ names.each { |name| raise ArgumentError, "A '#{name}' must be provided to a '#{action}' action" if params[name.to_sym].nil? }
65
+ else
66
+ raise ArgumentError, "A '#{names}' must be provided to a '#{action}' action" if params[names.to_sym].nil?
67
+ end
68
+ end
69
+
70
+ # Takes a Ruby underscore string and converts to a Java friendly camelized string
71
+ #
72
+ # @param [String] the string to be camelized
73
+ # @return [String] the Ruby string camelized
74
+ def camelize(ruby_string)
75
+ split_string = ruby_string.split('_')
76
+ split_string[0] + split_string[1].capitalize
77
+ end
78
+
79
+ ##
80
+ # Creates a nested hash when we have block within a block
81
+ #
82
+ # @param [String] the name of the action being built
83
+ # @param [Hash] the parameters to be added to the action
84
+ # @return [nil]
85
+ def create_nested_hash(name, params)
86
+ @nested_hash = build_action(name, params)
87
+ @nested_name = name
88
+ end
89
+
90
+ ##
91
+ # Creates a nested hash specfic to 'on', as an on may have an additional block
92
+ #
93
+ # @param [Hash] the parameters to be added to the instance of the 'on' action
94
+ # @return [nil]
95
+ def create_nested_on_hash(params)
96
+ @nested_on_hash ||= { :on => Array.new }
97
+ @nested_on_hash_cnt ||= 0
98
+ @nested_on_hash[:on] << params
99
+ end
100
+
101
+ ##
102
+ # Creates an on_hash for the on action
103
+ #
104
+ # @return [nil]
105
+ def create_on_hash
106
+ @on_hash ||= { :on => Array.new }
107
+ end
108
+
109
+ ##
110
+ # Method builds the elements for each of the actions
111
+ #
112
+ # @param [Hash] the individual elements to be used to build the hash
113
+ # @return [Hash] returns the elements properly formatted in a hash
114
+ def build_elements(params)
115
+ if params[:url]
116
+ uri = URI.parse params[:url]
117
+ # Check to see if it is a valid http address
118
+ if uri.class != URI::HTTP
119
+ # Check to see if it is a valid email address
120
+ if params[:url].match(/^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/) == false
121
+ raise ArgumentError, "The 'url' paramater must be a valid URL"
122
+ end
123
+ end
124
+ end
125
+
126
+ hash = Hash.new
127
+ params.each_pair do |k,v|
128
+ if k.to_s.include? "_"
129
+ k = camelize k.to_s
130
+ k = k.to_sym
131
+ end
132
+ hash.merge!({ k => v })
133
+ end
134
+ hash
135
+ end
136
+
137
+ ##
138
+ # Takes a Java Camelized string and converts to an underscore string
139
+ #
140
+ # @param [String] the string to be de-camelized
141
+ # @return [String] the Ruby string with an underscore and no capitals
142
+ def decamelize(camel_string)
143
+ camel_string.gsub(/[A-Z]/) { |char| '_' + char.downcase }
144
+ end
145
+
146
+ ##
147
+ # Formats the @response instance variable to JSON before making it available to the accessor
148
+ #
149
+ # @return [nil]`
150
+ def render_response
151
+ @response.to_json
152
+ end
153
+
154
+ ##
155
+ # Returns an hash from a collapsed array, using the values of 'key' or 'name' as the collpassed hash key
156
+ #
157
+ # @param [Array] the array of values to collapse into a Hash
158
+ # @return [Hash] the collapsed Hash
159
+ def transform_array(array)
160
+ transformed_to_hash = Hash.new
161
+
162
+ array.each_with_index do |ele, i|
163
+ # Set the key to the value of the respresentative key
164
+ key = ele['key'].to_sym if ele['key']
165
+ key = ele['name'].to_sym if ele['name']
166
+
167
+ # Merge this new key into the hash
168
+ transformed_to_hash.merge!({ key => Hash.new })
169
+
170
+ # Then add the corresponding key/values to this new hash
171
+ ele.each_pair do |k, v|
172
+ if k != 'key' && k != 'name'
173
+ transformed_to_hash[key].merge!(transform_pair(k, v))
174
+ end
175
+ end
176
+ end
177
+
178
+ transformed_to_hash
179
+ end
180
+
181
+ ##
182
+ # Transforms a hash into the appropriatey formatted hash with no camelcase and keys as symbols
183
+ #
184
+ # @param [Hash] Hash to be transformed
185
+ # @return [Hash] the transformed hash
186
+ def transform_hash(hash)
187
+ transformed_hash = Hash.new
188
+ hash.each_pair { |k, v| transformed_hash.merge!(transform_pair(k, v)) }
189
+ transformed_hash
190
+ end
191
+
192
+ ##
193
+ # Transforms a single keypair into a decamelized symbol with the appropriate value. Also converts
194
+ # any timestamps to a Ruby Time object
195
+ #
196
+ # @param[String] the key to be decamelized and symobolized
197
+ # @param[Hash] the newly created hash that contins the properly formatted key
198
+ def transform_pair(key, value)
199
+ hash = { decamelize(key).to_sym => value }
200
+ hash[:timestamp] = Time.parse(value) if hash[:timestamp]
201
+ if hash[:actions]
202
+ if hash[:actions][:name]
203
+ key_name = hash[:actions][:name]
204
+ hash[:actions].delete(:name)
205
+ hash[:actions] = { key_name.to_sym => hash[:actions] }
206
+ end
207
+ end
208
+ set_session_type(hash) if hash[:channel]
209
+ hash
210
+ end
211
+
212
+ ##
213
+ # Sets the session type instance variables of voice_session and text_session
214
+ #
215
+ # @param[Hash] the key, value pair of the channel
216
+ # @return nil
217
+ def set_session_type(hash)
218
+ case hash[:channel]
219
+ when "VOICE"
220
+ @voice_session = true
221
+ @text_session = false
222
+ when "TEXT"
223
+ @text_session = true
224
+ @voice_session = false
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,438 @@
1
+ # @author Jason Goecke
2
+ module Tropo
3
+ class Generator
4
+ include Tropo::Helpers
5
+
6
+ ##
7
+ # Set a couple of Booleans to indicate the session type as a convenience
8
+ attr_reader :voice_session, :text_session
9
+
10
+ ##
11
+ # Defines the actions on self so that we may call them individually
12
+ #
13
+ # @return [nil]
14
+ class << self
15
+ def method_missing(method_id, *args, &block)
16
+ g = Generator.new
17
+ g.send(method_id, *args, &block)
18
+ end
19
+ end
20
+
21
+ ##
22
+ # Initializes the Generator class
23
+ #
24
+ # @overload initialize()
25
+ # @overload initialize(params)
26
+ # @param [Object] pass in an object that may be accessed inside the block
27
+ # @overload initialize(params, &block)
28
+ # @param [Object] pass in an object that may be accessed inside the block
29
+ # @param [Block] a block of code to execute (optional)
30
+ # @return [Object] a new Generator object
31
+ def initialize(params=nil, &block)
32
+ @response = { :tropo => Array.new }
33
+ if block_given?
34
+ # Lets us know were are in the midst of building a block, so we only rendor the JSON
35
+ # response at the end of executing the block, rather than at each action
36
+ @building = true
37
+ instance_exec(&block)
38
+ render_response
39
+ end
40
+ end
41
+
42
+ ##
43
+ # Prompts the user (audio file or text to speech) and optionally waits for a response from the user.
44
+ # If collected, responses may be in the form of DTMF, speech recognition or text using a grammar or
45
+ # free-form text.
46
+ #
47
+ # @overload ask(params)
48
+ # @param [Hash] params the options to create an ask action request with.
49
+ # @option params [String] :name the name to assign to the result when returned to the application, default is true
50
+ # @option params [optional, Integer] :attempts (1) the number of times to prompt the user for input
51
+ # @option params [optional, Boolean] :bargein (true) allows a user to enter a key to stop the ask action
52
+ # @option params [optional, Float] :min_confidence (.5) the minimum confidence by which to accept the response expressed from 0-1, as opposed to asking again
53
+ # @option params [optional, Boolean] :required (true) if this is a field that must be completed by the user
54
+ # @option params [optional, Integer] :timeout (30) the amount of time, in seconds, to wait for a response before moving on
55
+ # @overload ask(params, &block)
56
+ # @param [Hash] params the options to create an ask action request with.
57
+ # @param [Block] takes a block so that you may trigger actions, such as a say, on a specific event
58
+ # @option params [String] :name the name to assign to the result when returned to the application
59
+ # @option params [optional, Integer] :attempts (1) the number of times to prompt the user for input
60
+ # @option params [optional, Boolean] :bargein (true) allows a user to enter a key to stop the ask action
61
+ # @option params [optional, Float] :min_confidence (.5) the minimum confidence by which to accept the response expressed from 0-1, as opposed to asking again
62
+ # @option params [optional, Boolean] :required (true) if this is a field that must be completed by the user
63
+ # @option params [optional, Integer] :timeout (30) the amount of time, in seconds, to wait for a response before moving on
64
+ # @return [String, nil] the JSON string to be passed back to Tropo or nil
65
+ # if the method has been called from inside a block
66
+ def ask(params={}, &block)
67
+ if block_given?
68
+ create_nested_hash('ask', params)
69
+ instance_exec(&block)
70
+ @response[:tropo] << @nested_hash
71
+ else
72
+ hash = build_action('ask', params)
73
+ @response[:tropo] << hash
74
+ end
75
+ render_response if @building.nil?
76
+ end
77
+ alias :prompt :ask
78
+
79
+ ##
80
+ # Choices to give the user on input
81
+ #
82
+ # @param [Hash] params the options used to construct the grammar for the user
83
+ # @option params [String] :value the name to assign to the result when returned to the app
84
+ # @option params [optional, String] :mode (ANY) the mode to use when asking the user [DTMF, SPEECH or ANY]
85
+ # @option params [optional, String] :term_char the user may enter a keypad entry to stop the request
86
+ # @option params [optional, String] :type (simple/grammar) the type of grammar to use
87
+ # @option [String, nil] the JSON string to be passed back to Tropo or nil
88
+ # if the method has been called from inside a block
89
+ def choices(params={})
90
+ hash = build_action('choices', params)
91
+
92
+ if @nested_hash
93
+ @nested_hash[@nested_name.to_sym].merge!(hash)
94
+ else
95
+ @response[:tropo] << hash
96
+ render_response if @building.nil?
97
+ end
98
+ end
99
+
100
+ ##
101
+ # Creates a conference or pushes a user to an existing conference
102
+ #
103
+ # @overload conference(params)
104
+ # @param [Hash] params the options to create a message with.
105
+ # @option params [String] :name the name to assign to the conference room and to identify events back to the application
106
+ # @option params [Integer] :id the number to assign to the conference room
107
+ # @option params [optional, Boolean] :mute (false) whether to mute this caller in the conference
108
+ # @option params [optional, Integer] :max_time the maximum time, in seconds, to allow this user to stay in conference
109
+ # @option params [optional, Integer] :send_tones whether to send the DTMF a user may enter to the audio of the conference
110
+ # @option params [optional, String] :exit_tone whether to play a beep when this user exits a conference
111
+ # @overload conference(params, &block)
112
+ # @param [Hash] params the options to create a message with.
113
+ # @param [Block] takes a block so that you may trigger actions, such as a say, on a specific event
114
+ # @option params [String] :name the name to assign to the conference room and to identify events back to the application
115
+ # @option params [Integer] :id the number to assign to the conference room
116
+ # @option params [optional, Boolean] :mute (false) whether to mute this caller in the conference
117
+ # @option params [optional, Integer] :max_time the maximum time, in seconds, to allow this user to stay in conference
118
+ # @option params [optional, Integer] :send_tones whether to send the DTMF a user may enter to the audio of the conference
119
+ # @option params [optional, String] :exit_tone whether to play a beep when this user exits a conference
120
+ # @return [String, nil] the JSON string to be passed back to Tropo or nil
121
+ # if the method has been called from inside a block
122
+ def conference(params={}, &block)
123
+ if block_given?
124
+ create_nested_hash('conference', params)
125
+ instance_exec(&block)
126
+ @response[:tropo] << @nested_hash
127
+ else
128
+ hash = build_action('conference', params)
129
+ @response[:tropo] << hash
130
+ end
131
+ render_response if @building.nil?
132
+ end
133
+
134
+ ##
135
+ # This function instructs Tropo to "hang-up" or disconnect the current session.
136
+ #
137
+ # May trigger these events:
138
+ # - hangup
139
+ # - error
140
+ #
141
+ # @return [String, nil] returns the JSON string to hangup/stop the current session or nil
142
+ # if the method has been called from inside a block
143
+ def hangup
144
+ @response[:tropo] << { :hangup => nil }
145
+ render_response if @building.nil?
146
+ end
147
+ alias :disconnect :hangup
148
+
149
+ ##
150
+ # Sets event handlers to call a REST resource when a particular event occurs
151
+ #
152
+ # @overload initialize(params)
153
+ # @param [Hash] params the options to create a message with.
154
+ # @option params [String] :event the event name that should trigger the callback
155
+ # @option params [String] :next the resource to send the callback to, such as '/error.json'
156
+ # @overload initialize(params, &block)
157
+ # @param [Hash] params the options to create a message with.
158
+ # @option params [String] :event the event name that should trigger the callback
159
+ # @option params [String] :next the resource to send the callback to, such as '/error.json'
160
+ # @param [Block] takes a block so that you may trigger actions, such as a say, on a specific event
161
+ # @option [String, nil] the JSON string to be passed back to Tropo or nil
162
+ # if the method has been called from inside a block
163
+ def on(params={}, &block)
164
+ if block_given?
165
+ create_nested_on_hash(params)
166
+ instance_exec(&block)
167
+ if @nested_hash
168
+ @nested_hash[@nested_name.to_sym].merge!(@nested_on_hash)
169
+ end
170
+ else
171
+ create_on_hash
172
+ hash = build_action('on', params)
173
+ @on_hash[:on] << hash
174
+ if @nested_hash
175
+ @nested_hash[@nested_name.to_sym].merge!(@on_hash)
176
+ else
177
+ @response[:tropo] << { :on => hash }
178
+ render_response if @building.nil?
179
+ end
180
+ end
181
+ end
182
+
183
+ ##
184
+ # Parses the JSON string recieved from Tropo into a Ruby Hash
185
+ #
186
+ # @param [String] a JSON string
187
+ # @return [Hash] a Hash representing the response from Tropo
188
+ def parse(json_string)
189
+ response = JSON.parse json_string
190
+
191
+ # Check to see what type of response we are working with
192
+ if response['session']
193
+ transformed_response = { :session => { } }
194
+
195
+ response['session'].each_pair do |key, value|
196
+ value = transform_hash value if value.kind_of? Hash
197
+ transformed_response[:session].merge!(transform_pair(key, value))
198
+ end
199
+
200
+ elsif response['result']
201
+ transformed_response = { :result => { :actions => { } } }
202
+
203
+ response['result'].each_pair do |key, value|
204
+ value = transform_hash value if value.kind_of? Hash
205
+ value = transform_array value if value.kind_of? Array
206
+ transformed_response[:result].merge!(transform_pair(key, value))
207
+ end
208
+ end
209
+
210
+ transformed_response
211
+ end
212
+
213
+ ##
214
+ # Plays a prompt (audio file or text to speech) and optionally waits for a response from the caller that is recorded.
215
+ # If collected, responses may be in the form of DTMF or speech recognition using a simple grammar format defined below.
216
+ # The record funtion is really an alias of the prompt function, but one which forces the record option to true regardless of how it is (or is not) initially set.
217
+ # At the conclusion of the recording, the audio file may be automatically sent to an external server via FTP or an HTTP POST/Multipart Form.
218
+ # If specified, the audio file may also be transcribed and the text returned to you via an email address or HTTP POST/Multipart Form.
219
+ #
220
+ # @overload record(params)
221
+ # @param [Hash] params the options to create a message with.
222
+ # @option params [String] :name the event name that should trigger the callback
223
+ # @option params [String] :url a valid URI, an HTTP, FTP or email address to POST the recording file to
224
+ # @option params [optional, String] :format (audio/wav) the audio format to record in, either a wav or mp3
225
+ # @option params [optional, String] :username if posting to FTP, the username for the FTP server
226
+ # @option params [optional, String] :password if posting to FTP, the password for the FTP server
227
+ # @overload record(params, &block)
228
+ # @param [Hash] params the options to create a message with.
229
+ # @param [Block] takes a block so that you may trigger actions, such as a say, on a specific event
230
+ # @option params [String] :name the event name that should trigger the callback
231
+ # @option params [String] :url a valid URI, an HTTP, FTP or email address to POST the recording file to
232
+ # @option params [optional, String] :format (audio/wav) the audio format to record in, either a wav or mp3
233
+ # @option params [optional, String] :username if posting to FTP, the username for the FTP server
234
+ # @option params [optional, String] :password if posting to FTP, the password for the FTP server
235
+ # @option [String, nil] the JSON string to be passed back to Tropo or nil
236
+ # if the method has been called from inside a block
237
+ def record(params={}, &block)
238
+ if block_given?
239
+ create_nested_hash('record', params)
240
+ instance_exec(&block)
241
+ @response[:tropo] << @nested_hash
242
+ else
243
+ hash = build_action('record', params)
244
+ @response[:tropo] << hash
245
+ end
246
+ render_response if @building.nil?
247
+ end
248
+
249
+ ##
250
+ # The redirect function forwards an incoming call to another destination / phone number before answering it.
251
+ # The redirect function must be called before answer is called; redirect expects that a call be in the ringing or answering state.
252
+ # Use transfer when working with active answered calls.
253
+ #
254
+ # tel: classic phone number (See RFC 2896), must be proceeded by a + and the country code (ie - +14155551212 for a US #)
255
+ # sip: Session Initiation Protocol (SIP) address
256
+ #
257
+ # @param [Hash] params the options to create a message with.
258
+ # @option params [required, String] :to where to redirect the session to
259
+ # @option params [optional, String] :from set the from id for the session when redirecting
260
+ # @return [String, nil] the JSON string to redirect the current session or nil
261
+ # if the method has been called from inside a block
262
+ def redirect(params={})
263
+ hash = build_action('redirect', params)
264
+ @response[:tropo] << hash
265
+ render_response if @building.nil?
266
+ end
267
+
268
+ ##
269
+ # Allows Tropo applications to reject incoming calls before they are answered.
270
+ # For example, an application could inspect the callerID variable to determine if the caller is known,
271
+ # and then use the reject call accordingly.
272
+ #
273
+ # @return [String, nil] the JSON string to reject the current session or nil
274
+ # if the method has been called from inside a block
275
+ def reject
276
+ @response[:tropo] << { :reject => nil }
277
+ render_response if @building.nil?
278
+ end
279
+
280
+ ##
281
+ # Renders the JSON string to be sent to Tropo to execute a set of actions
282
+ #
283
+ # @return [String] the JSON string to be sent to the Tropo Remote API
284
+ def response
285
+ @response.to_json
286
+ end
287
+
288
+ ##
289
+ # Resets the action hash if one desires to reuse the same Generator object
290
+ #
291
+ # @return [nil]
292
+ def reset
293
+ @response = { :tropo => Array.new }
294
+ @voice_session = false
295
+ @text_session = false
296
+ end
297
+
298
+ ##
299
+ # Plays a prompt (audio file, text to speech or text for IM/SMS). There is no ability to wait for a response from a user.
300
+ # An audio file used for playback may be in one of the following two formats:
301
+ # Wav 8bit 8khz Ulaw
302
+ # MP3
303
+ #
304
+ # @overload say(params)
305
+ # @param [Hash] params the options to create a message with.
306
+ # @option params [String] :value the text or audio to be spoken or played back to the user
307
+ # @option params [Boolean] :event assigns a callback when a particular event occurs
308
+ # @option params [Integer] :as instructs the engine on how to handle the grammar
309
+ # @option params [Boolean] :format instructs the engine on how to handle the grammar
310
+ # @return [String, nil] the JSON string to be passed back to Tropo or nil
311
+ # if the method has been called from inside a block
312
+ # @overload say(value, params)
313
+ # @param [String] the text or audio to be spoken or played back to the user
314
+ # @param [Hash] params the options to create a message with.
315
+ # @option params [Boolean] :event assigns a callback when a particular event occurs
316
+ # @option params [Integer] :as instructs the engine on how to handle the grammar
317
+ # @option params [Boolean] :format instructs the engine on how to handle the grammar
318
+ # @return [String, nil] the JSON string to be passed back to Tropo or nil
319
+ # if the method has been called from inside a block
320
+ def say(value=nil, params={})
321
+
322
+ # This will allow a string to be passed to the say, as opposed to always having to specify a :value key/pair,
323
+ # or still allow a hash or Array to be passed as well
324
+ if value.kind_of? String
325
+ params[:value] = value
326
+ elsif value.kind_of? Hash
327
+ params = value
328
+ elsif value.kind_of? Array
329
+ params = value
330
+ else
331
+ raise ArgumentError, "An invalid paramater type #{value.class} has been passed"
332
+ end
333
+
334
+ response = { :say => Array.new }
335
+
336
+ if params.kind_of? Array
337
+ params.each do |param|
338
+ hash = build_action('say', param)
339
+ response[:say] << hash
340
+ end
341
+ else
342
+ hash = build_action('say', params)
343
+ response[:say] << hash
344
+ end
345
+
346
+ if @nested_hash && @nested_on_hash.nil?
347
+ @nested_hash[@nested_name.to_sym].merge!(response)
348
+ elsif @nested_on_hash
349
+ @nested_on_hash[:on][@nested_on_hash_cnt].merge!(response)
350
+ @nested_on_hash_cnt += 1
351
+ else
352
+ @response[:tropo] << response
353
+ render_response if @building.nil?
354
+ end
355
+ end
356
+
357
+ ##
358
+ # Allows Tropo applications to begin recording the current session.
359
+ # The resulting recording may then be sent via FTP or an HTTP POST/Multipart Form.
360
+ #
361
+ # @param [Hash] params the options to create a message with.
362
+ # @option params [String] :url a valid URI, an HTTP, FTP or email address to POST the recording file to
363
+ # @option params [optional, String] :format (audio/wav) the audio format to record in, either a wav or mp3
364
+ # @option params [optional, String] :username if posting to FTP, the username for the FTP server
365
+ # @option params [optional, String] :password if posting to FTP, the password for the FTP server
366
+ # @return [String, nil] returns the JSON string to start the recording of a session or nil
367
+ # if the method has been called from inside a block
368
+ def start_recording(params={})
369
+ if block_given?
370
+ create_nested_hash('start_recording', params)
371
+ instance_exec(&block)
372
+ @response[:tropo] << @nested_hash
373
+ else
374
+ hash = build_action('start_recording', params)
375
+ @response[:tropo] << hash
376
+ end
377
+ render_response if @building.nil?
378
+ end
379
+
380
+ ##
381
+ # Stops the recording of the current session after startCallRecording has been called
382
+ #
383
+ # @return [String, nil] returns the JSON string to stop the recording of a session or nil
384
+ # if the method has been called from inside a block
385
+ def stop_recording
386
+ @response[:tropo] << { :stopRecording => nil }
387
+ render_response if @building.nil?
388
+ end
389
+
390
+ ##
391
+ # Transfers an already answered call to another destination / phone number.
392
+ # Call may be transferred to another phone number or SIP address, which is set through the "to" parameter and is in URL format.
393
+ # Supported formats include:
394
+ # tel: classic phone number (See RFC 2896), must be proceeded by a + and the country code (ie - +14155551212 for a US #)
395
+ # sip: SIP protocol address
396
+ #
397
+ # When this method is called the following occurs:
398
+ # The audio file specified in playvalue is played to the existing call. This could be "hold music", a ring-back sound, etc. The audio file is played up to playrepeat times.
399
+ # While audio is playing, a new call is initiated to the specified "to" address using the callerID specified.
400
+ # If answerOnMedia is true, the audio from the new call is connected to the existing call immediately.
401
+ # The system waits for an answer or other event from the new call up to the timeout.
402
+ # If the call successfully completes within the timeout, the existing call and new call will be connected, onSuccess will be called, and the transfer call will return a success event.
403
+ # If the call fails before the timeout, onCallFailure will be called and the method will return an onCallFailure event.
404
+ # If the call fails due to the timeout elapsing, onTimeout will be called and the method will return a timeout event
405
+ #
406
+ # @overload transfer(params)
407
+ # @param [Hash] params the options to create a transfer action request with
408
+ # @option params [String] :name the name to assign to the result when returned to the application, default is true
409
+ # @option params [optional, Boolean] :answer_on_media ???
410
+ # @option params [optional, Integer] :answer_timeout the amount of time to ring the far side before giving up and going to the next step
411
+ # @option params [optional, Boolean] :required (true) ???
412
+ # @option params [required, String] :to where to redirect the session to
413
+ # @option params [optional, String] :from set the from id for the session when redirecting
414
+ # @option params [optional, Integer] :ring_repeat ???
415
+ # @overload transfer(params, &block)
416
+ # @param [Hash] params the options to create a transfer action request with
417
+ # @option params [String] :name the name to assign to the result when returned to the application, default is true
418
+ # @option params [optional, Boolean] :answer_on_media ???
419
+ # @option params [optional, Integer] :answer_timeout the amount of time to ring the far side before giving up and going to the next step
420
+ # @option params [optional, Boolean] :required (true) ???
421
+ # @option params [required, String] :to where to redirect the session to
422
+ # @option params [optional, String] :from set the from id for the session when redirecting
423
+ # @option params [optional, Integer] :ring_repeat ???
424
+ # @return [nil, String]
425
+ def transfer(params={}, &block)
426
+ if block_given?
427
+ create_nested_hash('transfer', params)
428
+ instance_exec(&block)
429
+ @response[:tropo] << @nested_hash
430
+ else
431
+ hash = build_action('transfer', params)
432
+ @response[:tropo] << hash
433
+ end
434
+ render_response if @building.nil?
435
+ end
436
+
437
+ end
438
+ end