plivo 0.3.19 → 4.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +11 -0
  5. data/AUTHORS.md +4 -0
  6. data/CHANGELOG.md +158 -0
  7. data/Gemfile +10 -0
  8. data/Jenkinsfile +7 -0
  9. data/LICENSE.txt +19 -0
  10. data/README.md +155 -24
  11. data/Rakefile +9 -0
  12. data/ci/config.yml +7 -0
  13. data/examples/conference_bridge.rb +108 -0
  14. data/examples/jwt.rb +32 -0
  15. data/examples/lookup.rb +24 -0
  16. data/examples/multi_party_call.rb +295 -0
  17. data/examples/phlos.rb +55 -0
  18. data/examples/regulatory_compliance.rb +167 -0
  19. data/lib/plivo/base/resource.rb +148 -0
  20. data/lib/plivo/base/resource_interface.rb +108 -0
  21. data/lib/plivo/base/response.rb +38 -0
  22. data/lib/plivo/base.rb +17 -0
  23. data/lib/plivo/base_client.rb +393 -0
  24. data/lib/plivo/exceptions.rb +50 -0
  25. data/lib/plivo/jwt.rb +120 -0
  26. data/lib/plivo/phlo_client.rb +29 -0
  27. data/lib/plivo/resources/accounts.rb +181 -0
  28. data/lib/plivo/resources/addresses.rb +302 -0
  29. data/lib/plivo/resources/applications.rb +258 -0
  30. data/lib/plivo/resources/call_feedback.rb +55 -0
  31. data/lib/plivo/resources/calls.rb +559 -0
  32. data/lib/plivo/resources/conferences.rb +367 -0
  33. data/lib/plivo/resources/endpoints.rb +132 -0
  34. data/lib/plivo/resources/identities.rb +319 -0
  35. data/lib/plivo/resources/lookup.rb +88 -0
  36. data/lib/plivo/resources/media.rb +97 -0
  37. data/lib/plivo/resources/messages.rb +215 -0
  38. data/lib/plivo/resources/multipartycalls.rb +554 -0
  39. data/lib/plivo/resources/nodes.rb +83 -0
  40. data/lib/plivo/resources/numbers.rb +319 -0
  41. data/lib/plivo/resources/phlo_member.rb +64 -0
  42. data/lib/plivo/resources/phlos.rb +55 -0
  43. data/lib/plivo/resources/powerpacks.rb +717 -0
  44. data/lib/plivo/resources/pricings.rb +43 -0
  45. data/lib/plivo/resources/recordings.rb +116 -0
  46. data/lib/plivo/resources/regulatory_compliance.rb +610 -0
  47. data/lib/plivo/resources.rb +25 -0
  48. data/lib/plivo/rest_client.rb +63 -0
  49. data/lib/plivo/utils.rb +294 -0
  50. data/lib/plivo/version.rb +3 -0
  51. data/lib/plivo/xml/break.rb +31 -0
  52. data/lib/plivo/xml/conference.rb +20 -0
  53. data/lib/plivo/xml/cont.rb +13 -0
  54. data/lib/plivo/xml/dial.rb +16 -0
  55. data/lib/plivo/xml/dtmf.rb +13 -0
  56. data/lib/plivo/xml/element.rb +106 -0
  57. data/lib/plivo/xml/emphasis.rb +17 -0
  58. data/lib/plivo/xml/get_digits.rb +15 -0
  59. data/lib/plivo/xml/get_input.rb +16 -0
  60. data/lib/plivo/xml/hangup.rb +12 -0
  61. data/lib/plivo/xml/lang.rb +29 -0
  62. data/lib/plivo/xml/message.rb +13 -0
  63. data/lib/plivo/xml/multipartycall.rb +188 -0
  64. data/lib/plivo/xml/number.rb +13 -0
  65. data/lib/plivo/xml/p.rb +12 -0
  66. data/lib/plivo/xml/phoneme.rb +20 -0
  67. data/lib/plivo/xml/play.rb +13 -0
  68. data/lib/plivo/xml/plivo_xml.rb +19 -0
  69. data/lib/plivo/xml/pre_answer.rb +12 -0
  70. data/lib/plivo/xml/prosody.rb +28 -0
  71. data/lib/plivo/xml/record.rb +17 -0
  72. data/lib/plivo/xml/redirect.rb +13 -0
  73. data/lib/plivo/xml/response.rb +21 -0
  74. data/lib/plivo/xml/s.rb +12 -0
  75. data/lib/plivo/xml/say_as.rb +24 -0
  76. data/lib/plivo/xml/speak.rb +28 -0
  77. data/lib/plivo/xml/sub.rb +16 -0
  78. data/lib/plivo/xml/user.rb +13 -0
  79. data/lib/plivo/xml/w.rb +17 -0
  80. data/lib/plivo/xml/wait.rb +12 -0
  81. data/lib/plivo/xml.rb +39 -0
  82. data/lib/plivo.rb +12 -815
  83. data/plivo.gemspec +44 -0
  84. metadata +181 -41
  85. data/ext/mkrf_conf.rb +0 -9
@@ -0,0 +1,294 @@
1
+ require 'openssl'
2
+ require 'uri'
3
+ require 'base64'
4
+
5
+ module Plivo
6
+ # Utils module
7
+ module Utils
8
+ module_function
9
+
10
+ TYPE_WHITELIST = [Integer]
11
+ TYPE_WHITELIST.push(Fixnum, Bignum) unless 1.class == Integer
12
+
13
+ def valid_account?(account_id, raise_directly = false)
14
+ valid_subaccount?(account_id, raise_directly) || valid_mainaccount?(account_id, raise_directly)
15
+ end
16
+
17
+ # @param [String] account_id
18
+ # @param [Boolean] raise_directly
19
+ def valid_subaccount?(account_id, raise_directly = false)
20
+ unless account_id.is_a? String
21
+ return false unless raise_directly
22
+ raise_invalid_request('subaccount_id must be a string')
23
+ end
24
+
25
+ if account_id.length != 20
26
+ return false unless raise_directly
27
+ raise_invalid_request('subaccount_id should be of length 20')
28
+ end
29
+
30
+ if account_id[0..1] != 'SA'
31
+ return false unless raise_directly
32
+ raise_invalid_request("subaccount_id should start with 'SA'")
33
+ end
34
+ true
35
+ end
36
+
37
+ def valid_mainaccount?(account_id, raise_directly = false)
38
+ unless account_id.is_a? String
39
+ return false unless raise_directly
40
+ raise_invalid_request('account_id must be a string')
41
+ end
42
+
43
+ if account_id.length != 20
44
+ return false unless raise_directly
45
+ raise_invalid_request('account_id should be of length 20')
46
+ end
47
+
48
+ if account_id[0..1] != 'MA'
49
+ return false unless raise_directly
50
+ raise_invalid_request("account_id should start with 'SA'")
51
+ end
52
+ true
53
+ end
54
+
55
+ def raise_invalid_request(message = '')
56
+ raise Exceptions::InvalidRequestError, message
57
+ end
58
+
59
+ def valid_param?(param_name, param_value, expected_types = nil, mandatory = false, expected_values = nil)
60
+ if mandatory && param_value.nil?
61
+ raise_invalid_request("#{param_name} is a required parameter")
62
+ end
63
+
64
+ return true if param_value.nil?
65
+
66
+ return expected_type?(param_name, expected_types, param_value) unless expected_values
67
+ expected_value?(param_name, expected_values, param_value)
68
+ end
69
+
70
+ def valid_multiple_destination_nos?(param_name, param_value, options = nil)
71
+ if param_value.split(options[:delimiter]).size > 1 && options[:role].downcase != 'agent'
72
+ raise_invalid_request("Multiple #{param_name} values given for role #{options[:role]}")
73
+ elsif param_value.split(options[:delimiter]).size >= options[:agent_limit]
74
+ raise_invalid_request("No of #{param_name} values provided should be lesser than #{options[:agent_limit]}")
75
+ else
76
+ return true
77
+ end
78
+ end
79
+
80
+ def valid_multiple_destination_integers?(param_name, param_value)
81
+ if (param_value.is_a? String)
82
+ values = param_value.split("<")
83
+ for i in values
84
+ unless (Integer(i) rescue false)
85
+ raise_invalid_request("#{param_name} Destination Value must be integer")
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ def valid_url?(param_name, param_value, mandatory = false)
92
+ if mandatory && param_value.nil?
93
+ raise_invalid_request("#{param_name} is a required parameter")
94
+ end
95
+
96
+ return true if param_value.nil?
97
+ return raise_invalid_request("#{param_name}: Expected a String but received #{param_value.class} instead") unless expected_type?(param_name, String, param_value)
98
+
99
+ if param_value =~ /^(http[s]?:\/\/([a-zA-Z]|[0-9]|[\$\-\_\@\.\&\+\/\#]|[\!\*\(\)\,]|(%[0-9a-fA-F][0-9a-fA-F]))+|nil)$/ix
100
+ return true
101
+ else
102
+ return raise_invalid_request("Invalid URL : Doesn't satisfy the URL format")
103
+ end
104
+ end
105
+
106
+ def valid_range?(param_name, param_value, mandatory = false, lower_bound = nil, upper_bound = nil)
107
+ if mandatory && param_value.nil?
108
+ raise_invalid_request("#{param_name} is a required parameter")
109
+ end
110
+
111
+ return true if param_value.nil?
112
+
113
+ return raise_invalid_request("#{param_name}: Expected an Integer but received #{param_value.class} instead") unless expected_type?(param_name, Integer, param_value)
114
+ if lower_bound && upper_bound
115
+ return raise_invalid_request("#{param_name} ranges between #{lower_bound} and #{upper_bound}") if param_value < lower_bound or param_value > upper_bound
116
+
117
+ return true if param_value >= lower_bound and param_value <= upper_bound
118
+ elsif lower_bound
119
+ return raise_invalid_request("#{param_name} should be greater than #{lower_bound}") if param_value < lower_bound
120
+
121
+ return true if param_value >= lower_bound
122
+ elsif upper_bound
123
+ return raise_invalid_request("#{param_name} should be lesser than #{upper_bound}") if param_value > upper_bound
124
+
125
+ return true if param_value <= upper_bound
126
+ else
127
+ return raise_invalid_request("Any one or both of lower and upper bound should be provided")
128
+ end
129
+ end
130
+
131
+ def multi_valid_param?(param_name, param_value, expected_types = nil, mandatory = false, expected_values = nil, make_down_case = false, seperator = ',')
132
+ if mandatory && param_value.nil?
133
+ raise_invalid_request("#{param_name} is a required parameter")
134
+ end
135
+
136
+ return true if param_value.nil?
137
+
138
+ if make_down_case
139
+ param_value = param_value.downcase
140
+ else
141
+ param_value = param_value.uppercase
142
+ end
143
+
144
+ for val in param_value.split(seperator)
145
+ return expected_type?(param_name, expected_types, val.strip) unless expected_values
146
+ expected_value?(param_name, expected_values, val.strip)
147
+ end
148
+ end
149
+
150
+ def valid_date_format?(param_name, param_value, mandatory = false)
151
+ if mandatory && param_value.nil?
152
+ raise_invalid_request("#{param_name} is a required parameter")
153
+ end
154
+
155
+ return true if param_value.nil?
156
+
157
+ if param_value =~ /^(\d{4}\-\d{2}\-\d{2}\ \d{2}\:\d{2}(\:\d{2}(\.\d{1,6})?)?)$/ix
158
+ return true
159
+ else
160
+ return raise_invalid_request("Invalid Date Format")
161
+ end
162
+ end
163
+
164
+ def is_one_among_string_url?(param_name, param_value, mandatory = false, expected_values= nil)
165
+ if mandatory && param_value.nil?
166
+ raise_invalid_request("#{param_name} is a required parameter")
167
+ end
168
+
169
+ return true if param_value.nil?
170
+ return raise_invalid_request("#{param_name}: Expected a String but received #{param_value.class} instead") unless expected_type?(param_name, String, param_value)
171
+
172
+ if expected_values.include? param_value.downcase or expected_values.include? param_value.upcase
173
+ return true
174
+ elsif valid_url?(param_name, param_value)
175
+ return true
176
+ else
177
+ raise_invalid_request("#{param_name} neither a valid URL nor in the expected values")
178
+ end
179
+ end
180
+
181
+ def expected_type?(param_name, expected_types, param_value)
182
+ return true if expected_types.nil?
183
+ param_value_class = param_value.class
184
+ param_value_class = Integer if TYPE_WHITELIST.include? param_value_class
185
+ if expected_types.is_a? Array
186
+ return true if expected_types.include? param_value_class
187
+ raise_invalid_request("#{param_name}: Expected one of #{expected_types}"\
188
+ " but received #{param_value.class} instead")
189
+ else
190
+ return true if expected_types == param_value_class
191
+ raise_invalid_request("#{param_name}: Expected a #{expected_types}"\
192
+ " but received #{param_value.class} instead")
193
+ end
194
+ end
195
+
196
+ def expected_value?(param_name, expected_values, param_value)
197
+ return true if expected_values.nil?
198
+ if expected_values.is_a? Array
199
+ return true if expected_values.include? param_value
200
+ raise_invalid_request("#{param_name}: Expected one of #{expected_values}"\
201
+ " but received '#{param_value}' instead")
202
+ else
203
+ return true if expected_values == param_value
204
+ raise_invalid_request("#{param_name}: Expected '#{expected_values}'"\
205
+ " but received '#{param_value}' instead")
206
+ end
207
+ end
208
+
209
+ # @param [String] uri
210
+ # @param [String] nonce
211
+ # @param [String] signature
212
+ # @param [String] auth_token
213
+ def valid_signature?(uri, nonce, signature, auth_token)
214
+ parsed_uri = URI.parse(uri)
215
+ uri_details = {host: parsed_uri.host, path: parsed_uri.path}
216
+ uri_builder_module = parsed_uri.scheme == 'https' ? URI::HTTPS : URI::HTTP
217
+ data_to_sign = uri_builder_module.build(uri_details).to_s + nonce
218
+ sha256_digest = OpenSSL::Digest.new('sha256')
219
+ Base64.encode64(OpenSSL::HMAC.digest(sha256_digest, auth_token, data_to_sign)).strip() == signature
220
+ end
221
+
222
+ def generate_url?(uri, params, method)
223
+ uri.sub!("+", "%20")
224
+ parsed_uri = URI.parse(uri)
225
+ uri = parsed_uri.scheme + "://" + parsed_uri.host + parsed_uri.path
226
+ if params.to_s.length > 0 || parsed_uri.query.to_s.length > 0
227
+ uri += "?"
228
+ end
229
+ if parsed_uri.query.to_s.length > 0
230
+ parsed_uri_query = URI.decode(parsed_uri.query)
231
+ if method == "GET"
232
+ queryParamMap = getMapFromQueryString?(parsed_uri_query)
233
+ params.keys.sort.each { |key|
234
+ queryParamMap[key] = params[key]
235
+ }
236
+ uri += GetSortedQueryParamString?(queryParamMap, true)
237
+ else
238
+ uri += GetSortedQueryParamString?(getMapFromQueryString?(parsed_uri_query), true) + "." + GetSortedQueryParamString?(params, false)
239
+ uri = uri.chomp(".")
240
+ end
241
+ else
242
+ if method == "GET"
243
+ uri += GetSortedQueryParamString?(params, true)
244
+ else
245
+ uri += GetSortedQueryParamString?(params, false)
246
+ end
247
+ end
248
+ return uri
249
+ end
250
+
251
+ def getMapFromQueryString?(query)
252
+ mp = Hash.new
253
+ if query.to_s.length == 0
254
+ return mp
255
+ end
256
+ keyValuePairs = query.split("&")
257
+ keyValuePairs.each { |key|
258
+ params = key.split("=", 2)
259
+ if params.length == 2
260
+ mp[params[0]] = params[1]
261
+ end
262
+ }
263
+ return mp
264
+ end
265
+
266
+ def GetSortedQueryParamString?(params, queryParams)
267
+ url = ""
268
+ if queryParams
269
+ params.keys.sort.each { |key|
270
+ url += key + "=" + params[key] + "&"
271
+ }
272
+ url = url.chomp("&")
273
+ else
274
+ params.keys.sort.each { |key|
275
+ url += key.to_s + params[key].to_s
276
+ }
277
+ end
278
+ return url
279
+ end
280
+
281
+
282
+ def compute_signatureV3?(url, auth_token, nonce)
283
+ sha256_digest = OpenSSL::Digest.new('sha256')
284
+ new_url = url + "." + nonce
285
+ return Base64.encode64(OpenSSL::HMAC.digest(sha256_digest, auth_token, new_url)).strip()
286
+ end
287
+
288
+ def valid_signatureV3?(uri, nonce, signature, auth_token, method, params={})
289
+ new_url = generate_url?(uri, params, method)
290
+ generated_signature = compute_signatureV3?(new_url, auth_token, nonce)
291
+ return signature.split(",").include? generated_signature
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,3 @@
1
+ module Plivo
2
+ VERSION = "4.20.0".freeze
3
+ end
@@ -0,0 +1,31 @@
1
+ module Plivo
2
+ module XML
3
+ class Break < Element
4
+ @nestables = []
5
+ @valid_attributes = %w(strength time)
6
+ VALID_STRENGTH_VALUES= %w(none x-weak weak medium strong x-strong)
7
+
8
+ def initialize(attributes = {})
9
+ if attributes && attributes[:strength] && !VALID_STRENGTH_VALUES.include?(attributes[:strength])
10
+ raise PlivoXMLError, "invalid attribute value #{attributes[:strength]} for strength"
11
+ end
12
+ if attributes && attributes[:time]
13
+ if attributes[:time].downcase().include?('ms')
14
+ time = attributes[:time].split('ms')[0].to_i
15
+ if time<= 0 || time >10000
16
+ raise PlivoXMLError, "invalid attribute value #{attributes[:time]} for time attribute. Value for time in milliseconds should be > 0 or < 10000"
17
+ end
18
+ elsif attributes[:time].downcase().include?('s')
19
+ time = attributes[:time].split('s')[0].to_i
20
+ if time<= 0 || time >10
21
+ raise PlivoXMLError, "invalid attribute value #{attributes[:time]} for time attribute. Value for time in seconds should be > 0 or < 10"
22
+ end
23
+ else
24
+ raise PlivoXMLError, "invalid attribute value #{attributes[:time]} for time attribute"
25
+ end
26
+ end
27
+ super(nil, attributes)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module Plivo
2
+ module XML
3
+ class Conference < Element
4
+ @nestables = []
5
+ @valid_attributes = %w[muted beep startConferenceOnEnter
6
+ endConferenceOnExit waitSound enterSound exitSound
7
+ timeLimit hangupOnStar maxMembers
8
+ record recordFileFormat action method redirect
9
+ digitsMatch callbackUrl callbackMethod
10
+ stayAlone floorEvent
11
+ transcriptionType transcriptionUrl
12
+ transcriptionMethod recordWhenAlone relayDTMF]
13
+
14
+ def initialize(body, attributes = {})
15
+ raise PlivoXMLError, 'No conference name set for Conference' unless body
16
+ super(body, attributes)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Plivo
2
+ module XML
3
+ class Cont < Element
4
+ @nestables = []
5
+ @valid_attributes = []
6
+
7
+ def initialize(body)
8
+ super(body)
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,16 @@
1
+ module Plivo
2
+ module XML
3
+ class Dial < Element
4
+ @nestables = %w[Number User]
5
+ @valid_attributes = %w[action method timeout hangupOnStar
6
+ timeLimit callerId callerName confirmSound
7
+ dialMusic confirmKey redirect
8
+ callbackUrl callbackMethod digitsMatch digitsMatchBLeg
9
+ sipHeaders]
10
+
11
+ def initialize(attributes = {}, &block)
12
+ super(nil, attributes, &block)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module Plivo
2
+ module XML
3
+ class DTMF < Element
4
+ @nestables = []
5
+ @valid_attributes = %w[async]
6
+
7
+ def initialize(body, attributes = {})
8
+ raise PlivoXMLError, 'No digits set for DTMF' unless body
9
+ super(body, attributes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,106 @@
1
+ module Plivo
2
+ module XML
3
+ class Element
4
+ class << self
5
+ attr_accessor :valid_attributes, :nestables
6
+ end
7
+ @nestables = []
8
+ @valid_attributes = []
9
+ SSML_TAGS=%w[Break Emphasis Lang P Phoneme Prosody S SayAs Sub W]
10
+
11
+ attr_accessor :node, :name
12
+
13
+ def hyphenate(pascal_cased_word)
14
+ pascal_cased_word.to_s.gsub(/::/, '/').
15
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1-\2').
16
+ gsub(/([a-z\d])([A-Z])/,'\1-\2').
17
+ downcase
18
+ end
19
+
20
+ def initialize(body = nil, attributes = {}, nestables=self.class.nestables)
21
+ @name = self.class.name.split('::')[2]
22
+ @body = body
23
+ tagname = @name
24
+ if SSML_TAGS.include?(@name)
25
+ tagname = hyphenate(@name)
26
+ end
27
+ @node = REXML::Element.new tagname
28
+ attributes.each do |k, v|
29
+ if self.class.valid_attributes.include?(k.to_s)
30
+ @node.attributes[k.to_s] = convert_value(v)
31
+ else
32
+ raise PlivoXMLError, "invalid attribute #{k} for #{@name}"
33
+ end
34
+ end
35
+ @nestables = nestables
36
+ @node.text = @body if @body
37
+
38
+ # Allow for nested "nestable" elements using a code block
39
+ # ie
40
+ # Plivo::XML::Response.new do |r|
41
+ # r.Dial do |n|
42
+ # n.Number '+15557779999'
43
+ # end
44
+ # end
45
+ yield(self) if block_given?
46
+ end
47
+
48
+ def add_attribute(attribute, value)
49
+ @node.add_attribute(attribute, value)
50
+ end
51
+
52
+ def method_missing(method, *args, &block)
53
+ # Handle the addElement methods
54
+ method = Regexp.last_match(1).to_sym if method.to_s =~ /^add(.*)/
55
+ # Add the element
56
+ begin
57
+ add(Plivo::XML.const_get(method).new(*args, &block))
58
+ rescue StandardError => e
59
+ raise PlivoXMLError, e.message
60
+ end
61
+ end
62
+
63
+ def convert_value(v)
64
+ case v
65
+ when true
66
+ 'true'
67
+ when false
68
+ 'false'
69
+ when nil
70
+ 'none'
71
+ when 'get'
72
+ 'GET'
73
+ when 'post'
74
+ 'POST'
75
+ else
76
+ v
77
+ end
78
+ end
79
+
80
+ def add(element)
81
+ raise PlivoXMLError, 'invalid element' unless element
82
+ if @nestables.include?(element.name)
83
+ if element.name == "Cont"
84
+ @node.elements << element.node
85
+ element
86
+ temp = REXML::Text.new element.node.text
87
+ @node.elements['Cont'] = temp
88
+ else
89
+ @node.elements << element.node
90
+ element
91
+ end
92
+ else
93
+ raise PlivoXMLError, "#{element.name} not nestable in #{@name}"
94
+ end
95
+ end
96
+
97
+ def to_xml
98
+ @node.to_s
99
+ end
100
+
101
+ def to_s
102
+ @node.to_s
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,17 @@
1
+ module Plivo
2
+ module XML
3
+ class Emphasis < Element
4
+ @nestables = %w(Break Cont Emphasis Lang Phoneme Prosody SayAs Sub W)
5
+ @valid_attributes = %w(level)
6
+
7
+ VALID_LEVEL_ATTRIBUTE_VALUE=%w(strong moderate reduced)
8
+
9
+ def initialize(body, attributes = {})
10
+ if attributes && attributes[:level] && !VALID_LEVEL_ATTRIBUTE_VALUE.include?(attributes[:level])
11
+ raise PlivoXMLError, "invalid attribute value #{attributes[:level]} for level"
12
+ end
13
+ super(body, attributes)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Plivo
2
+ module XML
3
+ class GetDigits < Element
4
+ @nestables = %w[Speak Play Wait]
5
+ @valid_attributes = %w[action method timeout digitTimeout
6
+ numDigits retries invalidDigitsSound
7
+ validDigits playBeep redirect finishOnKey
8
+ digitTimeout log]
9
+
10
+ def initialize(attributes = {}, &block)
11
+ super(nil, attributes, &block)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Plivo
2
+ module XML
3
+ class GetInput < Element
4
+ @nestables = %w[Speak Play Wait]
5
+ @valid_attributes = %w[action method inputType executionTimeout
6
+ digitEndTimeout speechEndTimeout finishOnKey
7
+ numDigits speechModel hints profanityFilter
8
+ interimSpeechResultsCallback log language
9
+ interimSpeechResultsCallbackMethod redirect]
10
+
11
+ def initialize(attributes = {}, &block)
12
+ super(nil, attributes, &block)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module Plivo
2
+ module XML
3
+ class Hangup < Element
4
+ @nestables = []
5
+ @valid_attributes = %w[schedule reason]
6
+
7
+ def initialize(attributes = {})
8
+ super(nil, attributes)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ module Plivo
2
+ module XML
3
+ class Lang < Element
4
+ @nestables = %w(Break Cont Emphasis Lang P Phoneme Prosody S SayAs Sub W)
5
+ @valid_attributes = %w(xmllang)
6
+
7
+ VALID_LANG_ATTRIBUTE_VALUES = [
8
+ 'arb', 'cmn-CN','da-DK','nl-NL','en-AU',
9
+ 'en-GB', 'en-IN','en-US','en-GB-WLS','fr-FR',
10
+ 'fr-CA','de-DE','hi-IN','is-IS','it-IT',
11
+ 'ja-JP','ko-KR','nb-NO','pl-PL','pt-BR',
12
+ 'pt-PT','ro-RO','ru-RU','es-ES','es-MX',
13
+ 'es-US','sv-SE','tr-TR','cy-GB']
14
+
15
+
16
+ def initialize(body, attributes = {})
17
+ if attributes && attributes[:xmllang]
18
+ unless VALID_LANG_ATTRIBUTE_VALUES.include?(attributes[:xmllang])
19
+ raise PlivoXMLError, "invalid attribute value #{attributes[:xmllang]} for xmllang"
20
+ end
21
+ super(body, {})
22
+ add_attribute("xml:lang", attributes[:xmllang])
23
+ else
24
+ raise PlivoXMLError, 'xmllang attribute is a required attribute for lang'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module Plivo
2
+ module XML
3
+ class Message < Element
4
+ @nestables = []
5
+ @valid_attributes = %w[src dst type callbackUrl callbackMethod]
6
+
7
+ def initialize(body, attributes = {})
8
+ raise PlivoXMLError, 'No text set for Message' unless body
9
+ super(body, attributes)
10
+ end
11
+ end
12
+ end
13
+ end