Bot Hangouts Chat API - Not Working in ROOM - bots

I have a simple bot that identify a tag "#Ticket" and send an email.
My Bot in DM works, but when i join the bot into a room, it doesn't work.
Hangouts Chat API functionality - bot works in rooms and bot works in direct messages are enabled
My code is:
function onMessage(event) {
console.info(event);
var name = "";
if (event.space.type == "DM") {
name = "You open:";
} else {
name = event.message.sender.displayName + " open:";
}
var message = name + event.message.text.toUpperCase() + "\"";
if (message) {
if (message.indexOf('#Ticket') > -1) {
MailApp.sendEmail("email-account", name + "ticket", message);
}
}
}
function onAddToSpace(event) {
console.info(event);
var message = "";
if (event.space.type == "DM") {
message = "Tickets in DM, " + event.user.displayName + "!";
} else {
eturn { "text": message }; message = "Tickets add to " + event.space.displayName;
}
}
function onRemoveFromSpace(event) {
console.info("Tickets removed ", event.space.name);
}
Can someone help me?
Thanks

I debug the bot and I noticed that when bot is a member of a room, the sent message does not generate any events.
Event generated in DM
jsonPayload: {
configCompleteRedirectUrl:
"https://chat.google.com/api/bot_config_complete?token=XXXXXX"
eventTime: {…}
message: {
argumentText: "#Ticket: Open"
createTime: {…}
name: "spaces/XXXXXX/messages/XXX.XXX"
sender: {…}
space: {…}
text: "#Ticket: Open"
thread: {…}
Event generated in ROOM
No logs are found
In the API references we have event fields:
Event fields
I don´t know if a bot being a member of a room, can recognize all the events generated in the room (event.message.text) or is it really necessary to click on the bot and start a DM, necessary for the events (event.message. text) are recognized.

Related

how do i collect dms and send them into a channel on a server

I'm trying to make the bot receive DMS and send the received DMS into a channel. It already creates the channel and dms the user on command but idk how to receive & send the received dms in a channel. thanks for helping:)
run(client, message, args) {
message.guild.channels
.create(this.name, { type: 'text', })
.then((channel) => {
const catogaryID = '850020908596592713'
channel.setParent(catogaryID)
})
message.channel.send('<#839172815025340426> s1 needs help')
message.author.send('whats wrong')
What you can do is create a Map which stores the user's name and the channel that you want to post their messages to, something like this:
In your main file somewhere
// Stores the information somewhere that it can easily be retrieved
client.modmailThreads = new Map(); // I'm assuming this is what you want to achieve
Listening to new messages
client.on("message", message => {
// Your other code here
if(message.channel.type == "dm" && client.modmailThreads.get(message.author.id)) { // If this is a DM and the user has a modmail channel
client.channels.cache.get(client.modmailThreads.get(message.author.id)).send(message.content); // Get their modmail channel and send the message to it
}
});
In your current code
run(client, message, args) {
message.guild.channels
.create(this.name, { type: 'text', })
.then((channel) => {
const catogaryID = '850020908596592713'
channel.setParent(catogaryID)
client.modmailThreads.set(message.author.id, channel.id); // Store value
})
message.channel.send('<#839172815025340426> s1 needs help')
message.author.send('whats wrong')
Obviously this is only an example so you may want to do some more modifications yourself.

Using conditional operators with QnAMaker - operators aren't routing correctly

I'm having difficulty figuring out what most likely is a simple issue, which relates to a 'if then else' problem in my code (NodeJS, Bot Framework v4).
I can't quite figure out why the relevant card isn't being shown depending on the number of semi-colons it finds in the response string from QnAMaker.
When testing with the Bot Framework emulator, it only returns one response type, whether that's plain text or one Rich Card no matter how many semi-colons are in the response.
I've tried to see if it's the length of the string it's having problems with by parsing the number value in the length statement. Didn't make a difference sadly. Notably if I use any other conditional operator such as '===' for example, it breaks the response completely.
const { ActivityTypes, CardFactory } = require('botbuilder');
const { WelcomeCard } = require('./dialogs/welcome');
// const { HeroCard } = require('./dialogs/welcome');
// const { VideoCard } = require('./dialogs/welcome');
class MyBot {
/**
*
* #param {TurnContext} on turn context object.
*/
constructor(qnaServices) {
this.qnaServices = qnaServices;
}
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
for (let i = 0; i < this.qnaServices.length; i++) {
// Perform a call to the QnA Maker service to retrieve matching Question and Answer pairs.
const qnaResults = await this.qnaServices[i].getAnswers(turnContext);
const qnaCard = qnaResults.includes(';');
// If an answer was received from QnA Maker, send the answer back to the user and exit.
if (qnaCard.toString().split(';').length < 3) {
await turnContext.sendActivity(qnaResults[0].answer);
await turnContext.sendActivity({
text: 'Hero Card',
attachments: [CardFactory.heroCard(HeroCard)]
});
} else if (qnaCard.toString().split(';').length > 3) {
await turnContext.sendActivity(qnaResults[0].answer);
await turnContext.sendActivity({
text: 'Video Card',
attachments: [CardFactory.videoCard(VideoCard)]
});
} else if (qnaCard.toString().split(';').length === 0) {
await turnContext.sendActivity(qnaResults[0].answer);
return;
}
}
// If no answers were returned from QnA Maker, reply with help.
await turnContext.sendActivity('No QnA Maker answers were found.');
} else {
await turnContext.sendActivity(`[${ turnContext.activity.type } event detected]`);
} if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
// Handle ConversationUpdate activity type, which is used to indicates new members add to
// the conversation.
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
// Do we have any new members added to the conversation?
if (turnContext.activity.membersAdded.length !== 0) {
// Iterate over all new members added to the conversation
for (var idx in turnContext.activity.membersAdded) {
// Greet anyone that was not the target (recipient) of this message
// the 'bot' is the recipient for events from the channel,
// context.activity.membersAdded == context.activity.recipient.Id indicates the
// bot was added to the conversation.
if (turnContext.activity.membersAdded[idx].id !== turnContext.activity.recipient.id) {
// Welcome user.
// When activity type is "conversationUpdate" and the member joining the conversation is the bot
// we will send our Welcome Adaptive Card. This will only be sent once, when the Bot joins conversation
// To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details.
const welcomeCard = CardFactory.adaptiveCard(WelcomeCard);
await turnContext.sendActivity({ attachments: [welcomeCard] });
}
}
}
}
}
}
module.exports.MyBot = MyBot;
Ideally, what I'm hoping to see is if I ask a question which has 3 semi-colons in the response, it outputs a Hero Card. If it has more than 3, then a Video Card and if it doesn't have either, a text response.
I'm not a js specialist, but I'm quite confused by the following:
const qnaCard = qnaResults.includes(';');
In Javascript, includes is the following (source):
The includes() method determines whether an array includes a certain
value among its entries, returning true or false as appropriate.
So here your qnaCard is true or false. But it looks like you are trying to use it as if it was containing the text:
if (qnaCard.toString().split(';').length < 3) {
...
You have to work on the object containing the answer: qnaResults[0].answer.

wait for user input to reply on a facebook bot using Node.js

What I need to do is make my bot after replying to something wait for user response so that he can reply with a flow ending messege Example:
User: clicks the Get Started button
Bot: I can help you with the following (Payment) (option2) (option3)
User: clicks Payment
Bot: Can you please enter the bill number
User:3922509234
.............................
Bot:Ok thank you, your payment will be processed
this is how the facebook app comunicates with the bot
app.post('/webhook', function(request, response) {
var data = request.body;
if(data.object == 'page'){
data.entry.forEach(function(pageEntry){
pageEntry.messaging.forEach(function (messagingEvent) {
if(messagingEvent.message){
console.log("MESSAGE---------------------> ",messagingEvent);
var messageInfo = functions.reciveMessage(messagingEvent);
console.log("MESSAGEINFO ", messageInfo);
evaluateMessage(messageInfo);
}
if(messagingEvent.postback){
console.log("POSTBACK--------------------> ",messagingEvent);
var postBackInfo = functions.recivePostBack(messagingEvent);
evaluatePostBack(postBackInfo);
}
});
});
response.sendStatus(200);
}
});
This is where the user's input is evaluated for keywords
function evaluateMessage(messageInfo, type) {
if(functions.isWordContain(messageInfo.senderMessage,'Pagar')||
functions.isWordContain(messageInfo.senderMessage,'pagar')||
functions.isWordContain(messageInfo.senderMessage,'Factura')||
functions.isWordContain(messageInfo.senderMessage,'factura')){
var message = functions.sendTextMessage(messageInfo.senderId, "Por
favor ingresa el numero de tu contrato");
callSendAPI(message);
}
}
The messageInfo is check if contains the keyWord then returns the message to the user.
How do i make the bot wait for user input so that he can reply
Im using Node.Js with express not any bot building platform please help
I found an easy way of doing this though there might be a better way a made a global variable
var verifier = {
origin:null,
state:false
};
then when it enters the message validator and modifies the json with a sort of token and sets the state to true
function evaluateMessage(messageInfo) {
if (functions.isWordContain(messageInfo.senderMessage,'Pagar')||
functions.isWordContain(messageInfo.senderMessage,'pagar')||
functions.isWordContain(messageInfo.senderMessage,'Factura')||
functions.isWordContain(messageInfo.senderMessage,'factura')){
var message = functions.sendTextMessage(messageInfo.senderId, "Por favor
ingresa el numero de tu contrato");
verifier.origin = 'pagoFactura';
verifier.state = true;
callSendAPI(message);
}
}
later where the messages enter I just ask if that state is true and which is the origin and depending if its one or the other I send a message
app.post('/webhook', function(request, response) {
var data = request.body;
if(data.object == 'page'){
data.entry.forEach(function(pageEntry){
pageEntry.messaging.forEach(function (messagingEvent) {
if(messagingEvent.message){
if(verifier.state == false){
console.log("MESSAGE---------------------> ",messagingEvent);
var messageInfo = functions.reciveMessage(messagingEvent);
console.log("MESSAGEINFO ", messageInfo);
evaluateMessage(messageInfo);
}else {
console.log("verifierOrigin ", verifier.origin);
var messageInfo = functions.reciveMessage(messagingEvent);
switch (verifier.origin) {
case 'pagoFactura':
var message = functions.sendTextMessage(messageInfo.senderId,
"Gracias su pago se a procesado exitosamente");
callSendAPI(message);
break;
default:
}
}
}
if(messagingEvent.postback){
console.log("POSTBACK--------------------> ",messagingEvent);
var postBackInfo = functions.recivePostBack(messagingEvent);
evaluatePostBack(postBackInfo);
}
});
});
response.sendStatus(200);
}
});
If someone finds a better way please comment also I know this is not the best way this is just for testing purposes

Slack Bot Replying to his own message in Node js

I am trying to make a slack bot in nodejs that replys the user based on their input. But As far now the bot keeps replying to his own messages
this is the code for my bot
let Bot = require('slackbots');
// create a bot
let settings = {
token: 'xoxb-10584202949',
name: 'BotHelp'};
let bot = new Bot(settings);
bot.on('start', function() {
bot.postMessageToChannel('general', 'At your service');
});
bot.on('message',function (data) {
console.log(data);
if (data.username != "BotHelp" && data.subtype != 'bot_message'){
bot.postMessageToChannel('general', 'Yoooo');
}
});
The Console log for data Prints
{ type: 'hello' }
{ text: 'At your service',
username: 'BotHelp',
bot_id: 'B336WGVSM',
type: 'message',
subtype: 'bot_message',
team: 'T2ZAW44P3',
user_team: 'T2ZAW44P3',
channel: 'C303W2D4M',
ts: '1479877794.000266' }
{ type: 'presence_change',
presence: 'active',
user: 'U33QS0VEF' }
So why my validation is failing to check that the message has been sent from bot itself or not?
Thank you for your time
I had the same issue. The message event in slackbots fires for every event ie, user_typing, message_marked, desktop_notification. All events can be found here.
Now what i did to ensure my bot didn't send a message after receiving its own was:
bot.on('message',function (data) {
if (data.user != "Uxxxxxx" && data.message === 'message'){
bot.postMessageToChannel('general', 'Yoooo');
}
the data.user gives a unique id, you can get this by console.log(data) and find your user id.
Also, if you want to specify which message you want to listen to, say direct message. channel id inside data will start with a D. For private channels, the channel id starts with G
Hope this helps. I know there is much more to do here but this is the basic. And you can grow on this. I know I will be trying to :D
I know that the question is already answered but I will like to add my answer, because the slack api has made some changes.
if (data.type !== "message" || data.subtype === 'bot_message' ){
return;
}
else{
bot.postMessageToChannel('general', 'Yoooo');
}
If I were you I'd check if the parameters are really user_name and subtype . If it's right, I would try to check the type of the objects that are coming(Maybe there is a cast in objects coming from the Slack api). I've done a small project very similar to yours, using the same library slackbots and also a library I built myself,nodejslack(https://github.com/marcogbarcellos/nodejslack) but didn't get this issue.

Handle XMPP presence with Node

I'm using the node-xmpp module to connect to a XMPP server and join a group chat. Connecting to the server, setting the presence, joining the room and reading out messages works so far. But I want to receive the userlist of the room too.
The XMPP protocol requires to send a presence stanza when the client enters the room (http://xmpp.org/extensions/xep-0045.html#enter-pres). But how can I now parse it in node?
My code currently looks like this:
var xmpp = require('node-xmpp');
// Create the XMPP Client
var cl = new xmpp.Client({
jid: jid,
password: password,
reconnect: true
});
// Do things when online
cl.on('online', function() {
util.log("We're online!");
// Set client's presence
cl.send(new xmpp.Element('presence', { type: 'available' }).c('show').t('chat'));
cl.send(new xmpp.Element('presence', { to: room_jid+'/'+room_nick }).c('x', { xmlns: 'http://jabber.org/protocol/muc' }).c('history', {seconds: 1}));
// Send keepalive
setInterval(function() {
cl.send(' ');
}, 30000);
cl.on('stanza', function(stanza) {
// always log error stanzas
if (stanza.attrs.type == 'error') {
util.log('[error] ' + stanza);
return;
}
// ignore everything that isn't a room message
if (!stanza.is('message') || !stanza.attrs.type == 'chat') {
return;
}
var body = stanza.getChild('body');
// message without body is probably a topic change
if (!body) {
return;
}
// Extract username
var from, room, _ref;
_ref = stanza.attrs.from.split('/'), room = _ref[0], from = _ref[1];
var message = body.getText();
// Log topics and messages to the console
if(!from) {
util.log('Topic: ' + message);
} else {
util.log('[' + from + ']: ' + message);
}
});
});
I already tried triggering presence by using
if(stanza.is('presence')) {}
within the cl.on('stanza') part but it doesn't work.
UPDATE: I'm describing a new method now which doesn't require the client to send requests.
Background: When the client joins a group chat, the server returns presence stanzas which contain information about the connected users to the group chat.
cl.on('stanza', function(stanza) {
// always log error stanzas
if (stanza.attrs.type == 'error') {
util.log('[error] ' + stanza);
return;
}
if(stanza.is('presence')){
// We are only interested in stanzas with <x> in the payload or it will throw some errors
if(stanza.getChild('x') !== undefined) {
// Deciding what to do based on the xmlns attribute
var _presXmlns = stanza.getChild('x').attrs.xmlns;
switch(_presXmlns) {
// If someone is joining or leaving
case 'http://jabber.org/protocol/muc#user':
// Get the role of joiner/leaver
_presRole = stanza.getChild('x').getChild('item').attrs.role;
// Get the JID of joiner/leaver
_presJID = stanza.getChild('x').getChild('item').attrs.jid;
// Get the nick of joiner/leaver
_presNick = stanza.attrs.from.split('/')[1];
// If it's not none, this user must be joining or changing his nick
if(_presRole !== 'none') {
// We are now handling the data of joinging / nick changing users. I recommend to use an in-memory store like 'dirty' [https://github.com/felixge/node-dirty] to store information of the users currentliy in the group chat.
} else {
// We are now handling the data of leaving users
}
break;
}
return;
}
return;
}
OLD METHOD
I previously described a method how to query the server for current users in the group chat. By maintaining a store where all user traffic (joining, leaving, nick changing) is stored, this is no longer required. However you could still use it to make sure the data is consistent by issues like a presence stanza was not delivered to the client correctly. That's the reason it's still described below:
To request a list with users connected to the room, you need to perform the following actions:
First send a request to the server and ask for the user list:
cl.send(new xmpp.Element('iq', {from: jid, to: room_jid, type: 'get' }).c('query', { xmlns: 'http://jabber.org/protocol/disco#items' }));
then listen for iq-stanzas, parse them and populate an array with the data:
// Catching the requested user list
if(stanza.is('iq')){
// Fetching usernames from return data (data structure: http://xmpp.org/extensions/xep-0045.html#example-12)
var _items = stanza.getChild('query').getChildren('item');
var users = new Array();
for(var i = 0; i<_items.length; i++) {
// We are building an object here to add more data later
users[i] = new Object();
users[i]['name'] = _items[i].attrs.name;
}
console.log(util.inspect(users, {depth: null, colors: true}));
return;
}
This will provide you with a user list. To request unique JIDs you have to probe every user. To keep the list up to date, you should remove users when they leave and add + probe when they join.

Resources