How to access 'session.conversationData' while intercepting 'send' hook from middleware? - node.js

I have been following the official guidelines while trying to intercept user/bot messages.
bot.use({
botbuilder (session, next) {
logger.info("MESSAGE RECEIVED:" + session.message.text);
next();
},
send (event, next) {
logger.info("MESSAGE SENT:" + event.text);
next();
}
});
While botbuilder hook behaves as expected, send is never called.
At the moment when i will be able to solve this issue, my goal is to have
access to the session object, more precisely to the session.conversationData storage container from the send method middleware.
What have i done ?
i have been following the Logging middleware example and the readme states:
The botbuilder hook on the middleware is an example of ISessionMiddleware. The main advantage of using this hook instead of receive is the access we gain to the session.
and
send and receive hooks use IEventMiddleware. The first argument is the event itself. To see whether an event is a message, check to see if event.type is 'message'.
Currently i have wrapped the session.send in a custom function so i can log the messages which are send by the bot, and another function which logs the user response from inside the dialog. While this solution solves my problem it feels bad ( need to manually update each dialog ) and i am not able to create a generic middleware which could be loaded from a module.
What am i trying to achieve ?
The purpose of my middleware is to intercept user/bot messages and log them to SQL table with the following schema : conversation-id, message-text, timestamp.
conversation-id is stored in session.conversationData storage container, thus why i need to get access to session object from the send hook.
using "botbuilder": "^3.13.1"

You can load the session within the send by calling loadSessionWithoutDispatching:
send: function (message, next) {
bot.loadSessionWithoutDispatching(message.address,function (error,session){
console.log(session.userData);
});
next();
}

Related

Is it possible to not stop an API call which is doing some operation in server side if i redirect to another page in the mean time in React?

I used the post method to send some data through an API calling to Nodejs and waiting for the response after getting the response it will trigger another API. At this moment user wants to visit another page but the API calls will not be aborted. API call will do its task.
Is it possible to do so?
Call the API in redux using redux-thunk. Since redux is outside of all component. Changing page won't stop the API calling
You can just create a state variable and save the response of the post request in that variable, so it will be saved
When I implement the APIs in express, they continue to be executed even if the user navigates away, as illustrated by this example:
express()
.get("/api1", function(req, res) {
setTimeout(function() {
console.log("API call finished");
res.end();
}, 10000);
})
.get("/api2", function(req, res) {
res.end();
})
.listen(...);
The user first types http://server/api1 into their browser, which returns nothing after 10 seconds. But rather than wait, they navigate away to http://server/api2, which returns nothing immediately. But the /api1 call continues, as demonstrated by the console message after 10 seconds.
How does this differ from your case?

Issues with new express-openid-connect package

I have been trying to use express-openid-connect for the last few days with no success. I am able to get the flow to work when hard coding my params. However, my goal is to be able to dynamically call auth() depending on the user being logged in. My initial attempt included calling
app.use(auth(functionThatGetsParams()));
Using the approach above, express complains that secret is required. For some reason, the auth call is getting called before anything else is resolved.
I also tried doing a few different ways,
app.use((req,res, next)=> process.env.secret = 'hello');
app.use(auth({secret: process.env.secret}));
The example above also returns the secret issue. However, setting process.env.secret outside of app.use, works fine.
My issue seems to be related to the things I do in the app.use block. The approach I am looking to use is have a call that resolves who my user is and based off of that gets the right settings.
app.use(ConnectionResolver.resolve);
I use a call similar to the above which is basically a handler that does some async stuff to get the client info and right settings then ends with next().
I would expect that then calling
app.use(auth(ConnectionManager.getAuthSettings()));
Would return the auth settings I need, but when I debug, it looks like this line gets called before anything else, so then secret is missing as the error says.
One other option I believe I may have seen online is creating a list of auth calls for each client, which I can then use for authentication, but I have not seen any examples of how that works.
Does anyone have any ideas on how this might be possible? The environment I am in is multi tenant. So I need to be able to dynamically use a certain auth config depending on the user making the call.
Any help would be greatly appreciated.
You are misunderstanding the concept of middleware.
the auth function, is a middleware factory function, it gets a set of options and returns a middleware function based on those options.
The function passed to the use method of the express app, will execute only when an incoming request will arrive.
When you do app.use(auth(getParams())) what happens is that when your server is starting, it will call getParams function, pass the result to auth function which in turn will return the auth middleware function that will be passed to the app.use function.
Once a request will arrive, the auth middleware (the one returned by the auth factory function) will execute.
You don't need to use auth conditionally. You should set it up, and then you can use the requiresAuth middleware provided by express-openid-connect package to protect your paths that requires authorization/authentication.
If your secret is loading asynchronically, wrap your entire express app setup in a bootstrap function, load your secret and only then call the server bootstrap function.
async function loadSecret() {
//load secret from external source
}
function bootstrapServer(secret) {
const app = express()
app.use(auth({ ..., secert }))
app.get('protected', requiresAuth(), (req, res) => {
// your protected route, will automatically return 401 if not authenticated
})
app.get('non-protected', (req, res) => {
// This route will be open to all without authentication
})
}

Catching dialog name before being routed - middleware

I have a bot built with MS bot framework, using a library structure.
I'm trying to catch the dialog name + library of a message, before it is being routed to the dialog. (for analytics purposes)
Is there a middleware that can help me do that?
I tried the routing middleware of the UniversalBot, but it seems be running just before a dialog was choosen.
One possible option here could be using the ISessionMiddleware.
botbuilder: function (session, next) {
console.log(session.message.text);
next();
}
This will allow you to have access to the session. This will execute once a message is bound to a particular session and gives the option of looking at a message and the state of the session (where user is in available dialogs, etc) then making a decision of how to proceed.
It seems like bot.onDisambiguateRoute is the solution.
The var route contains the route name/library in that case, and has also the dialog arguments besides that. see the docs for more info
example code:
bot.onDisambiguateRoute(function (session, routes) {
// Route message as normal
var route = builder.Library.bestRouteResult(routes, session.dialogStack(), bot.name);
// *** log route
if (route) {
bot.library(route.libraryName).selectRoute(session, route);
} else {
// Just let the active dialog process the message
session.routeToActiveDialog();
}
}
});

Intercept user intent with `routing` middleware

I'm trying to intercept messages to send to my analytics server.
I'm looking to send it some data such as: messages,intent,resulted dialog.
I tried to use the routing middleware of universalBot in this fashion:
bot.on('routing',(session)=>{
console.log(session.intent);
console.log(session);
})
But it seems like the intent is undefined, and the only way I manage to see it is through triggerAction => onFindAction function.
I can use this method but it seems like a hack, is there a good way to intercept the intent data with middleware?
I'm using the Node.js SDK with botbuilder-apiai

Express middleware and parameter handling ordering on route

So I am running some API tests and I noticed that one test is failing because it is running some parameter handling logic before middleware, now here is an example of the route definition:
app.post("/something/:some_param",
middlewareA, middlewareB, middlewareC,
function(req, res) {
// Do stuff
});
Now I assumed (wrongly I think) that middleware would be invoked first then it would handle the parameter handler for :some_param however it seems to be the other way around. (by parameter handler I mean app.param())
Problem I have here is that if the above is correct and parameter handlers are run first, some of the logic within the parameter handler assumes the user is logged in already and blows up if they are not, and middlewareA handles user authentication and if they are not logged in redirects them etc, so ideally I would want middlewareA to be called first, so is there a way to achieve this ordering?
The only way I could see this working would be if the parameter handler could utilize middleware but there is no documentation on the API docs on this subject, so is there any best practice to handle this sort of scenario? as I do not want to have to shoe horn my middlewareA logic into my :some-param handling logic as I also have many other :other-param handlers etc which would also need this authentication (and other) middleware run before they run.
Yes, param handlers run before middleware. You can deal with this by either:
recoding your param handler as a middleware. There's not that much difference between the 2 mechanisms.
OR, in your param handler, just run the desired middleware directly as below:
.
function someParam(req, res, next, paramValue) {
myAuthMiddleware(req, res, function (error, result) {
if (error) {
next(error);
return;
}
//Here the user will be logged in
// do what you need to do with req and paramValue
next();
});
}

Resources