node-red-contrib-chatbot
Version:
REDBot a Chat bot for a full featured chat bot for Telegram, Facebook Messenger and Slack. Almost no coding skills required
430 lines (420 loc) • 21.8 kB
HTML
<script type="text/javascript">
$.RedBot.registerType('chatbot-facebook-node', {
category: 'config',
defaults: {
botname: {
value: '',
required: true
},
usernames: {
value: '',
required: false
},
store: {
value: '',
type: 'chatbot-context-store',
required: false
},
log: {
value: null
},
debug: {
value: false
},
multiWebHook: {
value: false
},
profileFields: {
value: 'first_name,last_name'
},
storeMessages: {
value: true
},
enableMissionControl: {
value: false
},
inspectMessages: {
value: true
},
chatbotId: {
value: ''
}
},
oneditprepare: function() {
var node = this;
var nodeRedUrl = $.RedBot.getNodeRedUrl();
// fetch available context providers
$.get(nodeRedUrl + 'redbot/globals')
.done(function(response) {
if (response != null && response.facebook != null && response.facebook[node.botname] != null) {
$('#node-config-input-botname').prop('readonly', true);
$('.form-editable').hide();
$('.form-warning').show();
$('.form-warning .bot-name').html('"' + node.botname + '"');
}
// hide mission control options if not enabled
if (!response.missionControl) {
$('.form-row-not-mission-control').show();
$('.form-row-mission-control').hide();
$('#node-config-input-enableMissionControl')
.prop('disabled', true)
.prop('checked', false);
}
});
// enable or disable mission control
$('#node-config-input-enableMissionControl')
.change(function() {
if ($(this).is(':checked')) {
$('.form-row-not-mission-control').hide();
$('.form-row-mission-control').show();
} else {
$('.form-row-not-mission-control').show();
$('.form-row-mission-control').hide();
}
});
// if enable mission control, set a random chatbot id if empty
$('#node-config-input-enableMissionControl')
.change(function() {
if ($(this).is(':checked')) {
const chatbotId = $('#node-config-input-chatbotId').val();
if (chatbotId == null || chatbotId === '') {
$.ajax({ url: '/mc/chatbotIdGenerator' })
.then(res => {
$('#node-config-input-chatbotId').val(res);
});
}
}
});
},
paletteName: 'Facebook Bot',
credentials: {
token: {
type: 'text'
},
verify_token: {
type: 'text'
},
app_secret: {
type: 'text'
}
},
label: function () {
return this.botname;
}
});
</script>
<script type="text/x-red" data-template-name="chatbot-facebook-node">
<div class="form-row">
<label for="node-config-input-botname"><i class="icon-bookmark"></i> Bot Name</label>
<input type="text" id="node-config-input-botname">
</div>
<div class="form-editable">
<div class="redbot-separator">
<div>Facebook Messenger settings</div>
</div>
<div class="form-row">
<label for="node-config-input-token">Token</label>
<input type="text" id="node-config-input-token" placeholder="Access Token">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
The access token that is generated when the Facebook app is connected to a Facebook page
</div>
</div>
<div class="form-row">
<label for="node-config-input-app_secret">App Secret</label>
<input type="text" id="node-config-input-app_secret" placeholder="App secret">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
This is the app secret, find it in the "dashboard" section of the Facebook app
</div>
</div>
<div class="form-row">
<label for="node-config-input-verify_token">Verify</label>
<input type="text" id="node-config-input-verify_token" placeholder="Verify token">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
The verify token is an arbitrary string, must match the same string in the "Webhooks" section in the
Facebook app
</div>
</div>
<div class="form-row">
<label for="node-config-input-usernames">Users</label>
<input type="text" id="node-config-input-usernames" placeholder="Authorized users">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
Comma separated list of userId authorized to use the chatBot
</div>
</div>
<div class="form-row">
<label for="node-config-input-profileFields">Profile fields</label>
<input type="text" id="node-config-input-profileFields">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
Comma separated <a target="_blank" href="https://developers.facebook.com/docs/messenger-platform/identity/user-profile/">
list of fields</a> to retrieve from the user's profile: all fields different from
<em>first_name</em>, <em>last_name</em> requires an authorized token
</div>
</div>
<div class="form-row">
<label for="node-config-input-multiWebHook" style="width:auto;">Support multiple chatbots</label>
<input type="checkbox" value="true" id="node-config-input-multiWebHook" class="redbot-checkbox">
<span class="redbot-form-hint">
Supports multiple Facebook Messenger chatbots using different callbacks (<em>http://my.host.com/redbot/facebook/1234abcd</em>)
</span>
</div>
<div class="redbot-separator">
<div>RedBot settings</div>
</div>
<div class="form-row">
<label for="node-config-input-debug">Debug</label>
<input type="checkbox" value="true" class="redbot-checkbox" id="node-config-input-debug">
<span class="redbot-form-hint">
Show debug information on send/receive
</span>
</div>
<div class="form-row">
<label for="node-config-input-enableMissionControl" class="redbot-label">Use Mission Control</label>
<input type="checkbox" value="true" class="redbot-checkbox" id="node-config-input-enableMissionControl">
<span class="redbot-form-hint">
Enable Mission Control, see <a href="https://github.com/guidone/node-red-contrib-chatbot/wiki/Mission-Control" target="_blank">documentation here</a>
</span>
</div>
<div class="form-row form-row-mission-control">
<div class="redbot-form-hint">
Mission Control uses the built-in <b>SQLite context provider</b>.
</div>
</div>
</div>
<div class="form-row form-row-not-mission-control">
<label for="node-input-bot">Context</label>
<input type="text" id="node-config-input-store" placeholder="Select storage for chat context">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
Select the chat context provider to use with this bot, if none is selected then non-persistent "memory" will be used.<br>
To extend <strong>RedBot</strong> with a new chat context provider see <a href="https://github.com/guidone/node-red-contrib-chatbot/wiki/Creating-a-Chat-Context-Provider" target="_blank">this tutorial</a>.
</div>
</div>
<div class="form-row form-row-mission-control">
<label for="node-config-input-chatbotId" class="redbot-label">Chatbot ID</label>
<input type="text" id="node-config-input-chatbotId" placeholder="Enter a chatbot ID">
<span class="redbot-form-hint">
Specify a chatbot ID if you're running multiple chatbots on this Node-RED instance (it's just a string of your choice). Leave it blank if you're just running a single chatbot.
</span>
</div>
<div class="form-row form-row-mission-control">
<label class="redbot-label" for="node-config-input-storeMessages">Store messages</label>
<input type="checkbox" value="true" class="redbot-checkbox" id="node-config-input-storeMessages">
<span class="redbot-form-hint">
Store inbound and outbound messages in Mission Control
</span>
</div>
<div class="form-row form-row-mission-control">
<label for="node-config-input-inspectMessages" class="redbot-label">Inspect messages</label>
<input type="checkbox" value="true" class="redbot-checkbox" id="node-config-input-inspectMessages">
<span class="redbot-form-hint">
Inspect messages in real time in Mission Control
</span>
</div>
<div class="redbot-separator">
<div>
Legacy settings
</div>
<span class="redbot-form-hint">
These settings are for retrocompatibility, should only be used in legacy bots. Use <b>Mission Control</b>
to control user access or to log messages
</span>
</div>
<div class="form-row">
<label for="node-config-input-usernames">Users</label>
<input type="text" id="node-config-input-usernames">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
Comma separated list of userId authorized to use the chatBot
</div>
</div>
<div class="form-row">
<label for="node-config-input-log">Log file</label>
<input type="text" id="node-config-input-log">
<div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;margin-top:5px;">
Store inbound and outbound messages to file
</div>
</div>
</div>
<div class="form-warning" style="display:none;">
This bot configuration is stored in <b>Node-RED</b> <em>settings.js</em> and cannot be modified from the UI, check
the section <code>functionGlobalContext</code> near the key <em class="bot-name">""</em>
</div>
</script>
<script type="text/x-red" data-help-name="chatbot-facebook-node"><p><strong>Facebook Messenger</strong> API talks to <strong>RedBot</strong> via a https callback (a self signed certificate is not enough). We’ll use <a href="https://ngrok.com/">ngrok</a> to create a https tunnel for our local <strong>Node-RED</strong> instance. Install it, then open a shell window and run</p>
<pre><code class="language-bash">ngrok http 127.0.0.1:1880
</code></pre>
<p>You should get something like</p>
<p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/a888bc1b-0672-4e91-a3c1-1daa9ca4afc8/facebook-1.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45EIPT3X45%2F20230218%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20230218T124916Z&X-Amz-Expires=3600&X-Amz-Signature=37f517c9a5d5b5261b0396dc2b7e85a817afd99b6f599293f131e1b0abda7195&X-Amz-SignedHeaders=host&x-id=GetObject" alt="ngrok"></p>
<p>Grab the https address you get, something like <em><a href="https://123123.ngrok.io">https://123123.ngrok.io</a></em>, this is the base url that points back to your <strong>Node-RED</strong> instance.</p>
<p>The callback is</p>
<pre><code class="language-plain">http://youraddress.ngrok.io/redbot/facebook
</code></pre>
<p>Replace the hostname (<em>youraddress.ngrok.io</em>) with what you got above. <a href="https://developers.facebook.com/apps/create/">Start here</a> to create a new <strong>Facebook</strong> app, select type <em>None</em>.</p>
<p>In the app <em>Dashboard</em> go to the <em>“Add products to your app”</em> and add <strong>Messenger</strong> </p>
<p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/e3f96e27-a89f-4f9d-89d0-f95c5cd62e4c/Markup_2023-01-15_at_22.55.06.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45EIPT3X45%2F20230218%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20230218T124916Z&X-Amz-Expires=3600&X-Amz-Signature=ab1591910f35693bb2504e8dada516000732d1d8761b153a3792026fc505394a&X-Amz-SignedHeaders=host&x-id=GetObject" alt=""></p>
<p>Your <strong>Facebook</strong> app must be connected to a <em>Facebook page</em>, go to the <em>Access tokens</em> section and click on the <em>Add or remove Pages</em> (or create a page if you don’t have one).</p>
<p>After the page has been linked to the app, click on <em>Generate token</em>, then grab it.</p>
<p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/e78902ab-d486-4a11-b196-cfe5273e8b21/Markup_2023-01-15_at_23.02.42.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45EIPT3X45%2F20230218%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20230218T124916Z&X-Amz-Expires=3600&X-Amz-Signature=17a5f224f627a1059398ba15e15aa8074e17cf92fa60930e1eed8ad63db0b41c&X-Amz-SignedHeaders=host&x-id=GetObject" alt=""></p>
<p>Go to the <em>Webhooks</em> sections and click on <em>Add Callback URL</em> and put the ngrok URL you got before (i.e., <em><a href="https://123123.ngrok.io/redbot/facebook">https://123123.ngrok.io/redbot/facebook</a></em>), put anything on <em>Verify token</em> and then click on <em>Verify an save.</em></p>
<p>Switch to the <em>Settings</em> → <em>Basic</em> section and grab the <em>App secret</em>.</p>
<p>Now switch to <strong>Node-RED,</strong> drop and connect a <code>Messenger Receiver</code> node, <code>Text</code> node and <code>Messenger Sender</code> node and connect like below</p>
<p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/97ba3329-452b-41da-bb0f-2a433999d004/Screenshot_2023-01-15_alle_23.13.18.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45EIPT3X45%2F20230218%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20230218T124916Z&X-Amz-Expires=3600&X-Amz-Signature=8daf65e88f6219a0e5130a62700681e7253fb2dfa24c1c4d6ac658e86c615bb0&X-Amz-SignedHeaders=host&x-id=GetObject" alt=""></p>
<p>Don’t forget to configure the <code>Text</code> node (i.e., set the text <em>“Hello world!”</em>).</p>
<p>Double click on the <code>Messenger Receiver</code> node and create a new configuration, use the values saved before: <em>Access token</em>, <em>App secret.</em></p>
<p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/1a50d9db-119e-438e-a9ee-965132ea61e4/Markup_2023-01-15_at_23.18.04.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45EIPT3X45%2F20230218%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20230218T124916Z&X-Amz-Expires=3600&X-Amz-Signature=697c22d80d08c1b4f53035fdd971a5245e70e968c5bdb77a4ad4fc5a79f014ff&X-Amz-SignedHeaders=host&x-id=GetObject" alt=""></p>
<p>Select also the newly created configuration in the <code>Messenger Sender</code> node.</p>
<p>Now open <a href="http://messenger.com">messenger.com</a>, create a new message and select as recipient the page previously selected, write anything, you should receive an <em>“Hello world!”</em>.</p>
<p>If you get an error means that you have used wrong parameters (access token, app secret, etc) or, for some reason, Facebook APIs cannot reach the your callback url.</p>
<p>To exclude the second option and be sure that your <strong>Node-RED</strong> instance works correctly, grab your <strong>ngrok</strong> url and open this address</p>
<pre><code class="language-plain">http://youraddress.ngrok.io/redbot/facebook/test
</code></pre>
<p>If you get an <em>“ok”</em> then <strong>Node-RED</strong> is up and running. </p>
<p><code>Messenger Receiver</code> and <code>Messenger Sender</code> nodes have a double bot configuration for <em>development</em> and <em>production</em>. By default is used the <em>development</em> configuration. To use <em>production</em> configuration, edit <strong>Node-RED</strong> settings file (<em>settings.js</em>) and set the <em>environment</em> global variable to <em>“production”</em>. See <a href="https://www.notion.so/c0c2de46b48a4def837753c7e284b356">Deploying RedBot</a> for more details.</p>
</script>
<script type="text/javascript">
$.RedBot.registerType('chatbot-facebook-receive', {
category: $.RedBot.config.name + ' Platforms',
color: '#FFCC66',
defaults: {
bot: {
value: '',
type: 'chatbot-facebook-node',
required: true
},
botProduction: {
value: '',
type: 'chatbot-facebook-node',
required: false
}
},
inputs: 0,
outputs: 1,
icon: 'messenger.svg',
paletteLabel: 'Messenger Receiver',
label: function () {
return 'Messenger Receiver';
}
});
</script>
<script type="text/x-red" data-template-name="chatbot-facebook-receive">
<div class="form-row">
<label for="node-input-bot" style="display:block;width:100%;">Bot configuration <span class="redbot-environment">(development)</span></label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row" style="margin-top:25px;">
<label for="node-input-botProduction" style="display:block;width:100%;">Bot configuration <span class="redbot-environment">(production)</span></label>
<input type="text" id="node-input-botProduction" placeholder="Bot">
</div>
<div class="redbot-form-hint">
Bot for <strong>production</strong> will be launched only if the global variable <em>"environment"</em> in <em>settings.js</em> is set to <em>"production"</em>, otherwise will be used the configuration for <strong>development</strong>.
</div>
</script>
<script type="text/x-red" data-help-name="chatbot-facebook-receive">
<p>Input node for Facebook Messenger.</p>
</script>
<script type="text/javascript">
$.RedBot.registerType('chatbot-facebook-send', {
category: $.RedBot.config.name + ' Platforms',
color: '#FFCC66',
defaults: {
bot: {
value: "",
type: 'chatbot-facebook-node',
required: true
},
botProduction: {
value: '',
type: 'chatbot-facebook-node',
required: false
},
track: {
value: false
},
passThrough: {
value: false
},
errorOutput: {
value: false
},
outputs: {
value: 0
}
},
inputs: 1,
outputs: 1,
icon: 'messenger.svg',
paletteLabel: 'Messenger Sender',
label: function () {
return 'Messengerk Sender';
},
inputLabels: 'Chat flow',
outputLabels: function(idx) {
if (idx === 0 && this.track) {
return 'Track';
} else if (idx === 0 && this.passThrough) {
return 'Pass through';
} else if (idx === 1) {
return 'Error';
}
},
oneditprepare: function() {
// cannot be checked at the same time
$('#node-input-passThrough')
.click(function() {
if ($(this).is(':checked')) {
$('#node-input-track').prop('checked', false);
}
});
$('#node-input-track')
.click(function() {
if ($(this).is(':checked')) {
$('#node-input-passThrough').prop('checked', false);
}
});
},
oneditsave: function() {
var count = 0;
var track = $('#node-input-track').is(':checked');
var passThrough = $('#node-input-passThrough').is(':checked');
var errorOutput = $('#node-input-errorOutput').is(':checked');
if (track || passThrough) {
count = 1;
}
if (errorOutput) {
count += 1;
}
this.outputs = count;
}
});
</script>
<script type="text/x-red" data-template-name="chatbot-facebook-send">
<div class="form-row">
<label for="node-input-bot" style="display:block;width:100%;">Bot configuration <span class="redbot-environment">(development)</span></label>
<input type="text" id="node-input-bot" placeholder="Bot">
</div>
<div class="form-row" style="margin-top:25px;">
<label for="node-input-botProduction" style="display:block;width:100%;">Bot configuration <span class="redbot-environment">(production)</span></label>
<input type="text" id="node-input-botProduction" placeholder="Bot">
</div>
<div class="redbot-form-hint">
Bot for <strong>production</strong> will be launched only if the global variable <em>"environment"</em> in <em>settings.js</em> is set to <em>"production"</em>, otherwise will be used the configuration for <strong>development</strong>.
</div>
<div class="form-row" style="margin-top:25px;">
<label for="node-input-track" style="margin-bottom:0px;">Track</label>
<input type="checkbox" value="true" id="node-input-track" style="margin-top:0px;">
<div class="redbot-form-hint">
Track response of the user for this message: any further answer will be redirect to the output pin.
</div>
<label for="node-input-track" style="margin-bottom:0px;margin-top:15px;">Pass Through</label>
<input type="checkbox" value="true" id="node-input-passThrough" style="margin-top:0px;">
<div class="redbot-form-hint">
Forward the message to the output pin after sending (useful to chain messages and keep the right order)
</div>
<label for="node-input-errorOutput" style="margin-bottom:0px;margin-top:15px;">Error Output</label>
<input type="checkbox" value="true" id="node-input-errorOutput" style="margin-top:0px;">
<div class="redbot-form-hint">
Redirect the flow to the error pin in case of platform specific error on sending the message
</div>
</div>
</script>
<script type="text/x-red" data-help-name="chatbot-facebook-send">
<p>Output node for Facebook Messenger.</p>
</script>