Where to implement the postback action code in a javascript chatbot - javascript

my question is regarding the implementation of this snippet of javascript code into my chatbot:
smooch.conversations.sendMessage('app_5790dca8cab9a256005c0148', {
text: 'Fabric',
role: 'appMaker',
actions: [
{
type: 'postback',
text: 'fabric instructions',
payload: 'egg_fabric'
}
]
}).then(() => {
// async code
});
Here is my script.json file that corresponds to this specific postback:
"HOW CAN I REMOVE AN EGG STAIN?": "%[Fabric](postback:egg_fabric) %[Surface](postback:egg_surface)",
The reason I am asking this question is because I want to have multiple "surface" and "fabric" buttons throughout the chat but I want the answer the bot spits out to correspond to the question most recently asked. Thanks for your help!

What you're looking for can't be done this with script.json, you'll have to define your own state functions in script.js, and your own postback event handling.
In this answer there are some suggestions as to how you can do this with the smooch-bot-example project (which is what estherbot was forked from).
To give you some context, script.js is where the actual bot logic lives. The script.json you're looking at is a shortcut that was introduced with estherbot to make it easier to define keyword-based bots. When your bot runs, the JSON actually gets compiled into states as if the were defined in script.js in the first place. What you're attempting to build will require more than the static keyword --> behaviour mapping that the script.json is limited to.

Following up on Andrew's answer above:
Check the smooch-bot-example project, but maybe start by looking into the webhook implementation file for the postbacks (heroku/index.js) instead of the bot logic/flow definition file (script.js) file:
Within the heroku folder of the repo, check the index.js file. The function handlePostback(req, res) (should be around line 109) should help you get started. E.g. change it to something like this:
From:
function handlePostback(req, res) {
const postback = req.body.postbacks[0];
if (!postback || !postback.action) {
res.end();
}
createBot(req.body.appUser).say(`You said: ${postback.action.text} (payload was: ${postback.action.payload})`)
.then(() => res.end());
}
To something like:
function handlePostback(req, res) {
const postback = req.body.postbacks[0];
if (!postback || !postback.action) {
res.end();
}
const sAction = postback.action.text;
const sPayload = postback.action.payload;
switch (sAction) {
case "egg_fabric":
//something something
break;
case "egg_surface":
//something something
break;
default:
//something something
}
}
Hope that helps.

Related

Utility Mapper functions in javascript

I wanted to know if there is any way to write a mapper function in javascript, and by map functions I do not mean the ES6 map HOF,
What I really need is when I get an response or data and I wish to produce a conditional result out of it,
for example, if role:['ADMIN'] do this,
if role:['HEAD'] do this, now it can be done with if else or switch but I do not want to write conditionals for this, as in future there is a possibility more conditions will be handled. So is there a way to create a custom mapper function which does this, it can also be useful in api calls as when a user has a specific role he/she can make this specific API call
Please comment if you need more information.
Thank you
I don't know if that's the right way to do it but you could create an Object with functions in it.
This would look somewhat like that:
const map = {
'ADMIN': () => { console.log('your role is admin') },
'HEAD': () => { console.log('your role is head') }
};
map['ADMIN'](); // Outputs 'your role is admin'
But what if you, by any reason, received garbage data. Your code will error.
So you would either need to catch that error:
const role = 'blarg';
try {
map[role]();
} catch(e) {
console.log('submittet incorect data')
}
Or check if the role key exists in the object:
if(Object.keys(map).includes(role)) {
map[role]()
}
But to be honest I still think I would do something like:
function handleRole(role) {
switch(role) {
case 'ADMIN': function_for_admin(); break;
case 'HEAD': function_for_head(); break;
}
}
handleRole(role);

Mocha/Sinon - Unit testing promises in JavaScript

While learning electron, I decided I would also like to train testing techniques in JavaScript. I have following code:
const winston = require('winston');
const AutoLaunch = require('auto-launch');
const launchFunction = (mb) => {
const autolaunch = new AutoLaunch();
autolaunch
.isEnabled()
.then((isEnabled) => {
if (isEnabled) {
return;
}
autolaunch.enable();
})
.catch((err) => {
winston.error(err);
});
};
I would like to assert if autolaunch.enabled() is properly triggered under specific condition and I have a lot of problem with writing any test that won't force me to create stub with exact copy of function from then(). There is an option that maybe something is wrong in this design of this solution - I can (and would like to) change code to make it more testable. How should I cope with that problem without compromising code testability?
I use mocha and sinon but I don't feel really attached to those tools
I would try more functional approach. Wrap closure in question in function and test it separately.
function enableWhenNeeded(autolaunch, isEnabled) {
if (isEnabled) {
return;
}
autolaunch.enable();
}
autolaunch
.isEnabled()
.then(curry(enableWhenNeeded, autolaunch))
.catch((err) => {
winston.error(err);
});
For purpose of the example, I made up function curry(), but I think there are at least thirty five JavaScript frameworks which provide one.
It is always a question is this code worth testing; if AutoLaunch is third party, why testing it?

Using a Mongoose Schema Function Inside Of An Exported Mongoose Model

I have been working on an authentication system lately that is supposed to either create a new user if no user with a given ID exists OR loads in a user with an existing ID. I also already figured out that you can return whether or not a user exists with in ID by using
User.count({_id: id}, function (err, count){
if(count > 0){
// User exists, continue with loading data
} else {
// User does not exist, create one
}
});
with User being an exported Mongoose Model mongoose.model('User', UserSchema);
If I created a function existsWithId(id) in my app.js now, it would work perfectly fine (judging by the fact that the previously mentioned code works perfectly fine), but I want to move this function to my user.js Model (which contains the Mongoose / MongoDB Code) instead so that I have it only for that specific model. Whenever I try to do that by using
UserSchema.statics.existsWithId = function(id) {
this.count({_id: id}, function (err, count){
return count > 0;
});
}
or similar methods, though, it will either just return undefined or an error once I run it inside of my app.js.
NOTE: I'm sorry if this is a kind of simple or even foolish question, but I am pretty new considering DB management with Mongoose and while I do have SOME experience with JS, I am not exactly a professional at it.
If any of you need additional code provided to answer the question, feel free to ask me and I will do so. Also, I can't +rep answers yet, but I always appreciate 'em :)
Your existsWithId method returns a value asynchronously so you can give a callback to it to get the result back like this :
UserSchema.statics.existsWithId = function(id, cb) {
this.count({ _id: id }, function(err, count) {
cb(err, count > 0);
});
}
User.existsWithId("5882c3be5aad09028d4d8b46", function(err, res) {
console.log(res);
});

Dynamically run a sequence of promises using Q

I am writing a SPA with typescript using breeze and knockout.
What I want to do is to create a launch manager, which can perform the neccessary steps required to even start the site (e.g. read configuration json, download odata metadata, initialize breeze metadata store and so on).
I've created the following to represent each step in the launch sequence:
export enum LauncherProgressStatus {
Ready,
InProgress,
Success,
Failed,
Aborted
}
export class LauncherProgressItem {
public status: KnockoutObservable<LauncherProgressStatus> = ko.observable<LauncherProgressStatus>();
public description: KnockoutObservable<String> = ko.observable<String>();
public statusText: KnockoutComputedFunctions<String> = ko.computed<String>(() => {
return LauncherProgressItem.getStatusText(this.status());
});
public start() {
this.action(this);
}
constructor(descriptionText: String,
public action: (arg: LauncherProgressItem) => Boolean) {
this.status(LauncherProgressStatus.InProgress);
this.description(descriptionText);
}
public static getStatusText(status: LauncherProgressStatus) : String {
switch (status) {
case LauncherProgressStatus.Ready:
return "Ready";
case LauncherProgressStatus.InProgress:
return "In progress";
case LauncherProgressStatus.Success:
return "Success";
case LauncherProgressStatus.Aborted:
return "Aborted";
default:
return "Failed";
}
}
}
TL;DR I create each step like this in code:
var item1 = new launcher.LauncherProgressItem("Loading configuration...", (item: LauncherProgressItem) => {
cfgMgr.setConfigurationFromFile("config.json?bust=" + (new Date()).getTime());
return true;
});
Now the problem: I want to utilize this to create a promise chain using Q. I can do this manually, i.e.
q.fcall(() => item1.action(item1))
.then(() => item2.action(item2))
.fail((r) => { console.log("Many whelps, HANDLE IT!") });
But I want to create some kind of manager object that doesnt really know how many steps is required. It will just be responsible for building an array of promises and execute them in sequence, whilst being able to detect errors (in the fail promise presumably) and abort the sequence.
The manager will have some kind of collection containing the LauncherProgressItem steps. Then I'm looking to build a chain of promises based on the content of that collection.
I've been looking at this for a while now but can't really seem to get my head around how to do this with Q. I've seen some examples etc but I don't really understand how it works.
Anyone got any suggestions on how to achieve this?
Update: I'll try to clarify what I am trying to achieve: My LauncherProgressItem wraps a lambda function and some state information which I bind to my view. This is why I am using these, but this is kind of irrelevant to what I'm actually struggling with.
So lets assume I have a class which contains an array of lambdas. This class has a method which will run all these lambas in sequence using Q, aborting on error. Exactly what I would achieve with the following code:
Q.fcall(doSomething).then(doSomethingElse).fail(reportError);
However, in this case doSomething and doSomethingElseresides in an array of functions, rather than a fixed number of steps. This is because I want it to be reusable, i.e. being able to run in multiple scenarios depending on the task at hand. So I want to avoid hard-coding the chain of functions to run.
Sorry I don't know typescript but I thought the comment thread above was not going very well, so here's the function you asked for in plain JS:
function runInSequence (functions) {
if (!functions || !functions.length) {
return;
}
var nextPromise = Q.fcall(functions[0]);
functions.slice(1).forEach(function (f) {
nextPromise = nextPromise.then(f);
});
nextPromise.fail(yourErrorHandler);
}

Windows 8 Metro Inapp purchases for Dummies

am ready to deploy my second windows 8 metro style javascript app and i would love to include in app purchases.
I tried implementing it with the following code i got from here
http://msdn.microsoft.com/en-us/library/windows/apps/hh694067.aspx
function appInit()
{
// some app initialization functions
// Get current product object
// Execute only one of these statements.
// The next line is commented out for testing.
// currentApp = Windows.ApplicationModel.Store.CurrentApp;
// The next line is commented out for production/release.
currentApp = Windows.ApplicationModel.Store.CurrentAppSimulator;
// We should have either a real or a simulated CurrentProduct object here.
// Get the license info
licenseInformation = currentApp.licenseInformation;
// other app initializations function
}
function buyFeature1() {
if (!licenseInformation.productLicenses.lookup("featureName").isActive)
{
currentApp.requestProductPurchaseAsync("featureName", false).then(
function () {
// the in-app purchase was successful
},
function () {
// The in-app purchase was not completed because // there was an error.
});
}
else
{
// The customer already owns this feature.
}
}
But nothing seems to happen.i know this is a novice question. but i'l be glad if someone can provide a full simple working solution.Btw i've read the docs and downloaded the sample.i also have my storeproxy.xml file setup.
You might try changing:
currentApp.requestProductPurchaseAsync("featureName", false).then(
Into:
currentApp.requestProductPurchaseAsync("featureName", false).done(
That is what I use and it works for me.

Categories