Skip to content

Instantly share code, notes, and snippets.

@LosantGists
Created December 9, 2016 23:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LosantGists/d423e2bdc10d3f3014b32d97371c322a to your computer and use it in GitHub Desktop.
Save LosantGists/d423e2bdc10d3f3014b32d97371c322a to your computer and use it in GitHub Desktop.
{
"globals":[
{
"key":"onMessageFinishedUrl",
"type":"string"
},
{
"key":"doorResponseUrl",
"type":"string"
},
{
"key":"openDoorCode",
"type":"string"
},
{
"key":"slackUrl",
"type":"string"
},
{
"key":"slackToken",
"type":"string"
}
],
"triggers":[
{
"type":"webhook",
"meta":{
"category":"trigger",
"name":"webhook",
"label":"On Call Received",
"x":120,
"y":120,
"uiId":"r1wvM6J7l",
"description":"Webhook is called by Twilio when our number is dialed. This URL must be set in Twilio."
},
"config":{
},
"key":"5842423fc0b30a010006496e",
"outputIds":[
[
"HynOzakmg"
]
]
},
{
"type":"webhook",
"meta":{
"category":"trigger",
"name":"webhook",
"label":"On Message Finished",
"x":380,
"y":120,
"uiId":"BypLF6JXe",
"description":""
},
"config":{
},
"key":"584250c5ad4390010068a937",
"outputIds":[
[
"HkTKKak7l"
]
]
},
{
"type":"webhook",
"meta":{
"category":"trigger",
"name":"webhook",
"label":"Door Action",
"x":1140,
"y":120,
"uiId":"SJfoLCJXg",
"description":"When somebody types a slash command in Slack, this is the webhook they'll hit."
},
"config":{
},
"key":"5842568dad4390010068a939",
"outputIds":[
[
"HkxtrDf7x"
]
]
},
{
"type":"webhook",
"meta":{
"category":"trigger",
"name":"webhook",
"label":"Door Response",
"x":640,
"y":120,
"uiId":"BkFcCreQe",
"description":"This webhook is called after the user leaves their message at the door. Our team's response will ultimately go through here."
},
"config":{
},
"key":"5842ce6ec0b30a0100064973",
"outputIds":[
[
"HyHjCreXg"
]
]
}
],
"nodes":[
{
"type":"DebugNode",
"meta":{
"category":"output",
"name":"debug",
"label":"On Call Placed",
"x":120,
"y":280,
"description":""
},
"config":{
"message":"On Call Placed",
"property":""
},
"id":"SyWOGpy7x",
"outputIds":[
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Webhook Reply",
"x":120,
"y":200,
"description":"This is the message the user first hears in the callbox. When they finish their recording, they are redirected to a different Losant webhook."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":" text/xml"
}
],
"replyIdPath":"",
"responseCodeTemplate":"",
"bodyTemplate":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Say voice=\"woman\">Welcome. At the tone, please state your name and whom you are here to see, then press any key to continue.</Say>\n<Record action=\"{{globals.onMessageFinishedUrl}}\" playBeep=\"true\" maxLength=\"10\" />\n</Response>",
"bodyTemplateType":"string"
},
"id":"HynOzakmg",
"outputIds":[
[
"SyWOGpy7x"
]
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Webhook Reply",
"x":380,
"y":200,
"description":"This is what the user hears after entering their message. We redirect the Twilio response to a third Losant webhook, which will handle our Slack response."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":" text/xml"
}
],
"replyIdPath":"",
"responseCodeTemplate":"",
"bodyTemplate":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Say voice=\"woman\">Thank you. Please wait.</Say>\n<Redirect>{{globals.doorResponseUrl}}</Redirect>\n</Response>",
"bodyTemplateType":"string"
},
"id":"HkTKKak7l",
"outputIds":[
[
"ByO2sJlmx"
]
]
},
{
"type":"GetValueNode",
"meta":{
"category":"data",
"name":"get-value",
"label":"Get webhookId",
"x":1140,
"y":280,
"description":""
},
"config":{
"keyName":"webhookId",
"valuePath":"data.webhookId",
"defaultValueType":"json",
"defaultValue":"null"
},
"id":"r1bZEkeQg",
"outputIds":[
[
"B1GQr1l7g"
]
]
},
{
"type":"DebugNode",
"meta":{
"category":"output",
"name":"debug",
"label":"On Message Finished",
"x":380,
"y":360,
"description":""
},
"config":{
"message":"On Message Finished",
"property":""
},
"id":"HJqlrylme",
"outputIds":[
]
},
{
"type":"ConditionalNode",
"meta":{
"category":"logic",
"name":"conditional",
"label":"Webhook ID?",
"x":1140,
"y":360,
"description":"Is somebody at the door right now? If somebody already answered this user, or the request timed out, the answer is no."
},
"config":{
"expression":"!!{{data.webhookId}}"
},
"id":"B1GQr1l7g",
"outputIds":[
[
"H1asbufmg"
],
[
"By7o_PMXx"
]
]
},
{
"type":"HttpNode",
"meta":{
"category":"output",
"name":"http",
"label":"Send to Slack",
"x":380,
"y":280,
"description":"Call our Slack webhook (defined in Slack), which alerts our chosen channel that somebody is at the door."
},
"config":{
"method":"POST",
"uriTemplate":"{{globals.slackUrl}}",
"responsePath":"",
"headerInfo":[
],
"bodyTemplate":"{\n \"text\": \"<!here> *Somebody is at the front door! <{{data.body.RecordingUrl}}|(Hear Message)>*\\n\\nType `/door [OPEN|WAIT] [customMessage]` to respond and optionally open the door.\"\n}"
},
"id":"ByO2sJlmx",
"outputIds":[
[
"HJqlrylme"
]
]
},
{
"type":"StoreValueNode",
"meta":{
"category":"data",
"name":"store-value",
"label":"Store webhookId",
"x":640,
"y":200,
"description":"We'll need this value because we're responding to this webhook in a different branch of our workflow."
},
"config":{
"keyName":"webhookId",
"valueType":"template",
"value":"{{data.replyId}}"
},
"id":"HyHjCreXg",
"outputIds":[
[
"SyQdkhl7x"
]
]
},
{
"type":"DelayNode",
"meta":{
"category":"logic",
"name":"delay",
"label":"Timeout 12s",
"x":640,
"y":280,
"description":"Twilio times out after 15 seconds. Let's set this for 12 seconds just to be safe."
},
"config":{
"delay":12
},
"id":"SyQdkhl7x",
"outputIds":[
[
"SkSWfvOXx"
]
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Dismiss / Timeout",
"x":740,
"y":600,
"description":"Nobody is answering. Let's reply to the webhook request letting the user nobody is in the office."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":"text/xml"
}
],
"replyIdPath":"data.webhookId",
"responseCodeTemplate":"",
"bodyTemplate":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Say voice=\"woman\">Sorry, but nobody is answering in the office at this time. Please contact your expecting party directly or try again. Goodbye.</Say>\n</Response>",
"bodyTemplateType":"string"
},
"id":"SJgex2e7x",
"outputIds":[
[
"H1iJYDOQg",
"SJFkiD_7e"
]
]
},
{
"type":"DebugNode",
"meta":{
"category":"output",
"name":"debug",
"label":"On Door Action",
"x":1140,
"y":600,
"description":""
},
"config":{
"message":"On Door Action",
"property":""
},
"id":"ByeH9MnxQl",
"outputIds":[
]
},
{
"type":"ConditionalNode",
"meta":{
"category":"logic",
"name":"conditional",
"label":"Redirected yet?",
"x":640,
"y":520,
"description":"Has this user already been redirected once?"
},
"config":{
"expression":"{{data.query.rdrcount}} === '1'"
},
"id":"rJpfWWfml",
"outputIds":[
[
"r1H0bbzmx"
],
[
"SJgex2e7x"
]
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Redirect once",
"x":540,
"y":600,
"description":"To buy ourselves more time, let's redirect this webhook right back to itself."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":" text/xml"
}
],
"replyIdPath":"",
"responseCodeTemplate":"",
"bodyTemplate":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n<Redirect>{{globals.doorResponseUrl}}?rdrcount=1</Redirect>\n</Response>",
"bodyTemplateType":"string"
},
"id":"r1H0bbzmx",
"outputIds":[
[
"BkLFmOMXl"
]
]
},
{
"type":"ConditionalNode",
"meta":{
"category":"logic",
"name":"conditional",
"label":"Verify",
"x":1140,
"y":200,
"description":"Make sure this request came from our Slack account."
},
"config":{
"expression":"{{data.body.token}} === {{globals.slackToken}}"
},
"id":"HkxtrDf7x",
"outputIds":[
[
],
[
"r1bZEkeQg"
]
]
},
{
"type":"RawFunctionNode",
"meta":{
"category":"logic",
"name":"function",
"label":"Parse message",
"x":1240,
"y":440,
"description":"Here we make sense of the body of the slash command – whether we should open the door and what should be said to the user through the callbox."
},
"config":{
"script":"if(payload.data && payload.data.body && payload.data.body.text) {\n if(payload.data.body.text.indexOf('WAIT') === 0) {\n // tell the user to wait there (no message)\n payload.replyMsg = 'Thank you. Please wait where you are. Somebody is on their way down to meet you.';\n } else if(payload.data.body.text.indexOf('OPEN') === 0) {\n // open the door ...\n payload.openDoor = true;\n payload.replyMsg = payload.data.body.text.replace('OPEN','');\n if(payload.replyMsg.trim() === '') {\n // if no message was included, add this one on.\n payload.replyMsg = 'Thank you. The door is opening now. Please head up to the 3rd floor.';\n }\n } else {\n // speak the message. do not open the door. end the call.\n payload.replyMsg = payload.data.body.text;\n }\n}"
},
"id":"By7o_PMXx",
"outputIds":[
[
"HJpHzuf7g",
"ByxAoDzmg"
]
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Reply to door",
"x":1340,
"y":520,
"description":"Answer the Door Response webhook. If we're opening the door, play the touchtones to open the door after speaking."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":"text/xml"
}
],
"replyIdPath":"data.webhookId",
"responseCodeTemplate":"",
"bodyTemplate":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Say voice=\"woman\">{{replyMsg}}</Say>\n{{#eq openDoor true}}<Play digits=\"{{globals.openDoorCode}}\" />{{/eq}}\n</Response>",
"bodyTemplateType":"string"
},
"id":"ByxAoDzmg",
"outputIds":[
[
"H1iJYDOQg"
]
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Slack reply (nobody at door)",
"x":940,
"y":520,
"description":"Tell this user privately in Slack that nobody is at the door right now."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":"application/json"
}
],
"replyIdPath":"",
"responseCodeTemplate":"200",
"bodyTemplate":"{\n \"text\": \"Nobody is at the door right now.\"\n}",
"bodyTemplateType":"string"
},
"id":"H1asbufmg",
"outputIds":[
[
"ByeH9MnxQl"
]
]
},
{
"type":"WebhookReplyNode",
"meta":{
"category":"output",
"name":"webhook-reply",
"label":"Slack reply (bingo)",
"x":1140,
"y":520,
"description":"Tell everybody in Slack who replied to the door request and what they said."
},
"config":{
"headerInfo":[
{
"keyTemplate":"Content-type",
"valueTemplate":"application/json"
}
],
"replyIdPath":"",
"responseCodeTemplate":"200",
"bodyTemplate":"{\n \"text\": \"User <@{{data.body.user_id}}|{{data.body.user_name}}> replied with ...\\n\\n{{data.body.text}}\",\n\"response_type\":\"in_channel\"\n}",
"bodyTemplateType":"string"
},
"id":"HJpHzuf7g",
"outputIds":[
[
"ByeH9MnxQl"
]
]
},
{
"type":"DebugNode",
"meta":{
"category":"output",
"name":"debug",
"label":"On Redirect",
"x":540,
"y":680,
"description":""
},
"config":{
"message":"On Redirect",
"property":""
},
"id":"BkLFmOMXl",
"outputIds":[
]
},
{
"type":"GetValueNode",
"meta":{
"category":"data",
"name":"get-value",
"label":"Get webhookId",
"x":640,
"y":360,
"description":"Let's make sure the webhookId still exists before continuing."
},
"config":{
"keyName":"webhookId",
"valuePath":"data.webhookId",
"defaultValueType":"json",
"defaultValue":"null"
},
"id":"SkSWfvOXx",
"outputIds":[
[
"ry_BGPu7x"
]
]
},
{
"type":"ConditionalNode",
"meta":{
"category":"logic",
"name":"conditional",
"label":"Webhook ID?",
"x":640,
"y":440,
"description":"Has this webhook been answered yet? The presence of a webhook ID tells us that is has not."
},
"config":{
"expression":"!!{{data.webhookId}}"
},
"id":"ry_BGPu7x",
"outputIds":[
[
],
[
"rJpfWWfml"
]
]
},
{
"type":"StoreValueNode",
"meta":{
"category":"data",
"name":"store-value",
"label":"Clear webhookId",
"x":1140,
"y":760,
"description":"Clear the webhookId from storage, which prevents any further action on the door or on Slack."
},
"config":{
"keyName":"webhookId",
"valueType":"clear",
"value":""
},
"id":"H1iJYDOQg",
"outputIds":[
]
},
{
"type":"DebugNode",
"meta":{
"category":"output",
"name":"debug",
"label":"On Timeout",
"x":740,
"y":760,
"description":""
},
"config":{
"message":"On Timeout",
"property":""
},
"id":"H1C85D_Xx",
"outputIds":[
]
},
{
"type":"HttpNode",
"meta":{
"category":"output",
"name":"http",
"label":"Timeout to Slack",
"x":740,
"y":680,
"description":"Tell the Slack channel that we failed to respond in time."
},
"config":{
"method":"POST",
"uriTemplate":"{{globals.slackUrl}}",
"responsePath":"",
"headerInfo":[
],
"bodyTemplate":"{\n \"text\": \"Nobody answered in time. The person at the door has been told that nobody is home.\"\n}"
},
"id":"SJFkiD_7e",
"outputIds":[
[
"H1C85D_Xx"
]
]
}
],
"name":"Front Door",
"enabled":true,
"description":"Clear the request",
"applicationId":"5842419f37c9d60100e16386",
"_type":"flow",
"_exportDate":"2016-12-09T23:55:49.963Z"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment