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();
Related
The "old / version 8" JavaScript API for Firebase messaging had a function for sending a notification to the mobile device:
admin.messaging().sendToDevice(...)
The "new / modular / version 9" JavaScript API fetches the messaging object with getMessaging(app), but this object does not seem to have any function, either actual or documented, to do the equivalent. I cannot find a similar function anywhere in the new API--not even in "messaging-compat", which is supposed to simulate the old API in the new one. Is it just not there? Will I have to forgo the new API entirely just to get this one function? Or perhaps is this functionality moved to some other API?
I'm trying to do this from within a Firebase Cloud Function, if that matters.
As far as I can see, you can just pass the token in the to property of the JSON object you pass to send like shown in this code from the documentation on sending messages to specific devices:
// This registration token comes from the client FCM SDKs.
const registrationToken = 'YOUR_REGISTRATION_TOKEN';
const message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
getMessaging().send(message)
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).
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.
I've got a chatbot up and running, built using Node.JS Microsoft Bot Framework, and deployed to an Azure server as a Web App, with a Bot Channels Registration resource as the frontend endpoint.
This Bot Channels Registration is connected to Facebook Messenger (via a FB App) - meaning, the webhook for the Facebook App points to https://facebook.botframework.com/api/v1/bots/<BOT_CHANNELS_REGISTRATION_RESOURCE_NAME>.
This all works well for normal chat functionality.
However, I'd now like to add an opt-in checkbox to a separate web page I have. This checkbox works by pinging FB, which then sends a very specific payload to the already configured bot webhook.
{
"recipient":{
"id":"<PAGE_ID>"
},
"timestamp":<UNIX_TIMESTAMP>,
"optin":{
"ref":"<PASS_THROUGH_PARAM>",
"user_ref":"<UNIQUE_REF_PARAM>"
}
}
My question is this:
How does the Bot Channels Registration receive and handle the above payload? Will it just automatically forward it to the Messaging Endpoint I have configured in the Bot Channels Registration settings? Or will it get stuck, and never reach my actual bot Web App?
Finally, if it does reach my normal messages endpoint, how can I handle the specific payload with my botbuilder.ChatConnector() listener? Given that my web app code looks like (in essence)
var restify = require('restify');
var builder = require('botbuilder');
var dialogues = require('./dialogues');
var chatbot = function (config) {
var bot = {};
chatbot.listen = function () {
var stateStorage = new builder.MemoryBotStorage();
var connector = new builder.ChatConnector({
appId: process.env.APP_ID,
appPassword: process.env.APP_PASSWORD
});
bot = new builder.UniversalBot(connector, function (session) {
session.beginDialog(dialogues.base(bot).name);
}).set('storage', stateStorage);
return connector.listen();
};
return chatbot;
}
var server = restify.createServer();
// Listen for messages from users
server.post('/api/messages', chatbot.listen());
server.listen(process.env.port, function () {
console.log('%s listening to %s', server.name, server.url);
});
Thanks!
EDIT: I've figured out how to handle the above payload within my messaging endpoint - by adding a server.pre() handler to my server, e.g.
server.pre(function (req, res, next) {
if (req.body && req.body.optin_payload_specific_field){
// handle opt-in payload
} else {
return next();
}
});
However, via extra logging lines, it seems the opt-in payload isn't even making it to this endpoint. It seems to be stopped within the Bot Channels Registration. Currently looking for a way to resolve that major roadblock.
So, per #JJ_Wailes investigation, it seems like this is not a supported feature (in fact, it's a current feature request). See his comments on the original post for more details.
However, I did find a half-workaround to capture the user_ref identifier generated by the checkbox_plugin, for those interested:
1) From your external site, follow the steps from the documentation here for sending the initial user_ref to FB. FB will then make a callout to your bot, but per the above, that gets blocked by the Bot Channels Registration piece, so it's ignored.
2) From that same external site, use the user_ref to send a message to the user (just using the normal requests library). A successful send means that the user_ref was properly registered in FB by that step #1 call - a failure means you'll need to repeat step #1 (or use some other error handling flow).
3) After that, the next time the user responds to your bot in FB (as long as you don't send any other messages to them), the message your bot will receive will contain this as part of the payload:
{ ...
channelData:
{ ...
prior_message:
{ source: 'checkbox_plugin',
identifier: <user_ref> }
}
}
So I've currently added a check within my bot.use(), where if that section is present in the incoming message payload (session.message.sourceEvent.prior_message) and the source is "checkbox_plugin", I store the corresponding user_ref in the session.userData, and can work from there.
I would love to see this feature added into the supported Azure bot stack, but in the meantime hopefully this helps anyone else encountering this (admittedly niche) hurdle.
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);
}
});