Giter VIP home page Giter VIP logo

Comments (17)

philnash avatar philnash commented on June 3, 2024 1

Find me was one I built a little while back and you can see it here: https://github.com/twilio-labs/function-templates/tree/master/hunt.

I didn't specifically build it to replicate the twimlet exactly (numbers are set in an environment variable, for example) but it might be a good start for building out this twimlet replacement.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024 1

numbers are set in an environment variable, for example

This is a good point.

After careful thought, I am considering to use the following guidelines for the new function templates:

Level of Properties Shared by
environment all function templates: account parameters
script constants all instances of the script: localization strings, default values
script parameters a single instance of the script: values specific to the task

It may be useful to cross these boundaries in some cases:

  • use a script parameter, if provided,
  • otherwise default to an environment parameter, if it exists,
  • or else fallback to a default value declared as a constant in the script.

from function-templates.

dkundel avatar dkundel commented on June 3, 2024 1

I think that's a good guideline. Largely because Functions in the Twilio Console for example can be selected for a phone number without having to know the URL. Therefore query (script) parameters would be difficult to specify. At the same time having them to specify dynamic behavior was one of the most useful features of Twimlets.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

Annotated Source Code

based on a snapshot of Find Me TwiML source code (findme.php)
sent to me by Twilio support by email on 2019-07-08

This is PHP code.

<?php

It is shared by Twilio under the MIT license.

/*
Copyright (c) 2012 Twilio, Inc.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

It uses the (deprecated) class Twilio\Twiml of the twilio-php helper library to generate TwiML.

use Twilio\Twiml;

Start a new TwiML document.

// initiate response library
$response = new Twiml();

Make sure that PhoneNumbers is an array. Thanks to this code, if you provide only one phone number, it is possible to omit the square brackets from the parameter name and write just PhoneNumbers=916-555-0123 instead of PhoneNumbers[]=916-555-0123.

// init as array, if it's not
if (!is_array($_REQUEST['PhoneNumbers'])) {
	$_REQUEST['PhoneNumbers'] = array($_REQUEST['PhoneNumbers']);
}

Restrict the list to 10 non-empty phone numbers.

While writing the corresponding test case, I found a bug 🐞 in this code. While it checks that no more than 10 numbers were given, it then keeps only the numbers above the limit of 10. How is that possible? I checked the documentation of the PHP function array_splice:

  1. array_splice(array, 10) correctly removes all items starting from item 10 until the end of the array
  2. but it changes the array itself
  3. and it returns the removed items
  4. which are here assigned back to the original array

As a result, only the removed items are preserved.

// remove empty entries from PhoneNumbers
$_REQUEST['PhoneNumbers'] = @array_filter($_REQUEST['PhoneNumbers']);

// verify no more than 10 numbers given
if (count($_REQUEST['PhoneNumbers']) > 10) {
	$_REQUEST['PhoneNumbers'] = array_splice($_REQUEST['PhoneNumbers'], 10);
}

Stage 4

// if The Dial flag is present, it means we're returning from an attempted Dial
if (isset($_REQUEST['Dial']) && ($_REQUEST['DialStatus'] == 'answered' || $_REQUEST['DialCallStatus'] == 'completed')) {

	// answered call, so just hangup
	$response->hangup();

Stage 1

} else {

	// No dial flag, or anything other than "answered", roll on to the next (or first, as it may be) number

	// get the next number of the array
	if (!$nextNumber = @array_shift($_REQUEST['PhoneNumbers'])) {

		// if no phone numbers left, redirect to the FailUrl

		// FailUrl found, so redirect and kill the cookie
		if (strlen($_REQUEST['FailUrl'])) {
			header('Location: ' .$_REQUEST['FailUrl']);
			die;
		} else {

			// no FailUrl found, so just end the call
			$response->hangup();

		}

	} else {

		// re-assemble remaining numbers into a QueryString, shifting the 0th off the array
		$qs = 'FailUrl=' . urlencode($_REQUEST['FailUrl']) . '&Timeout=' . urlencode($_REQUEST['Timeout']) . '&Message=' . urlencode($_REQUEST['Message']);
		foreach ($_REQUEST['PhoneNumbers'] as $number) {
			$qs .= '&PhoneNumbers%5B%5D=' . urlencode($number);
		}

		// add a dial to the response
		$dial = $response->dial(array(
			'action' => $_SERVER['SCRIPT_URL'] . '?Dial=true&' . $qs,
			'timeout' => $_REQUEST['Timeout'] ? $_REQUEST['Timeout'] : 60,
		));

		// add the number to dial
		$dial->number($nextNumber, array(

Stage 2 and Stage 3: Whisper

Through the Whisper Twimlet, request the recipient to press a key to accept the incoming call (stage 2), then bridge the call when a digit has been pressed (stage 3). With the parameter HumanCheck set to true, the call will be interrupted when a timeout of 5 seconds in <Gather> expires without any digits pressed.

			'url' => 'whisper?Message=' . urlencode($_REQUEST['Message']) . '&HumanCheck=1',
		));

	}

}

Send the XML content-type header and the TwiML body.

// send the response
if (!headers_sent()) {
	header('Content-type: text/xml');
}
echo $response;

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

Test Cases

[FIND-ME-1-1] Find Me with 3 Numbers (from Example 1)

Input

Parameter Value
PhoneNumbers[] 415-555-1212
PhoneNumbers[] 415-555-1313
PhoneNumbers[] 415-555-1414

Output

$ curl -s 'https://twimlets.com/findme?PhoneNumbers%5B%5D=415-555-1212&PhoneNumbers%5B%5D=415-555-1313&PhoneNumbers%5B%5D=415-555-1414' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
    <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-2] Find Me with 3 Numbers and Fallback URL (from Example 2)

Input

Parameter Value
PhoneNumbers[] 415-555-1212
PhoneNumbers[] 415-555-1313
PhoneNumbers[] 415-555-1414
FailUrl https://example.com/please-try-later.mp3

Output

$ curl -s 'https://twimlets.com/findme?PhoneNumbers%5B%5D=415-555-1212&PhoneNumbers%5B%5D=415-555-1313&PhoneNumbers%5B%5D=415-555-1414&FailUrl=https%3A%2F%2Fexample.com%2Fplease-try-later.mp3' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
    <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-3] Find Me with Custom Timeout and Message

Input

Parameter Value
PhoneNumbers[] 415-555-1212
PhoneNumbers[] 415-555-1313
PhoneNumbers[] 415-555-1414
Timeout 42
Message Custom message

Output

$ curl -s 'https://twimlets.com/findme?PhoneNumbers%5B%5D=415-555-1212&PhoneNumbers%5B%5D=415-555-1313&PhoneNumbers%5B%5D=415-555-1414&Timeout=42&Message=Custom%20message' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=42&amp;Message=Custom+message&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
    <Number url="whisper?Message=Custom+message&amp;HumanCheck=1">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-4] Allow up to 10 numbers

Input

Parameter Value
PhoneNumbers[] 415-555-1001
PhoneNumbers[] 415-555-1002
PhoneNumbers[] 415-555-1003
PhoneNumbers[] 415-555-1004
PhoneNumbers[] 415-555-1005
PhoneNumbers[] 415-555-1006
PhoneNumbers[] 415-555-1007
PhoneNumbers[] 415-555-1008
PhoneNumbers[] 415-555-1009
PhoneNumbers[] 415-555-1010

Output

$ curl -s 'https://twimlets.com/findme?PhoneNumbers%5B%5D=415-555-0001&PhoneNumbers%5B%5D=415-555-0002&PhoneNumbers%5B%5D=415-555-0003&PhoneNumbers%5B%5D=415-555-0004&PhoneNumbers%5B%5D=415-555-0005&PhoneNumbers%5B%5D=415-555-0006&PhoneNumbers%5B%5D=415-555-0007&PhoneNumbers%5B%5D=415-555-0008&PhoneNumbers%5B%5D=415-555-0009&PhoneNumbers%5B%5D=415-555-0010' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-0002&amp;PhoneNumbers%5B%5D=415-555-0003&amp;PhoneNumbers%5B%5D=415-555-0004&amp;PhoneNumbers%5B%5D=415-555-0005&amp;PhoneNumbers%5B%5D=415-555-0006&amp;PhoneNumbers%5B%5D=415-555-0007&amp;PhoneNumbers%5B%5D=415-555-0008&amp;PhoneNumbers%5B%5D=415-555-0009&amp;PhoneNumbers%5B%5D=415-555-0010" timeout="60">
    <Number url="whisper?Message=&amp;HumanCheck=1">415-555-0001</Number>
  </Dial>
</Response>

[FIND-ME-1-5] Discard Extra Numbers Above 10

When more than 10 numbers are provided, the first one is called and only 9 are kept for the next try.

Input

Parameter Value
PhoneNumbers[] 415-555-1001
PhoneNumbers[] 415-555-1002
PhoneNumbers[] 415-555-1003
PhoneNumbers[] 415-555-1004
PhoneNumbers[] 415-555-1005
PhoneNumbers[] 415-555-1006
PhoneNumbers[] 415-555-1007
PhoneNumbers[] 415-555-1008
PhoneNumbers[] 415-555-1009
PhoneNumbers[] 415-555-1010
PhoneNumbers[] 415-555-1011
PhoneNumbers[] 415-555-1012

Output

$ curl -s 'https://twimlets.com/findme?PhoneNumbers%5B%5D=415-555-0001&PhoneNumbers%5B%5D=415-555-0002&PhoneNumbers%5B%5D=415-555-0003&PhoneNumbers%5B%5D=415-555-0004&PhoneNumbers%5B%5D=415-555-0005&PhoneNumbers%5B%5D=415-555-0006&PhoneNumbers%5B%5D=415-555-0007&PhoneNumbers%5B%5D=415-555-0008&PhoneNumbers%5B%5D=415-555-0009&PhoneNumbers%5B%5D=415-555-0010&PhoneNumbers%5B%5D=415-555-0011&PhoneNumbers%5B%5D=415-555-0012' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-0012" timeout="60">
    <Number url="whisper?Message=&amp;HumanCheck=1">415-555-0011</Number>
  </Dial>
</Response>

This is not the expected output. Due to a bug in the original code, the Find Me Twimlet keeps only the numbers beyond the 10th, instead of keeping only the first 10 numbers.

The output should actually be identical to the previous test case:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-0002&amp;PhoneNumbers%5B%5D=415-555-0003&amp;PhoneNumbers%5B%5D=415-555-0004&amp;PhoneNumbers%5B%5D=415-555-0005&amp;PhoneNumbers%5B%5D=415-555-0006&amp;PhoneNumbers%5B%5D=415-555-0007&amp;PhoneNumbers%5B%5D=415-555-0008&amp;PhoneNumbers%5B%5D=415-555-0009&amp;PhoneNumbers%5B%5D=415-555-0010" timeout="60">
    <Number url="whisper?Message=&amp;HumanCheck=1">415-555-0001</Number>
  </Dial>
</Response>

[FIND-ME-1-6] No More Numbers, Without Fallback URL

Input

Parameter Value
PhoneNumbers[] (empty or missing)

Output

$ curl -s 'https://twimlets.com/findme' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

[FIND-ME-1-7] No More Numbers, With Fallback URL

Input

Parameter Value
PhoneNumbers[] (empty or missing)
FailUrl https://example.com/please-try-later.mp3

Output

Query only headers to avoid following the redirect:

$ curl -I -s 'https://twimlets.com/findme?FailUrl=https%3A%2F%2Fexample.com%2Fplease-try-later.mp3'
HTTP/2 302 
date: Tue, 16 Jul 2019 21:27:14 GMT
content-type: text/html
location: https://example.com/please-try-later.mp3
server: nginx
x-shenanigans: none
x-shenanigans: none

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

[FIND-ME-4-1] Call Answered

Input

Parameter Value
Dial true
DialStatus answered

Output

$ curl -s 'https://twimlets.com/findme?Dial=true&DialStatus=answered' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

[FIND-ME-4-2] Call Completed

Input

Parameter Value
Dial true
DialCallStatus completed

Output

$ curl -s 'https://twimlets.com/findme?Dial=true&DialCallStatus=completed' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

Unit Tests

 PASS  funlet-find-me/funlet-find-me.test.js
  ✓ [FINDME-INPUT-PHONE-NUMBERS-1] Read Single Phone Number from Event (4ms)
  ✓ [FINDME-INPUT-PHONE-NUMBERS-2] Read List of Phone Numbers from Event
  ✓ [FINDME-INPUT-PHONE-NUMBERS-3] Read Single Phone Number from Environment (1ms)
  ✓ [FINDME-INPUT-PHONE-NUMBERS-4] Read Five Phone Numbers from Environment
  ✓ [FINDME-INPUT-PHONE-NUMBERS-5] Read Default Phone Numbers from Script
  ✓ [FINDME-INPUT-PHONE_NUMBERS-6] Skip empty values
  ✓ [FINDME-INPUT-TIMEOUT-1] Read Timeout from Event (1ms)
  ✓ [FINDME-INPUT-TIMEOUT-2] Read Timeout from Environment
  ✓ [FINDME-INPUT-TIMEOUT-3] Read Default Timeout from Script
  ✓ [FINDME-INPUT-DIAL-0] Read No Whisper from Event
  ✓ [FINDME-INPUT-DIAL-1] Read Whisper from Event (1ms)
  ✓ [FINDME-INPUT-MESSAGE-1] Read Message from Event
  ✓ [FINDME-INPUT-MESSAGE-2] Read Message from Environment
  ✓ [FINDME-INPUT-MESSAGE-3] Read Default Message from Script (with number in From parameter) (1ms)
  ✓ [FINDME-INPUT-MESSAGE-4] Read Default Message from Script (with number in Caller parameter)
  ✓ [FINDME-INPUT-LANGUAGE-1] Read Language from Event
  ✓ [FINDME-INPUT-LANGUAGE-2] Read Language from Environment
  ✓ [FINDME-INPUT-LANGUAGE-3] Read Default Language from Script (1ms)
  ✓ [FINDME-INPUT-VOICE-1] Read Voice from Event
  ✓ [FINDME-INPUT-VOICE-2] Read Voice from Environment
  ✓ [FINDME-INPUT-VOICE-3] Read Default Voice from Script
  ✓ [WHISPER-INPUT-HUMAN-CHECK-0] Read Human Check "1" from Event
  ✓ [FINDME-INPUT-HUMAN-CHECK-1] Read Human Check from Event (1ms)
  ✓ [FINDME-INPUT-HUMAN-CHECK-2] Read Human Check from Environment
  ✓ [FINDME-INPUT-HUMAN-CHECK-3] Read Default Human Check from Script
  ✓ [FINDME-INPUT-DIGITS-0] Read No Digits from Event
  ✓ [FINDME-INPUT-DIGITS-1] Read Empty Digits from Event
  ✓ [FINDME-INPUT-DIGITS-2] Read Non-Empty Digits from Event (1ms)
  ✓ [FINDME-INPUT-DIAL-0] Read No Dial from Event
  ✓ [FINDME-INPUT-DIAL-1] Read Dial from Event
  ✓ [FINDME-INPUT-CALL-STATUS-0] Read No Call Status from Event
  ✓ [FINDME-INPUT-CALL-STATUS-1] Read Answered Call Status from Event
  ✓ [FINDME-INPUT-CALL-STATUS-2] Read Completed Call Status from Event
  ✓ [FINDME-INPUT-CALL-STATUS-3] Read Busy Call Status from Event
  ✓ [FINDME-INPUT-FALLBACK-URL-1] Read Fallback URL from Event
  ✓ [FINDME-INPUT-FALLBACK-URL-2] Read Fallback URL from Environment
  ✓ [FINDME-INPUT-FALLBACK-URL-3] Read Default Fallback URL from Script (1ms)
  ✓ [FINDME-OUTPUT-FINDME-1-1] Find Me with 3 Phone Numbers (2ms)
  ✓ [FINDME-1-3] Find Me with Custom Timeout and Message (1ms)
  ✓ [FINDME-2-1] Whisper: Recorded Message (1ms)
  ✓ [FINDME-3-1] Whisper: A Digit was Pressed
  ✓ [FINDME-4-3] Failure with Fallback URL (1ms)

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

Integration Tests

With https://$DOMAIN.twil.io/findme the URL of a copy of the Find Me Funlet deployed in my Twilio account with checks for signed requests disabled:

$ ./test-find-me.sh "https://$DOMAIN.twil.io/findme"
[FIND-ME-1-1] Find Me with 3 Numbers (from Example 1)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
    <Number url=".?Whisper=true">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-2] Find Me with 3 Numbers and Fallback URL (from Example 2)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
    <Number url=".?Whisper=true">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-3] Find Me with Custom Timeout and Message
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
    <Number url=".?Whisper=true&amp;Message=Custom%20message">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-4] Allow up to 10 numbers
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
    <Number url=".?Whisper=true">415-555-1001</Number>
  </Dial>
</Response>

[FIND-ME-1-5] Discard Extra Numbers Above 10
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010&amp;PhoneNumbers%5B%5D=415-555-1011&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
    <Number url=".?Whisper=true">415-555-1001</Number>
  </Dial>
</Response>

[FIND-ME-1-6] No More Numbers, Without Fallback URL
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true" timeout="60">
    <Number url=".?Whisper=true"/>
  </Dial>
</Response>

[FIND-ME-1-7] No More Numbers, With Fallback URL
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3" timeout="60">
    <Number url=".?Whisper=true"/>
  </Dial>
</Response>

[FIND-ME-4-1] Call Answered
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

[FIND-ME-4-2] Call Completed
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

Checking differences with the output of the Find Me Twimlet,

$ ./test-find-me.sh "https://$DOMAIN.twil.io/findme" | diff twimlet-find-me.log  -
4,5c4,5
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1212</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
>     <Number url=".?Whisper=true">415-555-1212</Number>
12,13c12,13
<   <Dial action="/findme?Dial=true&amp;FailUrl=https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1212</Number>
---
>   <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
>     <Number url=".?Whisper=true">415-555-1212</Number>
20,21c20,21
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=42&amp;Message=Custom+message&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
<     <Number url="whisper?Message=Custom+message&amp;HumanCheck=1">415-555-1212</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
>     <Number url=".?Whisper=true&amp;Message=Custom%20message">415-555-1212</Number>
28,29c28,29
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1001</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
>     <Number url=".?Whisper=true">415-555-1001</Number>
36,37c36,37
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1011</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010&amp;PhoneNumbers%5B%5D=415-555-1011&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
>     <Number url=".?Whisper=true">415-555-1001</Number>
44c44,46
<   <Hangup/>
---
>   <Dial action=".?Dial=true" timeout="60">
>     <Number url=".?Whisper=true"/>
>   </Dial>
48c50,55
< Redirect: https://example.com/please-try-later.mp3
---
> <?xml version="1.0" encoding="UTF-8"?>
> <Response>
>   <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3" timeout="60">
>     <Number url=".?Whisper=true"/>
>   </Dial>
> </Response>

we notice the following differences:

  • parameters with empty values (FailUrl=, Message= are omitted)
  • the relative URL .? is used to refer to the script itself
  • the flag Whisper=true is used to handle the Whisper stages internally instead of delegating to a separate script
  • space characters are encoded as %20 instead of +
  • the flag HumanCheck=1 is omitted in the Whisper URL; this is the default value in the parameter MY_HUMAN_CHECK in this script.
  • TwiML <Redirect> is used instead of an HTTP redirect

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

I overlooked significant differences between the Twimlet and the Funlet on two cases:

44c44,46
<   <Hangup/>
---
>   <Dial action=".?Dial=true" timeout="60">
>     <Number url=".?Whisper=true"/>
>   </Dial>

and

48c50,55
< Redirect: https://example.com/please-try-later.mp3
---
> <?xml version="1.0" encoding="UTF-8"?>
> <Response>
>   <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3" timeout="60">
>     <Number url=".?Whisper=true"/>
>   </Dial>
> </Response>

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

They correspond to:

[FIND-ME-1-6] No More Numbers, Without Fallback URL

Twimlet:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

Funlet:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true" timeout="60">
    <Number url=".?Whisper=true"/>
  </Dial>
</Response>

and

[FIND-ME-1-7] No More Numbers, With Fallback URL

Twimlet:

Redirect: https://example.com/please-try-later.mp3

Funlet:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3
    <Number url=".?Whisper=true"/>
  </Dial>
</Response>

This is not expected.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

These two test cases were missing, and the corresponding part of the implementation was missing as well.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

I have added the missing test cases and implementation. Let's now check the integration tests again.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

Integration Tests

With https://$DOMAIN.twil.io/findme the URL of a copy of the Find Me Funlet deployed in my Twilio account with checks for signed requests disabled:

$ ./test-find-me.sh "https://$DOMAIN.twil.io/findme"
[FIND-ME-1-1] Find Me with 3 Numbers (from Example 1)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
    <Number url=".?Whisper=true">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-2] Find Me with 3 Numbers and Fallback URL (from Example 2)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
    <Number url=".?Whisper=true">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-3] Find Me with Custom Timeout and Message
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
    <Number url=".?Whisper=true&amp;Message=Custom%20message">415-555-1212</Number>
  </Dial>
</Response>

[FIND-ME-1-4] Allow up to 10 numbers
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
    <Number url=".?Whisper=true">415-555-1001</Number>
  </Dial>
</Response>

[FIND-ME-1-5] Discard Extra Numbers Above 10
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010&amp;PhoneNumbers%5B%5D=415-555-1011&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
    <Number url=".?Whisper=true">415-555-1001</Number>
  </Dial>
</Response>

[FIND-ME-1-6] No More Numbers, Without Fallback URL
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

[FIND-ME-1-7] No More Numbers, With Fallback URL
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Redirect>https://example.com/please-try-later.mp3</Redirect>
</Response>

[FIND-ME-4-1] Call Answered
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

[FIND-ME-4-2] Call Completed
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

Checking differences with the output of the Find Me Twimlet,

$ ./test-find-me.sh "https://$DOMAIN.twil.io/findme" | diff twimlet-find-me.log  -
4,5c4,5
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1212</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
>     <Number url=".?Whisper=true">415-555-1212</Number>
12,13c12,13
<   <Dial action="/findme?Dial=true&amp;FailUrl=https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1212</Number>
---
>   <Dial action=".?Dial=true&amp;https%3A%2F%2Fexample.com%2Fplease-try-later.mp3&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="60">
>     <Number url=".?Whisper=true">415-555-1212</Number>
20,21c20,21
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=42&amp;Message=Custom+message&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
<     <Number url="whisper?Message=Custom+message&amp;HumanCheck=1">415-555-1212</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1313&amp;PhoneNumbers%5B%5D=415-555-1414" timeout="42">
>     <Number url=".?Whisper=true&amp;Message=Custom%20message">415-555-1212</Number>
28,29c28,29
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1001</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
>     <Number url=".?Whisper=true">415-555-1001</Number>
36,37c36,37
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1011</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010&amp;PhoneNumbers%5B%5D=415-555-1011&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
>     <Number url=".?Whisper=true">415-555-1001</Number>
48c48,51
< Redirect: https://example.com/please-try-later.mp3
---
> <?xml version="1.0" encoding="UTF-8"?>
> <Response>
>   <Redirect>https://example.com/please-try-later.mp3</Redirect>
> </Response>

we notice some expected differences:

  • parameters with empty values (FailUrl=, Message= are omitted)
  • the relative URL .? is used to refer to the script itself
  • the flag Whisper=true is used to handle the Whisper stages internally instead of delegating to a separate script
  • space characters are encoded as %20 instead of +
  • the flag HumanCheck=1 is omitted in the Whisper URL; this is the default value in the parameter MY_HUMAN_CHECK in this script.
  • TwiML <Redirect> is used instead of an HTTP redirect

as well as an uncommon one:

36,37c36,37
<   <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
<     <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1011</Number>
---
>   <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010&amp;PhoneNumbers%5B%5D=415-555-1011&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
>     <Number url=".?Whisper=true">415-555-1001</Number>

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

It corresponds to the following test case:

[FIND-ME-1-5] Discard Extra Numbers Above 10

Twimlet:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action="/findme?Dial=true&amp;FailUrl=&amp;Timeout=&amp;Message=&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
    <Number url="whisper?Message=&amp;HumanCheck=1">415-555-1011</Number>
  </Dial>
</Response>

Funlet:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010&amp;PhoneNumbers%5B%5D=415-555-1011&amp;PhoneNumbers%5B%5D=415-555-1012" timeout="60">
    <Number url=".?Whisper=true">415-555-1001</Number>
  </Dial>
</Response>

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

The Twimlet has a bug identified previously: when more than 10 numbers are included, the first 10 are discarded and the following numbers kept, instead of keeping only the first 10 and discarding extra numbers.

The Funlet has a different bug: it does not discard the extra numbers, and happily keeps more than 10 numbers.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

I fixed that bug too, and extra numbers beyond the first 10 are now correctly discarded:

[FIND-ME-1-5] Discard Extra Numbers Above 10
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial action=".?Dial=true&amp;PhoneNumbers%5B%5D=415-555-1002&amp;PhoneNumbers%5B%5D=415-555-1003&amp;PhoneNumbers%5B%5D=415-555-1004&amp;PhoneNumbers%5B%5D=415-555-1005&amp;PhoneNumbers%5B%5D=415-555-1006&amp;PhoneNumbers%5B%5D=415-555-1007&amp;PhoneNumbers%5B%5D=415-555-1008&amp;PhoneNumbers%5B%5D=415-555-1009&amp;PhoneNumbers%5B%5D=415-555-1010" timeout="60">
    <Number url=".?Whisper=true">415-555-1001</Number>
  </Dial>
</Response>

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 3, 2024

On the other hand, there are no unexpected differences in the two Whisper stages,

$ ./test-whisper.sh "https://$DOMAIN.twil.io/findme"
[WHISPER-2-1] Recorded Message
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1">
    <Play>https://example.com/recorded-message.mp3</Play>
  </Gather>
  <Hangup/>
</Response>

[WHISPER-2-2] Text Message
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1">
    <Say language="en" voice="alice">Text message</Say>
  </Gather>
  <Hangup/>
</Response>

[WHISPER-2-3] Default Message
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1">
    <Say language="en" voice="alice">You are receiving a call from +. 1. 9. 1. 6. 5. 5. 5. 0. 1. 2. 3. . Press any key to accept.</Say>
  </Gather>
  <Hangup/>
</Response>

[WHISPER-2-4] Human Check
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1">
    <Say language="en" voice="alice">Text message</Say>
  </Gather>
  <Hangup/>
</Response>

[WHISPER-3-1] A Digit was Pressed
<?xml version="1.0" encoding="UTF-8"?>
<Response/>

[WHISPER-3-2] No Digits were Pressed
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

We get the same differences as in the Call Me Funlet:

$ ./test-whisper.sh "https://$DOMAIN.twil.io/findme" | diff twimlet-whisper.log  -
14c14
<     <Say>Text message</Say>
---
>     <Say language="en" voice="alice">Text message</Say>
23c23
<     <Say>You are receiving a call from +. 1. 9. 1. 6. 5. 5. 5. 0. 1. 2. 3. .  Press any key to accept.</Say>
---
>     <Say language="en" voice="alice">You are receiving a call from +. 1. 9. 1. 6. 5. 5. 5. 0. 1. 2. 3. . Press any key to accept.</Say>
32c32
<     <Say>Text message</Say>
---
>     <Say language="en" voice="alice">Text message</Say>

from function-templates.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.