From 75cffa4e8ddef6b86f0597c2f1ee1437856de2e8 Mon Sep 17 00:00:00 2001 From: dhruv Date: Thu, 8 Aug 2024 15:11:07 -0400 Subject: [PATCH 1/6] docs: fix inline code --- voicemail/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voicemail/README.md b/voicemail/README.md index 711633d0..9e61287b 100644 --- a/voicemail/README.md +++ b/voicemail/README.md @@ -46,7 +46,7 @@ twilio serverless:init sample --template=voicemail && cd sample twilio serverless:start --ngrok ``` -5. Set your incoming call webhook URL for the phone number you want to configure to `https://.ngrok.io/voicemail +5. Set your incoming call webhook URL for the phone number you want to configure to `https://.ngrok.io/voicemail` ℹ️ Check the developer console and terminal for any errors, make sure you've set your environment variables. From ebbd73455fa56afdfca43e86967eb1f68e598c62 Mon Sep 17 00:00:00 2001 From: dhruv Date: Thu, 8 Aug 2024 15:26:00 -0400 Subject: [PATCH 2/6] chore(deps): update moment package --- voicemail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voicemail/package.json b/voicemail/package.json index 6fa6ae79..47bb34ea 100644 --- a/voicemail/package.json +++ b/voicemail/package.json @@ -2,6 +2,6 @@ "version": "1.0.0", "private": true, "dependencies": { - "moment": "^2.24.0" + "moment": "^2.30.1" } } From b5b6e0e11b63e0d936936d27216b0e5131ebae8b Mon Sep 17 00:00:00 2001 From: dhruv Date: Fri, 16 Aug 2024 14:51:24 -0400 Subject: [PATCH 3/6] docs: add Function comments --- voicemail/functions/recording.js | 29 ++++++++ voicemail/functions/voicemail.protected.js | 84 ++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/voicemail/functions/recording.js b/voicemail/functions/recording.js index 6a2f9a19..ddcd3069 100644 --- a/voicemail/functions/recording.js +++ b/voicemail/functions/recording.js @@ -1,3 +1,32 @@ +/* + * recording.js + * Description: + * This Twilio Function is executed when a voicemail + * recording has been processed by Twilio. This + * recording is initiated in the voicemail function + * located in voicemail.protected.js. Once the recording + * is finished and processed, it will send the + * generated recording URL to MY_PHONE_NUMBER + * specified in /.env. + * + * Contents: + * 1. Main Handler + */ + +/* + * 1. Main Handler + * + * This is the entry point to your Twilio Function, + * which will send the provided recording URL as an SMS + * to MY_PHONE_NUMBER specified in /.env. + * + * The function will fetch the Twilio Client provided by + * Functions. The Twilio client will be used to find the Twilio Number + * the voicemail was left at. It will then use the Twilio Client + * send an SMS of the recording URL from that number to + * MY_PHONE_NUMBER specified in /.env. + */ + exports.handler = async function (context, event, callback) { const client = context.getTwilioClient(); diff --git a/voicemail/functions/voicemail.protected.js b/voicemail/functions/voicemail.protected.js index 657ff790..6e2d6403 100644 --- a/voicemail/functions/voicemail.protected.js +++ b/voicemail/functions/voicemail.protected.js @@ -1,10 +1,53 @@ +/** + * Call Forwarding with Voicemail + * + * Description: + * This file contains the main Twilio Function that forwards + * incoming calls to a specific phone number during a set work + * hours and records voicemail for calls that are unanswered or + * outside of the work hours. + * + * Contents: + * 1. Dependencies + * 2. Configuration + * 3. Helper Function + * 4. Main Handler + */ + +/** + * 1. Dependencies + * These dependecies will be used in the main handler to assist + * in formatting the date and forwaring URL for the recorded voicemail. + */ + const moment = require('moment'); const url = require('url'); +/* + * 2. Configuration + * + * Contains greeting messages which is spoken when a call + * is received out of work hours. Here you can change the default + * greetings, voice types, and add addional greetings for specified languages. + * + * The function chooses the greeting based on the FromCountry parameter provided + * by Twilio when the call request is sent to the function. + * + * You can also change the default UTC time offset, work hours + * start and end times, start and end days of the work week. + * + */ + const GREETINGS = { + // default greeting if there isn't one set for the callers FromCountry parameter _default: { + // message that is spoken to the caller text: 'Hi there! You are calling after my work hours. Please leave a message after the beep', + + // language code for conversion of text-to-speech messages, e.g. 'en' or 'en-gb' language: 'en-US', + + // voice for text-to-speech messages, one of 'man', 'woman' or any supported Amazon Polly or Google voices voice: 'Polly.Joey', }, DE: { @@ -20,6 +63,17 @@ const DEFAULT_WORK_WEEK_END = 5; // Friday const DEFAULT_WORK_HOUR_START = 8; // 8:00, 8AM const DEFAULT_WORK_HOUR_END = 18; // 18:59, 6:59PM +/* + * 2. Helper Function + * + * Helper function to parse string values to integers. + * Returns default value if string cannot parsed to an integer. + * + * stringValue - value to be converted into an integer + * defaultValue - default value to return if stringValue + * can't be parse into integer + */ + function getInteger(stringValue, defaultValue) { const parsedNumber = parseInt(stringValue, 10); if (isNaN(parsedNumber)) { @@ -28,7 +82,27 @@ function getInteger(stringValue, defaultValue) { return parsedNumber; } +/* + * 3. Main Handler + * + * This is the entry point to your Twilio Function, + * which will create a new Voice Response using Twiml based on + * the current time and defined work hours. If the call is + * during work hours the Voice Response will forward the call + * and dial the MY_PHONE_NUMBER specified in /.env. + * If the call is placed outside work hours, the Voice Response + * will respond to the caller with a greeting and will record a voicemail + * which will be forwarded to the recording function in recording.js. + * + * The callback will be used to return from your function + * with the Twiml Voice Response you defined earlier. + * In the callback in non-error situations, the first + * parameter is null and the second parameter + * is the value you want to return. + */ + exports.handler = function (context, event, callback) { + // parse the environment variables and get the work hours and timezone const phoneNumberToForwardTo = context.MY_PHONE_NUMBER; const timezone = getInteger(context.TIMEZONE_OFFSET, DEFAULT_UTC_OFFSET); const workWeek = { @@ -40,18 +114,27 @@ exports.handler = function (context, event, callback) { end: getInteger(context.WORK_HOUR_END, DEFAULT_WORK_HOUR_END), }; + // calculate the current day and time according to the timezone const currentTime = moment().utcOffset(timezone); const hour = currentTime.hour(); const day = currentTime.day(); + + // check if there is a translated greeting for callers country const translatedGreeting = GREETINGS[event.FromCountry]; const hasTranslatedGreeting = typeof translatedGreeting !== 'undefined'; + // between monday and friday const isWorkingDay = day <= workWeek.end && day >= workWeek.start; // between 8am and 7pm const isWorkingHour = hour <= workHour.end && hour >= workHour.start; + // create a new TwiML response const twiml = new Twilio.twiml.VoiceResponse(); + /* + * If the current time is within work hours, forward the call to the specified phone number. + * Else play the greeting message and begin recording for a voicemail message. + */ if (isWorkingDay && isWorkingHour) { twiml.dial(phoneNumberToForwardTo); } else { @@ -76,5 +159,6 @@ exports.handler = function (context, event, callback) { action: url.resolve(context.PATH, 'recording'), }); } + // return the generated Twilio Voice Response callback(null, twiml); }; From ea9d2a2b5d983eef322c906113564b439e710761 Mon Sep 17 00:00:00 2001 From: dhruv Date: Fri, 16 Aug 2024 14:56:18 -0400 Subject: [PATCH 4/6] chore: update helper function name --- voicemail/functions/voicemail.protected.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/voicemail/functions/voicemail.protected.js b/voicemail/functions/voicemail.protected.js index 6e2d6403..940937e8 100644 --- a/voicemail/functions/voicemail.protected.js +++ b/voicemail/functions/voicemail.protected.js @@ -74,7 +74,7 @@ const DEFAULT_WORK_HOUR_END = 18; // 18:59, 6:59PM * can't be parse into integer */ -function getInteger(stringValue, defaultValue) { +function parseInteger(stringValue, defaultValue) { const parsedNumber = parseInt(stringValue, 10); if (isNaN(parsedNumber)) { return defaultValue; @@ -104,14 +104,14 @@ function getInteger(stringValue, defaultValue) { exports.handler = function (context, event, callback) { // parse the environment variables and get the work hours and timezone const phoneNumberToForwardTo = context.MY_PHONE_NUMBER; - const timezone = getInteger(context.TIMEZONE_OFFSET, DEFAULT_UTC_OFFSET); + const timezone = parseInteger(context.TIMEZONE_OFFSET, DEFAULT_UTC_OFFSET); const workWeek = { - start: getInteger(context.WORK_WEEK_START, DEFAULT_WORK_WEEK_START), - end: getInteger(context.WORK_WEEK_END, DEFAULT_WORK_WEEK_END), + start: parseInteger(context.WORK_WEEK_START, DEFAULT_WORK_WEEK_START), + end: parseInteger(context.WORK_WEEK_END, DEFAULT_WORK_WEEK_END), }; const workHour = { - start: getInteger(context.WORK_HOUR_START, DEFAULT_WORK_HOUR_START), - end: getInteger(context.WORK_HOUR_END, DEFAULT_WORK_HOUR_END), + start: parseInteger(context.WORK_HOUR_START, DEFAULT_WORK_HOUR_START), + end: parseInteger(context.WORK_HOUR_END, DEFAULT_WORK_HOUR_END), }; // calculate the current day and time according to the timezone From ebfec92b28b07bfbfb3f8ae158259c5dfdeb7bfc Mon Sep 17 00:00:00 2001 From: dhruv Date: Fri, 16 Aug 2024 15:07:37 -0400 Subject: [PATCH 5/6] docs: update function comments --- voicemail/functions/voicemail.protected.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/voicemail/functions/voicemail.protected.js b/voicemail/functions/voicemail.protected.js index 940937e8..717f422e 100644 --- a/voicemail/functions/voicemail.protected.js +++ b/voicemail/functions/voicemail.protected.js @@ -35,6 +35,7 @@ const url = require('url'); * * You can also change the default UTC time offset, work hours * start and end times, start and end days of the work week. + * These values are only used if they arent specified in /.env. * */ @@ -57,6 +58,10 @@ const GREETINGS = { }, }; +/* + * default values to be used if they aren't provided as environment variables + * in /.env. + */ const DEFAULT_UTC_OFFSET = 0; const DEFAULT_WORK_WEEK_START = 1; // Monday const DEFAULT_WORK_WEEK_END = 5; // Friday From 90808037b70765b5fd65e4cc63a8880872de7563 Mon Sep 17 00:00:00 2001 From: dhruv Date: Fri, 16 Aug 2024 15:16:53 -0400 Subject: [PATCH 6/6] docs: update formatting with prettier --- voicemail/changelog.md | 3 ++- voicemail/functions/recording.js | 10 +++++----- voicemail/functions/voicemail.protected.js | 18 +++++++++--------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/voicemail/changelog.md b/voicemail/changelog.md index 3982d461..144828c2 100644 --- a/voicemail/changelog.md +++ b/voicemail/changelog.md @@ -3,6 +3,7 @@ ## [Unreleased] ## [1.0.0] + ### Added -- Initial release. +- Initial release. diff --git a/voicemail/functions/recording.js b/voicemail/functions/recording.js index ddcd3069..742c31e2 100644 --- a/voicemail/functions/recording.js +++ b/voicemail/functions/recording.js @@ -1,14 +1,14 @@ /* * recording.js - * Description: + * Description: * This Twilio Function is executed when a voicemail * recording has been processed by Twilio. This * recording is initiated in the voicemail function * located in voicemail.protected.js. Once the recording - * is finished and processed, it will send the + * is finished and processed, it will send the * generated recording URL to MY_PHONE_NUMBER * specified in /.env. - * + * * Contents: * 1. Main Handler */ @@ -19,12 +19,12 @@ * This is the entry point to your Twilio Function, * which will send the provided recording URL as an SMS * to MY_PHONE_NUMBER specified in /.env. - * + * * The function will fetch the Twilio Client provided by * Functions. The Twilio client will be used to find the Twilio Number * the voicemail was left at. It will then use the Twilio Client * send an SMS of the recording URL from that number to - * MY_PHONE_NUMBER specified in /.env. + * MY_PHONE_NUMBER specified in /.env. */ exports.handler = async function (context, event, callback) { diff --git a/voicemail/functions/voicemail.protected.js b/voicemail/functions/voicemail.protected.js index 717f422e..3dc4387e 100644 --- a/voicemail/functions/voicemail.protected.js +++ b/voicemail/functions/voicemail.protected.js @@ -2,9 +2,9 @@ * Call Forwarding with Voicemail * * Description: - * This file contains the main Twilio Function that forwards - * incoming calls to a specific phone number during a set work - * hours and records voicemail for calls that are unanswered or + * This file contains the main Twilio Function that forwards + * incoming calls to a specific phone number during a set work + * hours and records voicemail for calls that are unanswered or * outside of the work hours. * * Contents: @@ -29,10 +29,10 @@ const url = require('url'); * Contains greeting messages which is spoken when a call * is received out of work hours. Here you can change the default * greetings, voice types, and add addional greetings for specified languages. - * + * * The function chooses the greeting based on the FromCountry parameter provided * by Twilio when the call request is sent to the function. - * + * * You can also change the default UTC time offset, work hours * start and end times, start and end days of the work week. * These values are only used if they arent specified in /.env. @@ -71,9 +71,9 @@ const DEFAULT_WORK_HOUR_END = 18; // 18:59, 6:59PM /* * 2. Helper Function * - * Helper function to parse string values to integers. + * Helper function to parse string values to integers. * Returns default value if string cannot parsed to an integer. - * + * * stringValue - value to be converted into an integer * defaultValue - default value to return if stringValue * can't be parse into integer @@ -98,7 +98,7 @@ function parseInteger(stringValue, defaultValue) { * If the call is placed outside work hours, the Voice Response * will respond to the caller with a greeting and will record a voicemail * which will be forwarded to the recording function in recording.js. - * + * * The callback will be used to return from your function * with the Twiml Voice Response you defined earlier. * In the callback in non-error situations, the first @@ -107,7 +107,7 @@ function parseInteger(stringValue, defaultValue) { */ exports.handler = function (context, event, callback) { - // parse the environment variables and get the work hours and timezone + // parse the environment variables and get the work hours and timezone const phoneNumberToForwardTo = context.MY_PHONE_NUMBER; const timezone = parseInteger(context.TIMEZONE_OFFSET, DEFAULT_UTC_OFFSET); const workWeek = {