Search code examples
node.jsbotframeworkfacebook-messenger-bot

Handlling link/referral interruptions from facebook (Bot Framework v4)


Consider this scenario:

  1. So when a user clicks an m.me link with referral parameters,it redirects to a messenger bot, shows some welcome message and then asks user if they want to proceed or not through a ConfirmPrompt.
  2. User didn't click either yes/no BUT re-clicks the link with referral parameter which would cause an error since (and I don't know how to capture this error), error is at onTurn level.

Can someone kindly, explain what happened to this kind of activity and how to handle it properly (by just restarting my whole dialog for referral parameters)

THANK YOU !!! PS. I use NodeJs SDK for my bot, (bot framework V4)

Edited: (thank you for asking nicely about code sample for full understanding of scenario, I'll also add some screenshots for visualization of the problem)

So this code is inside the one of waterfall stages in ReferralDialog that specifically asks for user confirmation.

await step.context.sendActivity("Doesn’t that sound easy?");
await step.context.sendActivity({ type: 'typing'});
return await step.prompt(CONFIRM_PROMPT, 'Now, would you like to apply?', ['yes', 'no']);

next stage of waterfall contains snippets codes of this:

if(step.result)
        {
            await step.context.sendActivity("And to protect your privacy from prying eyes, I will bring you outside of messenger to a secure East West owned chat environment");


           return await step.endDialog();
        }
        else
        {
            await step.context.sendActivity("Thank you ! If you change your mind, please click the link your referrer sent you again to re-enter the program.");
            return await step.endDialog();
        }

Inside the main dialog (snippets): //through fb but with ref (has already interacted)

else if(channelData &&  channelData.referral && channelData.referral.ref && stepContext.context.activity.channelId === 'facebook')
    {
return await stepContext.beginDialog(REFERRAL_DIALOG, userData);}

So the assumption was that: if user say clicks either yes/no, there will be a message for it: (but some crazy user clicks the referral link again)

So we now have this error:

Error Message

2nd and 3rd image is for what bot responds: Messenger prompt Messenger error

The error message, occurs in index.js has this code: (Its preset from framework, I never change/do something on that code)

// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
    // This check writes out errors to console log .vs. app insights.
    // NOTE: In production environment, you should consider logging this to Azure
    //       application insights.
    console.error(`\n [onTurnError] unhandled error: ${ error }`);

    // Send a trace activity, which will be displayed in Bot Framework Emulator
    await context.sendTraceActivity(
        'OnTurnError Trace',
        `${ error }`,
        'https://www.botframework.com/schemas/error',
        'TurnError'
    );

    // Send a message to the user
    let onTurnErrorMessage = 'The bot encounted an error or bug.';
    await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
    onTurnErrorMessage = 'To continue to run this bot, please fix the bot source code.';
    await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
    await context.sendActivity(error);
    // Clear out state
    await conversationState.delete(context);
};

And the only toLowerCase code of my bot can be found in CancelAndHelpDialog (Also I didn't defined but add something :

class CancelAndHelpDialog extends ComponentDialog {
    async onContinueDialog(innerDc) {
        const result = await this.interrupt(innerDc);
        if (result) {

            console.log("Bot was interrupted");
            return result;
        }
        return await super.onContinueDialog(innerDc);
    }

    async interrupt(innerDc) {
        console.log("Interrupt");
        let interruptData=innerDc.context.activity;
        if (interruptData && interruptData.text) {
            console.log("uhhhhhhhhhmmm" + typeof innerDc.context.activity.text);
                const text = innerDc.context.activity.text.toLowerCase();

                switch (text) {
                case 'help':
                case '?': {
                    const helpMessageText = 'Call our customer service 8888-1700 for further assistance.';
                    await innerDc.context.sendActivity(helpMessageText, helpMessageText, InputHints.ExpectingInput);
                    return { status: DialogTurnStatus.waiting };
                }
                case 'cancel':
                case 'quit': {
                    const cancelMessageText = 'Cancelling...';
                    await innerDc.context.sendActivity(cancelMessageText, cancelMessageText, InputHints.IgnoringInput);
                    return await innerDc.cancelAllDialogs();
                }
            }
        }
    }
}

It's really peculiar why I all my console.log() that I added in CancelAndHelpDialog wont be shown, and more importantly (to reiterate) I don't have any other toLowerCase code except in that dialog.

Thanks!

EDIT: Since the issue was that it becomes an error to user, I found a way to change onContinueDialog and reprompt users to reclick the link. hehe

async onContinueDialog(innerDc) {
        console.log("This is at oncontinue Dialog");
        console.log("\n\r This is the channel Data" + JSON.stringify(innerDc.context.activity.channelData));

        let interruptData=innerDc.context.activity;
        if(interruptData.channelData.referral && interruptData.channelData.referral.ref)
        {
            await innerDc.context.sendActivity("Sorry I didn't catch it. Kindly click the link again.");   
            return await innerDc.cancelAllDialogs();
        }
        else
        {
            const result = await this.interrupt(innerDc);
            console.log("The result: " + JSON.stringify(result));
            if (result) {

                console.log("Bot was interrupted");
                return result;
            }
            return await super.onContinueDialog(innerDc);
        }
    }

In that way users are forced to re-clicked the link and restart all dialogs.


Solution

  • Previously my bot is using Bot Framework 4.7.2 where it contains the bug for Facebook channel. Upgrading to 4.8.0 will get rid of the error “TypeError: Cannot read property 'toLowerCase' of undefined”.