intercept user message to modify it , bot framework - javascript

I am using a bot framework with direct line, and I would like to intercept the user's message before sending it to the server to modify it.
The idea is that if the user enters some phone number, credit card, etc, modify that part of the message by asterisks for example, and that does not travel the message with that data to the server.
I have tried to configure some event or activity but I can not do it.
I have tried using javascript, create an addeventlistener to the inputBox and the button, but when that event is launched the message can no longer be modified
any ideas?
conect.activity$
.filter(function (activity) {
return activity.type === 'endOfConversation';
})
.subscribe(function (activity) {
console.log('RemoveLocalStorage endOfConversation');
RemoveLocalStorage("paramCon");
});
BotChat.App({
botConnection : conect,
speechOptions: speechOptions,
user: user,
bot: bot,
typing:false,
locale: (params.locale !== undefined) ? params.locale : "es-es",
resize: 'detect'
},window.parent.frames["chatBot"].document.getElementById('bot'));
//window.frames[0].document.getElementById('bot')
//document.getElementById("bot")
window.parent.frames["chatBot"].document.getElementsByClassName("wc-send")[0].addEventListener("click", disableSensitiveData);
window.parent.frames["chatBot"].document.getElementsByClassName("wc-textbox")[0].addEventListener("keyup", disableSensitiveData);

You can create a custom middleware to intercept and modify the text attribute of messages when the user hits send. I created examples in V3 and V4 of Webchat below that convert the entire message to asterisks.
WebChat V4
// We are adding a new middleware to customize the behavior of WEB_CHAT/SEND_MESSAGE.
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'WEB_CHAT/SEND_MESSAGE') {
// Edit text when user sends message
action.payload.text = action.payload.text.split('').map(_ => '*').join('')
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store
}, document.getElementById('webchat'));
Checkout the WebChat Repository for more samples and information about v4.
WebChat V3
We are going to modify how the bot handles posting activities to intercept and modify the message from the user.
var dl = new BotChat.DirectLine({ secret: '<SECRET>' });
BotChat.App({
botConnection: Object.assign({}, dl, {
postActivity: activity => {
// Edit text when user sends message
activity.text = activity.text.split('').map(_ => '*').join('');
return dl.postActivity(activity);
}
}),
bot: 'bot',
user: 'user',
resize: 'detect',
}, document.getElementById('bot'));
Hope this helps!

Related

why messaging().sendtodevice is not working sometimes?

I'm using the following code to send a notification from one device to another using FCM. Everything works fine until before return admin.messaging().sendToDevice(...). The 'Token ID: ' log displays token ID of the receiver, but when I set the variable token_id to the sendToDevice function, the notification is not called, therefore the notification is not sent. Can someone tell me what's wrong?
var firebase = require("firebase-admin");
var serviceAccount = require("./julla-tutorial.json");
console.log("enter in then Firebase Api");
const firebaseToken = [
'e0T6j1AiRjaa7IXweJniJq:APA91bHNznSHSIey08s-C-c3gchci6wepvhP1QxQyYbmZ8LySI3wnu64iW7Q23GhA6VCdc4yodZoCFOgynfAb5C8O8VE81OcSv_LL-K3ET1IKGZ_6h35n-_q5EKFtfJWlzOqZr4IvpiB',
'dNWnSqyCQbufzv1JutNEWr:APA91bFcI9FDyRxHRBEcdw4791X0e-V0k1FjXcSstUA67l94hSojMRCd6LWr2b57azNEt3z_XLwLljMX4u2mc9cZDrAVm55Mw9CHGyue-09KofWnnHNR9XWBibc4T76xOV_DWX7T2RvW',
'cq65rtuaTCKGk5lHk7UabN:APA91bFR3kAArg6lhuBq7ktNuBk7Z9MXXk3PskqhYa8CgNaEl6MX4TQ5lo35d6XhnCQ4fEkCkyZ_j08evxE9Y4oVCRTEdqsrkccCVTE8Di47lfmDR3i1NdoL3re9oLw6F_uNsnvRoQcq'
]
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount)
})
const payload = {
notification: {
title: 'Demo 2345',
body: 'dfghj',
sound: 'default',
color: 'yellow',
android_channel_id: 'default',
channel_id: 'default'
},
data: { id: 'broadcast', channelId: 'default' }
}
const options = {
priority: 'high',
timeToLive: 60 * 60 * 24, // 1 day
};
console.log('------payload---',payload);
console.log('-----TOKEN_Array----',firebaseToken);
console.log('-------options-----',options);
firebase.messaging().sendToDevice(firebaseToken, payload, options).then(function (response) {
console.log('--------response',response);
}) .catch(function (error) {
console.log('-------rejet',reject);
});
It looks like you did not change the code from this tutorial:
https://medium.com/#jullainc/firebase-push-notifications-to-mobile-devices-using-nodejs-7d514e10dd4
you will need to change the 2nd line of code:
var serviceAccount = require("./julla-tutorial.json");
to actually point to your own firebase-push-admin.json file which holds your private keys registering your backend app with the firebase cloud messaging api. you can download this file from the firebase console as mentioned in the above article.
I recommend hiding this file from your git history by adding it to .gitignore so you dont accidentally push your private keys to a public repo.
I will link you another resource in addition to above link which helped me implement firebase push notifications in a nodeJS backend app.
https://izaanjahangir.medium.com/setting-schedule-push-notification-using-node-js-and-mongodb-95f73c00fc2e
https://github.com/izaanjahangir/schedule-push-notification-nodejs
Further I will also link you another repo where I am currently working on a fully functional firebase push notification implementation. Maybe it helps to actually see some example code.
https://gitlab.com/fiehra/plants-backend

jQuery or JS to pre-populate and submit a text field after dynamically generated input field finishes loading

My goal is to trigger a specific chat flow within the Microsoft Power Virtual Agent service based on the page the user is on. I haven't been able to find a way to customise the Microsoft service to dynamically start at a specific chat topic other than one fixed one using these instructions.
I want to use jQuery to pre-populate the dynamically generated text field:
$('.webchat__send-box-text-box__input').val('red');
The above code works where I see the word "red" appear in the text box very briefly but then it gets overwritten by the code that is generating the input field. If I run the above script manually from the browser console after everything has loading, it works fine.
Is there a way to customise the Microsoft webchat code to get the user to the start of a specific flow, or alternatively can I automate the insertion of the right words so that the user is automatically taken to the start of the relevant chat flow? It would be great if I could set a paramter in the webchat JS code that sets a topic right from the beginning, but I haven't found any instructions that suggests this is possible-just some basic styling parameters.
This is the code from Microsoft that generates a web chat interface:
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<script>
const styleOptions = {
// Add styleOptions to customize web chat canvas
hideUploadButton: true
};
// Add your BOT ID below
var BOT_ID = "[BOT ID VALUE REDACTED]";
var theURL = "https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken?botId=" + BOT_ID;
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === "DIRECT_LINE/CONNECT_FULFILLED") {
dispatch({
meta: {
method: "keyboard",
},
payload: {
activity: {
channelData: {
postBack: true,
},
//Web Chat will show the 'Greeting' System Topic message which has a trigger-phrase 'hello'
name: 'startConversation',
type: "event"
},
},
type: "DIRECT_LINE/POST_ACTIVITY",
});
}
return next(action);
}
);
fetch(theURL)
.then(response => response.json())
.then(conversationInfo => {
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine({
token: conversationInfo.token,
}),
store: store,
styleOptions: styleOptions
},
document.getElementById('webchat');
);
})
.catch(err => console.error("An error occurred: " + err));
</script>
This is fairly easy to overcome. All you need to do is decide on how you want to identify the page being visited, filter on that in Web Chat's store, and post an activity that would trigger the appropriate topic.
In the example below, my page is title "PVA Test Page". When the page loads that has that title, using the DIRECT_LINE/CONNECT_FULFILLED action type and matching on document.title === 'PVA Test Page', then the DIRECT_LINE/POST_ACTIVITY action is dispatched. The activity I have setup is of type 'message' and sends a text value of 'store hours'. In my PVA bot I have a topic that is setup to return dialog detailing the store hours. The trigger phrases are configured to recognize that text value. So, providing all those conditions are met, the store hours are returned as a dialog when the page loads.
Si
<!DOCTYPE html>
<html>
<head>
<title>PVA Test Page</title>
[ ... ]
</head>
[ ... ]
</html>
const store = window.WebChat.createStore(
{},
( { dispatch } ) => next => action => {
if ( action.type === "DIRECT_LINE/CONNECT_FULFILLED" ) {
if (document.title === 'PVA Test Page') {
dispatch( {
meta: {
method: "keyboard",
},
payload: {
activity: {
channelData: {
postBack: true,
},
text: 'store hours',
type: "message"
},
},
type: "DIRECT_LINE/POST_ACTIVITY",
} );
}
}
return next( action );
}
);

Discord.js - How to change style of Button

This is how I create and send the button:
client.on('messageCreate', (message) => {
/* ... Checking Command ... */
const actionRow = new MessageActionRow().addComponents(
new MessageButton()
.setStyle("PRIMARY")
.setLabel("X")
.setCustomId("test"));
message.channel.send({ content: "Test", components: [actionRow] });
}
A blue Button appears in the chat, as expected.
This is my Button-Listener:
client.on("interactionCreate", (interaction) => {
if (interaction.isButton()) {
if (interaction.customId === "test") {
//Before: console.log(interaction.component);
interaction.component.setStyle("DANGER");
//After: console.log(interaction.component);
}
}
});
Logging the component-object before and after .setStyle("DANGER") also reveals, that the style got changed from Primary to Danger successfully.
But in my Discord Client, the Style/Color didn't change, and ontop of that I am getting an error, saying that the interaction failed.
The style-property doesn't seem to be read-only: https://discord.js.org/#/docs/main/stable/class/MessageButton?scrollTo=style
So what am I doing wrong?
You updated the style only locally, you didn't send the changed component back to the Discord API.
To get rid of the error "This interaction failed", you need to respond to the interaction. One way to respond is to use MessageComponentInteraction.update(), which updates the original message.
client.on("interactionCreate", (interaction) => {
if (interaction.isButton()) {
if (interaction.customId === "test") {
// Change the style of received button component
interaction.component.setStyle("DANGER");
// Respond to the interaction,
// and send updated component to the Discord API
interaction.update({
components: [
new MessageActionRow().addComponents(interaction.component)
]
});
}
}
});
To make this work with multiple buttons, use the example below.
client.on("interactionCreate", (interaction) => {
if (interaction.isButton()) {
// Make this work only for certain buttons,
// with IDs like switch_0, switch_1, etc.
if (interaction.customId.startsWith("switch_")) {
// Change the style of the button component,
// that triggered this interaction
interaction.component.setStyle("DANGER");
// Respond to the interaction,
// and send updated components to the Discord API
interaction.update({
components: interaction.message.components
});
}
}
});
For any future viewers who might be using Discordjs V14+ you can't edit the components directly anymore, so you need to recreate them in order to edit them. This is a solution I came up with that flips the color when clicked!
const collector = interaction.channel.createMessageComponentCollector({ time: 15000 });
collector.on('collect', async i => {
//loop through each action row on the embed and update it accordingly
let newActionRowEmbeds = i.message.components.map(oldActionRow => {
//create a new action row to add the new data
updatedActionRow = new ActionRowBuilder();
// Loop through old action row components (which are buttons in this case)
updatedActionRow.addComponents(oldActionRow.components.map(buttonComponent => {
//create a new button from the old button, to change it if necessary
newButton = ButtonBuilder.from(buttonComponent)
//if this was the button that was clicked, this is the one to change!
if(i.component.customId == buttonComponent.customId){
//If the button was a primary button then change to secondary, or vise versa
if(buttonComponent.style == ButtonStyle.Primary){
newButton.setStyle(ButtonStyle.Secondary)
}
else if (buttonComponent.style == ButtonStyle.Secondary){
newButton.setStyle(ButtonStyle.Primary)
}
}
return newButton
}));
return updatedActionRow
});
// and then finally update the message
await i.update({components: newActionRowEmbeds})
});

how to disable/enable attachment button inside chatbox using javascript in C# bot framework

I have created a Microsoft bot framework using this tutorial. I created a chatbot using this javascript. I need to Enable/Disable the attachment button based on the bot message. My condition is to Enable the attachment button when the bot sends a message to the user to submit the attachment.
Html:
<div id="webchat" role="main"></div>
Script:
<script crossorigin="anonymous" src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<script>
// style properties
var styleOptions = {
botAvatarInitials: 'Bot',
bubbleBackground: 'rgba(0, 0, 255, .1)',
bubbleFromUserBackground: 'rgba(0, 255, 0, .1)',
userAvatarInitials: 'User',
hideUploadButton: true, //To hide attachment button
backgroundColor: "Grey"
};
// chatbot
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine({
token: 'access token'
}),
userID: 'YOUR_USER_ID',
username: 'Web Chat User',
locale: 'en-US',
styleOptions
},
document.getElementById('webchat'),
);
</script>
You can accomplish this by filtering the activities that pass thru Web Chat's store. As you can see below, I first query for the attachment button's elements - there are two, a hidden input field and the button.
Next, I check if the activity has an attachment and if that attachment's contentType matches "application/vnd.microsoft.card.adaptive". If it does, then the attachment input & button is enabled. Otherwise, the attachment input & button is disabled for all other activities.
The whole if statement is wrapped in a time out. This is necessary because the check on the contentType of the attachment will complete before the store has finished rendering the activity resulting in a persistently disabled button. Setting a time out of ~300 ms allows the store to complete its rendering action. You can adjust the time out, but less than ~50 ms and the above will start occurring. Longer than ~500 ms and it will start to be noticeable to users.
Please note, isolating the input & button elements relies on attributes and classes defined by Web Chat. While it is unlikely to be an issue, it's possible those definitions could change in future releases resulting in breaking changes and requiring updates to your code.
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => action => {
if ( action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' ) {
const activity = action.payload?.activity;
const attachmentBtn = document.querySelector( '[title="Upload file"]' );
const attachmentInput = document.querySelector( '.webchat__upload-button--file-input' );
setTimeout(() => {
if ( activity && activity.attachments) {
if (activity.attachments[0].contentType === 'application/vnd.microsoft.card.adaptive' ) {
attachmentBtn.disabled = false;
attachmentBtn.disabled = false;
}
} else {
attachmentBtn.disabled = true;
attachmentInput.disabled = true;
}
}, 300);
};
next( action );
} );
[...]
window.WebChat.renderWebChat(
{
directLine: directLine,
store: store,
},
document.getElementById( 'webchat' )
);
document.querySelector( '#webchat > *' ).focus();
Hope of help!

MS teams bot JS - create conversation

I need to proactivly create conversation on channel in msteams. So i looked for examples but didn't find any examples of realy proactive conversation creation. All examples include first of all handling message, and creating conversation using context.
To be more accurate i have facebook, whatsapp, and web widget. Users write for example from facebook, i get message through fb webhook and i need to create new thread ( block with replies inside channel ) and only after that, someone who will answer in channel using thread block and i'll get message.
As i understood i need to bootstrap conversation object and use adapter.createConversation({ ...convFields }), but for example i don't have serviceUrl.
// i am using adapter from examples
new BotFrameworkAdapter({
appId: id,
appPassword: password
});
// then i have something like that in examples
const conversationParameters = {
isGroup: true,
channelData: {
channel: {
id: 'msteams'
}
},
activity: 'dsada'
};
const connectorClient = this.adapter.createConnectorClient(
context.activity.serviceUrl // i don't have context to get that serviceUrl, because i must do it first, not handle message and create thread after that.
);
const conversationResourceResponse = await connectorClient.conversations.createConversation(
conversationParameters as any
);
const conversationReference = TurnContext.getConversationReference(
context.activity // same here, i don't have context
);
conversationReference.conversation.id = conversationResourceResponse.id;
return [conversationReference, conversationResourceResponse.activityId];
In order to prevent (or at least hinder) spam, your bot can only send proactive messages to channels or group chats where it is already installed. In that instance you'll need to store the necessary information from the conversationUpdate membersAdded event you'll receive.
For 1:1 chats, it is possible to create a new conversation with a user, however your bot needs to know the Id of the user in order to do so. Typically this is achieved by retrieving the roster of a group chat or team where your bot is installed.
Essentially, it isn't possible to send a completely proactive message - the bot needs to be installed and/or have some amount of information about where it is sending the message previously.
Assuming you can achieve the correct permissions, it is possible to proactively install your bot. See this article for more details on that approach: https://learn.microsoft.com/en-us/graph/teams-proactive-messaging
Even though it is in C#, you may find this sample helpful as it demonstrates the minimal amount of information required in order to send proactive messages to each type of destination (which is the same across languages): https://github.com/clearab/teamsProactiveMessaging.
The relevant file is below:
public class MessageSender : IMessageSender
{
private ConnectorClient conClient;
private string serviceUrl;
public MessageSender(string serviceUrl, string id, string password)
{
MicrosoftAppCredentials.TrustServiceUrl(serviceUrl);
conClient = new ConnectorClient(new Uri(serviceUrl), id, password);
}
public async Task<ResourceResponse> SendOneToOneMessage(string conversationId, Activity activity)
{
return await conClient.Conversations.SendToConversationAsync(conversationId, activity);
}
public async Task<ConversationResourceResponse> CreateOneToOneConversation(string userId, string tenantId)
{
var members = new List<ChannelAccount>()
{
new ChannelAccount
{
Id = userId
}
};
ConversationParameters conParams = new ConversationParameters
{
Members = members,
TenantId = tenantId
};
return await this.conClient.Conversations.CreateConversationAsync(conParams);
}
public async Task<ConversationResourceResponse> CreateAndSendChannelMessage(string channelId, Activity activity)
{
ConversationParameters conParams = new ConversationParameters
{
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(channelId)
},
Activity = activity
};
ConversationResourceResponse response = await this.conClient.Conversations.CreateConversationAsync(conParams);
return response;
}
public async Task<ResourceResponse> SendReplyToConversationThread(string threadId, Activity activity)
{
return await this.conClient.Conversations.SendToConversationAsync(threadId, activity);
}
}

Categories

Resources