Azure bot framework - Connection open and close - azure

I am new to Azure bot services. I have created a bot and hosted locally. I want to know when the connectivity between user and bot gets closed.
I actually need this to store chat history to DB that too before connection getting closed.
I am using Directline API.
Is bot connection will remains for a long time?
Is there any event triggers before connection close?
How actally connection between use and bot created and closed?

If you are using a directline channel within your own website the following method should work. Essentially you will just send a backchannel message to your bot when a user closes out of a chat with your bot.
Make sure to define your directline as follows so the connection can be used for backchannel messages
botConnection = new BotChat.DirectLine({
secret: "<secret>"
});
You will want to register an "onunload" method on your html body or div like so:
<body onunload="closeBotChat();">
and then within this method you simply send an event from your website to your bot that indicates that the conversation is over
function closeBotChat(){
botConnection
.postActivity({
from: { id: '<user>' },
value: "chat <conversationId> closed", //send whatever information you need about the conversation here
type: 'event',
name: "ConversationUpdate"
})
.subscribe(id=> console.log("closed" + id)) // this will likely not be shown unless the botchat is in a modal within the page somewhere
}
The following code when used in your bot will be able to hear and process this event:
bot.on("event", function(e){
console.log(util.inspect(e)); // do whatever with the conversation end event here
});
Note that you do not have to add anything for an "open connection" event with your bot webchat, as a ConversationUpdate event is sent automatically at the start of a new conversation.

Related

Is the Bot Framework Emulator handling new members differently from Bot Framework Webchat?

According to this official sample project (https://github.com/microsoft/BotBuilder-Samples/blob/master/samples/typescript_nodejs/13.core-bot/src/bots/dialogAndWelcomeBot.ts) I can identity new members and send them a welcome message using this (my code):
this.onMembersAdded(async (context) => {
const welcomeCardTemplate = require("../lib/data/resources/cards/welcomeCard.json");
const membersAdded = context.activity.membersAdded;
for (const member of membersAdded) {
if (member.id !== context.activity.recipient.id) {
const welcomeCard = CardFactory.adaptiveCard(welcomeCardTemplate );
await context.sendActivity({ attachments: [welcomeCard] });
}
}
});
It works great when using the emulator. As soon as I connect to the chat I get my welcome message, but when using the Chat on Azure or the WebChat it's not triggered until I first enter some kind of text input to the chat.
One thing I noticed is that when I'm using the emulator two activities are sent to the bot as soon as I connect to the chat, one that contains the Id of the bot and one that contains the Id of the user but when using the other chat options (Azure Chat and WebChat) only one activity is being sent (where the memberId is the same as the recipientId) so it never goes past the if-statement.
What am I missing here, why is only one activity being sent from the Azure Chat and WebChat?
At this time, WebChat and DirectLine behaves differently from the emulator in certain scenarios like the one you describe. There is an open issue for this particular situation where you can find more information.
As stated in the issue, there is a workaround to force the ConversationUpdate event which you can try and test if it suits your needs (I haven't tried myself).

Get notified when user open direct message window with my app bot user

I have a Slack app that has a Bot user, and I want to get notified via the Slack Events API (using #slack/events-api official NPM package) when a user opens the app's Direct Message window of the Bot User (UC: to send him a welcome message).
Looks like the im_open event is what i need but somehow it's not triggered.
I configured it in my app's settings:
And then defined the following code:
const { createEventAdapter } = require('#slack/events-api');
const slackEvents = createEventAdapter('some-secret);
slackEvents.on('im_open', async (event) => {
console.log(`Received a im_open event`);
});
const port = 5000;
slackEvents.start(port).then(() => {
console.log(`server listening on port ${port}`);
});
But it's never triggered.
I have listeners for app_mention and message events that works fine but this one somehow doesn't.
Any idea why?
I think you misunderstand what triggers the im.open event.
It fires when a new direct message channel is established for the first time, not when someone clicks on an existing channel to see its messages. The app channel is created by default during installation of the app. You probably don't see it fired, because it is created before the event handler of your app can be active.
So this will not work and to my knowledge there also is no alternative solution to your problem. Slack events just are not designed to work on the UI level.

How can I get my bot to post a message to a Microsoft Teams channel?

I have a bot that is identical to the one demonstrated in the docs quickstart. It repeats back whatever the user says (for now).
It is currently running locally and exposed with ngrok. I've registered the bot with the Microsoft Bot Framework.
I have configured the Microsoft Teams channel in the Microsoft Bot Framework, and I've sideloaded my bot into Teams. My bot can receive messages from Teams users.
At present, the bot just repeats whatever it receives back to the user, but what I want it to do is post to a Microsoft Teams channel. I want it to post to a Teams channel - not a user - without being prompted first by a user. So for example given a certain condition (eg. triggered by some event such as time of day, a pull request, etc.) it posts a message in a channel.
I've read the documentation about sending proactive messages, and I gather that in order to send a message to a teams channel, the bot needs to know the "address" of the user. This information is stored in the session.message.address object, and it gets this from the current conversation. However, in my case I don't have a 'current conservation', because I don't want to just respond to a user, I want to post in a channel proactively.
So, how do I permanently set the necessary credentials/address/session-data for the Teams channel?
Things I've looked into:
Webhooks. I've configured a webhook in my Teams channel, and I can send it a message easily enough (using the webhook url) using curl. So I can send the Teams channel a simple message with just a url (no authentication required), but I'm not sure how I'd get this url into my bot.
How do we maintain different session for different users in Microsoft Bot Framework? I'm not sure that the answer here answers my question. My problem is that the bot is initiating the 'conversation', not a Teams user, so I need to be able to set the session data myself so the bot knows where to go.
App.js:
require('dotenv').config();
var restify = require('restify');
var builder = require('botbuilder');
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with the Bot Framework Service
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
// Listen for messages from users
server.post('/api/messages', connector.listen());
// Receive messages from the user and respond by echoing each message back (prefixed with 'You said:')
var bot = new builder.UniversalBot(connector, function (session) {
session.send("You said: %s", session.message.text);
});
For anyone who is wondering about the same for c#, here is the solution that worked for me:
var channelData = context.Activity.GetChannelData<TeamsChannelData>();
var message = Activity.CreateMessageActivity();
message.Text = "Hello World";
var conversationParameters = new ConversationParameters
{
IsGroup = true,
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(channelData.Channel.Id),
},
Activity = (Activity) message
};
var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = await
connectorClient.Conversations.CreateConversationAsync(conversationParameters);
Note: If you are calling this outside Bot's controller code then you need to call TrustServiceUrl on serviceUrl as shown here:
MicrosoftAppCredentials.TrustServiceUrl(serviceUrl, DateTime.MaxValue);
var connectorClient = new ConnectorClient(new Uri(serviceUrl));
Source of answer: https://github.com/OfficeDev/BotBuilder-MicrosoftTeams/issues/162
It is definitely possible. We call these proactive messages and it’s possible to proactively message both users and channels.
For the latter, see the sample at https://github.com/OfficeDev/microsoft-teams-sample-complete-node, specifically this file, ProactiveMsgToChannelDialog.ts.
To send proactive messages to channels, you need to use the Microsoft Teams SDK (as these samples do).
Last but not least, you need to add the bot to a team in order to send a message to one of the channels in the team, which requires a manifest.
Hope this works for you.. below code proactively sends the message to session before initiating the chat.
bot.on('conversationUpdate', function (message) {
if (message.membersAdded[0].id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Hello"");
bot.send(reply);
}
});

Respond with a rich message as a Slack bot

I'm working on a Node.js slack app containing a bot user. But I don't know how to respond to a user with a rich message as a bot.
Example:
I can respond with simple messages without problems using this code:
import * as SlackClient from '#slack/client';
slackBot = new SlackClient.RtmClient(bot_access_token)
slackBot.on(SlackClient.RTM_EVENTS.MESSAGE, message => {
slackBot.sendMessage('Hello', message.channel);
});
slackBot.start();
But RTM API doesn't support rich messages:
The RTM API only supports posting simple messages formatted using our default message formatting mode. It does not support attachments or other message formatting modes. To post a more complex message as a user clients can call the chat.postMessage Web API method with as_user set to true.
so I tried to use the web client to respond with rich messages and moved to this code:
import * as SlackClient from '#slack/client';
slackWebClient = new SlackClient.WebClient(access_token);
slackBot = new SlackClient.RtmClient(bot_access_token)
slackBot.on(SlackClient.RTM_EVENTS.MESSAGE, message => {
slackWebClient.chat.postMessage(message.channel, 'Hello', { attachments: myAttachments });
});
slackBot.start();
this approach is working when I testing the bot with my account. But if an other team user writes a DM to the bot, slackWebClient.chat.postMessage fails with the error error: channel_not_found. (I also tried to add a parameter as_user: true - but behaviour is the same, except that messages are signed with my name instead of bot name).
Solved: I created a SlackClient.WebClient instance with the Bot User OAuth Access Token instead of the OAuth Access Token (also with as_user set to true) and now it works as intended. I didn't know that the Bot User OAuth Access Token can be also used as a token for the Web API client.
Working code:
import * as SlackClient from '#slack/client';
slackWebClient = new SlackClient.WebClient(bot_access_token);
slackBot = new SlackClient.RtmClient(bot_access_token)
slackBot.on(SlackClient.RTM_EVENTS.MESSAGE, message => {
slackWebClient.chat.postMessage(message.channel, 'Hello', { attachments: myAttachments, as_user: true });
});
slackBot.start();

Google Cloud Pub/Sub API - Push E-mail

I'm using node.js to create an app that gets a PUSH from Gmail each time an email is received, checks it against a third party database in a CRM and creates a new field in the CRM if the e-mail is contained there. I'm having trouble using Google's new Cloud Pub/Sub, which seems to be the only way to get push from Gmail without constant polling.
I've gone through the instructions here: https://cloud.google.com/pubsub/prereqs but I don't understand how exactly this is supposed to work from an app on my desktop. It seems that pub/sub can connect to a verified domain, but I can't get it to connect directly toto the .js script that I have on my computer. I've saved the api key in a json file and use the following:
var gcloud = require('gcloud');
var pubsub;
// From Google Compute Engine:
pubsub = gcloud.pubsub({
projectId: 'my-project',
});
// Or from elsewhere:
pubsub = gcloud.pubsub({
projectId: 'my-project',
keyFilename: '/path/to/keyfile.json'
});
// Create a new topic.
pubsub.createTopic('my-new-topic', function(err, topic) {});
// Reference an existing topic.
var topic = pubsub.topic('my-existing-topic');
// Publish a message to the topic.
topic.publish('New message!', function(err) {});
// Subscribe to the topic.
topic.subscribe('new-subscription', function(err, subscription) {
// Register listeners to start pulling for messages.
function onError(err) {}
function onMessage(message) {}
subscription.on('error', onError);
subscription.on('message', onMessage);
// Remove listeners to stop pulling for messages.
subscription.removeListener('message', onMessage);
subscription.removeListener('error', onError);
});
However, I get errors as if it isn't connecting to server and on the API list I see only errors, no actual successes. I'm clearly doing something wrong, any idea what it might be?
Thank you in advance!
TL;DR
Your cannot subscribe to push notifications from the client side.
Set up an HTTPS server to handle the messages. Messages will be sent
to the URL endpoint that you configure, representing that server's
location. Your server must be reachable via a DNS name and must
present a signed SSL certificate. (App Engine applications are
preconfigured with SSL certificates.)
Just subscribe to the push notifications on your server, and when you get the notification, you can figure out who it concerns. The data you will get from the notifications is what user that it concerns, and the relevant historyId, like so:
// This is all the data the notifications will give you.
{"emailAddress": "user#example.com", "historyId": "9876543210"}
Then you could e.g. emit an event through Socket.io to the relevant user if he is online, and have him do a sync with the supplied historyId on the client side.

Resources