Using Slackbots(https://www.npmjs.com/package/slackbots) I was hoping to build a simple message forwarding bot (i.e. when the bot receives a direct message, it shoots it into a chat room and says who it is from) but I can't seem to get it to push out user names, only user ID's. Any idea here?
var SlackBot = require('slackbots');
var bot = new SlackBot({
token: 'xoxb-',
name: 'helper'
});
bot.on('start', function() {
var params = {
icon_emoji: ':cat:'
};
bot.postMessageToChannel('helpertest', 'meow!', params);
});
bot.on('message', function(data) {
bot.postMessageToChannel('helpertest', data.text + data.user.name);
})
Related
How can I make my bot receives responses without using force_reply? something like botFather does?
Let say I've sent message to user like this:
bot.sendMessage(chatId, 'What is your name?', { parse_mode: 'HTML' });
Now how do I get user response?
Without the help of force_reply, you'll need to write some custom logic. I've implemented this in my custom bots like so:
Send question to user bot.sendMessage() and remember the ID
Wait for a message bot.on('message')
Check if we're waiting for on a reply from this user
Reply accordingly
// Create bot
const TelegramBot = require('node-telegram-bot-api');
const bot = new TelegramBot('XXXXXXXX:AAEibBwftjTEKuYd9d2X0ACeyyzTk4DLe60', {
polling: true
});
// List of id's we're waiting for
const wait = [];
// Hardcoded chat id
const chatId = 1234567;
// Ask and add to wait list
bot.sendMessage(chatId, 'What is your name?', { parse_mode: 'HTML' });
wait.push(chatId);
// On message
bot.on('message', (msg) => {
// Check we're waiting on this user
if (wait.includes(msg.chat.id)) {
// Send reply
bot.sendMessage(chatId, 'Your name: ' + msg.text );
// Remove from wait list
wait.splice(wait.indexOf(msg.chat.id), 1);
} else {
// Normal message; notify user
bot.sendMessage(chatId, 'Hi! I\'m not expecting a reply from you! How can I help?');
}
});
Note: This is just an example! The code can be extended to include multiple checks, and possibly states to see what message the user is replying on.
I am using botframework v4, but coming over from v3, I have not found any documentation that is similar to the code I use below but for v4, regarding sending proactive messages from Azure Function App
Below is the code I previously used but am having trouble adapting:
var builder = require('botbuilder');
// setup bot credentials
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
module.exports = function (context, req) {
if (req.body) {
var savedAddress = req.body.channelAddress;
var inMemoryStorage = new builder.MemoryBotStorage();
var bot = new builder.UniversalBot(connector).set('storage', inMemoryStorage);
sendProactiveMessage(savedAddress, bot)
}
};
function sendProactiveMessage(address, bot) {
var msg = new builder.Message().address(address);
msg.textLocale('en-US');
var img = {
attachments: [{
contentType: "image/jpg",
contentUrl: latestUrl,
}]
};
msg.addAttachment(img.attachments[0]);
msg.text('hello');
bot.send(msg);
}
This works fine with v3 but not v4.
If possible I would also like to find a way to log a user out:
await botAdapter.signOutUser(innerDc.context, this.connectionName);
This is how I do it in the bot itself, but doing so from Azure Functions again is proving difficult.
Any help would be appreciated.
Great that you are making the move from v3 to v4! Have you had a look at Send proactive notifications to users? This example is pretty straight forward and can be used within an Azure function.
First you retrieve the Conversation Reference in your bot by calling TurnContext.getConversationReference(context.activity);. This is the reference you could use in your proactive function to open the conversation. In your case you provide that via the request body to a proactive function, so I will do the same in my example.
My proactive endpoint example is written in Typescript, however it works the same way in plain Javascript. Create a HTTP trigger in Azure Functions and use the following code. I have added comments inline for clarity.
const { BotFrameworkAdapter } = require('botbuilder');
// Create adapter.
// If you need to share this adapter in multiple functions, you could
// instantiate it somewhere else and import it in every function.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
module.exports = async function (context, req) {
// Validate if request has a body
if (!req.body) {
context.res = {
status: 400,
body: "Please pass a conversation reference in the request body"
};
return;
}
// Retrieve conversation reference from POST body
const conversationReference = req.body;
// Open the conversation and retrieve a TurnContext
await adapter.continueConversation(conversationReference, async turnContext => {
// Send a text activity
// Depending on the channel, you might need to use https://aka.ms/BotTrustServiceUrl
await turnContext.sendActivity('Proactive hello');
});
context.res = {
body: 'Message sent!'
};
};
In the end you could make a request to this Azure Function, where you pass the Conversation Reference as body of the type application/json.
Extending this example with features like signOutUser is simple. You can call all functions within the continueConversation function, just as in a normal bot. You can even receive the adapter object there if you wish.
await adapter.continueConversation(conversationReference, async turnContext => {
// Sign user out
turnContext.adapter.signOutUser(turnContext, 'connection-name');
});
This might be very simple, but I cannot find any reference regarding this.
I integrated the chat bot in the web app using direct line API; I’m using this API to generate conversation id:
POST: https://directline.botframework.com/v3/directline/conversations
I’m trying to get the generated conversation id from the above API (from web app code) to the chatbot code (NodeJS). Is there a way or any reference to do this?
one way as per this issue comment is to send data to bot before starting the conversation using:
var params = BotChat.queryParams(location.search);
var my_token = params['my_token'];
var botConnection = new BotChat.DirectLine({
secret: 'DIRECTLINE_SECRET'
});
BotChat.App({
botConnection: botConnection
,user: { id: 'USER_ID', name: 'User' } // user.id auto updates after first user message
}, document.getElementById("bot"));
botConnection.connectionStatus$.subscribe(function (status) {
if (status == 2) { // wait for connection is 'OnLine' to send data to bot
var convID = botConnection.conversationId;
botConnection.postActivity({
from: { id: convID } // because first time user ID == conversation ID
,type: 'event'
,name: 'registerUserData' // event name as we need
,value: my_token // data attached to event
}).subscribe(function (activityId) {
// This subscription is a MUST
// If I remove this handler the postActivity not reaches the bot
});
}
});
Here you subscribe to the botConnection.connectionStatus$ and when the status is equal to 2, you get the conversation ID from the botConnection object.
Then, you can add this middleware code in the bot code to get the data:
bot.use({ receive: function(event, next) {
if (!!event && !!event.address && event.name == 'registerUserData') {
var message = new builder.Message().address(event.address).text('my_token:' + event.value);
bot.send(message, function (err) {}); // simulate proactive message to user
}
next();
} });
Hope this helps.
I resolve it using Botframework Web Chat back channel, here's the link for reference:
https://github.com/Microsoft/BotFramework-WebChat
After I generated the conversation id using directline API:
POST: https://directline.botframework.com/v3/directline/conversations
I send data from the web app to the chatbot via backchannel.
<div id="webchat"></div>
<script>
(async function () {
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
// When we receive DIRECT_LINE/CONNECT_FULFILLED action, we will send an event activity using WEB_CHAT/SEND_EVENT
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { conversation_id: conversationID }
}
});
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
//Note: conversationID and token is generated in the backend code of the web app.
</script>
When i try to start up my bot via node the program quits again without any errors
var Discord = require('discord.io');
var bot = new Discord.Client({
token: "nope"
});
bot.connect();
console.log("hi");
bot.on('ready', function (evt) {
console.log('Connected');
});
bot.on('message', function (user, userID, channelID, message, event) {
bot.sendMessage({
to:channelID,
message:"user, userID, channelID, message, evt:"+user + userID + channelID+ message+ event
});
});
My issue was the token which was somehow breaking stuff.
My workaround, was by just coping my token from the ./auth.json and place in it manually inside the client variable. (which was retriving from the file)
before:
var client = new Discord.Client({
token: auth.token,
autorun: true
});
after:
var client = new Discord.Client({
token: "REPLACE_THIS_WITH_YOUR_TOKEN",
autorun: true
});
Im building a chat application in node.js , socket.io and mongoose. My goal is to build a one on one chat, it is similar like facebook web chat. So basically whenever I click on a user it will go to that user url and possibly chat with him/her
But the problem, that I'm facing is that I could only emit the message to the targeted user, but not to myself.
Here's the current code
Serverside
socket.on('chatTo', function(data){
User.findOne({ username: data.destinationUsername, socketId: { '$ne': null}}, function(err, foundUser) {
if (foundUser) {
io.to(foundUser.socketId).emit('incomingChat', { sender: user.username, message: data.message });
} else {
io.to(socket.id).emit('deliverError', { error: foundUser + ' is not online' });
}
});
});
Clientside
$(function() {
var socket = io();
function chatTo(message, destinationUsername) {
socket.emit('chatTo', { message: message, destinationUsername });
}
$('#sendMessage').submit(function(){
var input = $('#message').val();
var username = $('#username').val();
chatTo(input, username);
$('#message').val('');
return false;
});
socket.on('incomingChat', function(data) {
var html = data; // Messages to append to media-list
$('.media-list').append(html);
});
});
So what is happening here is that, on the clientside, User A clicks form submit , to submit the message, it will invoke chatTo function and emit the data. Just want to let you guys know, input and username are from html page. It would look something like this
input = "Hello";
username = "jackmoscovi" // user's username
then it will emit both of these data back to server, which is socket.on('chatTo') is listening to. After some MongoDB operation, if found the user then emit to that specific socket.
The result will be
The message that was emitted by batman only shows up on joker's page but not on Batman's page. I know that because I specifically emit to that socket. The real question is How do I force both of these user to be in a unique room? Should I create a new Room mongoose model? and then call socket.join('uniqueRoom')?
and then simply io.to('uniqueRoom').emit("Message?");
How would I implement this room mechanism?
I have been struggling for 2 days already, please someone end this misery :(
First create a mongoose schema like this
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var messageSchema=new Schema({
sender : {
type : String,
},
receiver : {
type : String.
},
message : {
type : String
}
})
mongoose.model('messages',messageSchema);
Then in server code
message = mongoose.model('messages')
socket.on('chatTo', function(data){ // data is json containing sender, receiver and message
User.findOne({ username: data.destinationUsername, socketId: { '$ne': null}}, function(err, foundUser) {
if (foundUser) {
io.to(foundUser.socketId).emit('incomingChat', { sender: user.username, message: data.message });
socket.emit('incomingChat', { sender: user.username, message: data.message });
var newMessage = new message({
sender : data.sender,
receiver : data.receiver,
message : data.message
})
newMessage.save(function (err, data){
if(err)
console.log(err)
})
} else {
io.to(socket.id).emit('deliverError', { error: foundUser + ' is not online' });
}
});
});
This is a little bit of a difficult one to answer because it feels like you are actually asking the wrong question. To understand how you are "supposed" to do this you really have to have solved quite a few other architectural issues first.
The first thing you need to solve is the Authentication/Authorisation problem i.e. when you connect a socket from the browser to the server how does your server know who you are and know that you're not an imposter? I don't have a best practice for this but you might want to check out the socketio-auth package which might give you a few ideas.
The second thing you need to solve is how to associate the authenticated user with the socket. The only source that I could find that has any reference to this is in the chat demo on the socket.io website.
At this point, you should have a collection of sockets in your server that have associated users. When Batman comes online you should check the database for any Chats that he is part of and have him connect to that chat room by id:
Chat.find({usernames: "Batman"}).exec().then(function(chats){
chats.forEach(function(chat){
socket.join(chat.id);
})
});
So this so far is assuming that Joker hasn't already created a chat with Batman, and hence there is not a chat in the database that connects them both.
When Joker wants to chat to batman you need to send a "connect" message down the socket that
creates a chat with both of them in it
finds both their current sockets if they are currently connected to the server and
sends a message that they have connected to each other
example:
socket.on('startChat', function(data){
//assuming that you have assocated the current user with the socket
var currentUser = socket.user;
//who the current user (Joker) wants to connect to
var connectToUser = data.connectToUser; // Batman
Chat.create({
usernames: [currentUser.username, connectToUser.username] // ["Joker", "Batman"]
}).then(function(newChat){
socket.join(newChat.id); // add current user (Joker) to that socket.io room
// this is overly simplified: assuming you have an array collectionOfConnectedSockets which
// contains all currently connected sockets
var otherUserSocket = collectionOfConnectedSockets[connectToUser.username];
//otherUserSocket now is Batman's socket - so make him join the room
otherUserSocket.join(newChat.id);
//send them both a message that a chat has been connected
io.to(newChat.id).emit('You have been connected to a new chat');
});
});
Now this brushes over a lot of the details, and each of those details depend on your application's architecture. Also my syntax may be a little off, the examples are only given as an indication of you should be trying to do and not as a direct solution to your problem.