Unable to Intercept Bot Response in Azure Bot Framework - node.js

I want to intercept all the messages exchanged between user and bot. PFB code that I have used to intercept. I am using Bot Diaolog framework for webchat. Here the issue is I am not able to extract values from activities object which contains messages sent from bot to user.
adapter.use(async (turnContext, next) => {
// pre-processing of the current incoming activity
console.log("adapture use::turnContext::" + turnContext.activity.text);
// hook up a handler to process any outgoing activities sent during this turn
turnContext.onSendActivities(async (sendContext, activities, nextSend) => {
// pre-processing of outgoing activities
await nextSend();
console.log("adapture use::activities::POST##::" + flat.stringify(activities));
// post-processing outgoing activities
});
await next();
// post-processing of the current incoming activity
console.log(`Processing activity ${turnContext.activity.id} finishing. `);
});

To access the bot's responses, you can update the bot.js file (i.e. the file with the activity handlers defined) to something like the below.
In short, the onSendActivities() method keeps an array of the activities that have been passed in. You can cycle thru the activities pushing them into an array and then acting on a particular one. Or, react as each arrives. Further below are examples of each output.
const { ActivityHandler, MessageFactory } = require('botbuilder');
class EchoBot extends ActivityHandler {
constructor() {
super();
[...]
const transcript = [];
this.onTurn(async (context, next1) => {
let responses = {};
logActivity(transcript, cloneActivity(context.activity));
context.onSendActivities(async (ctx, activities, next2) => {
responses = await next2();
activities.forEach((a) => logActivity(transcript, cloneActivity(a)));
console.log('TRANSCRIPT ', activities);
return responses;
});
await next1();
});
}
}
const logActivity = (transcript, activity) => {
if (!activity.timestamp) {
activity.timestamp = new Date();
}
transcript.push(activity);
};
const cloneActivity = (activity) => {
return Object.assign({}, activity);
};
module.exports.EchoBot = EchoBot;
Logging the transcript array: Shows the list of activities.
[
{
type: 'conversationUpdate',
id: '1hEUP37Da8S',
timestamp: 2021-09-07T23:01:04.910Z,
serviceUrl: 'https://directline.botframework.com/',
channelId: 'directline',
from: { id: 'dl_16310556645490.nc93iu9jr1' },
conversation: { id: '5JgOxxxxxxxxxxxxv6sw-g' },
recipient: { id: 'somebot#QaeuoeEamLg', name: 'Some Bot' },
membersAdded: [ [Object], [Object] ],
rawTimestamp: '2021-09-07T23:01:04.9109865Z',
callerId: 'urn:botframework:azure'
},
{
type: 'message',
text: 'Hello and welcome!',
inputHint: 'acceptingInput',
speak: 'Hello and welcome!',
channelId: 'directline',
locale: undefined,
serviceUrl: 'https://directline.botframework.com/',
conversation: { id: '5JgOxxxxxxxxxxxxv6sw-g' },
from: { id: 'somebot#QaeuoeEamLg', name: 'Some Bot' },
recipient: { id: 'dl_16310556645490.nc93iu9jr1' },
timestamp: 2021-09-07T23:01:06.547Z
},
{
type: 'message',
id: '5JgOxxxxxxxxxxxxv6sw-g|0000001',
timestamp: 2021-09-07T23:01:08.704Z,
localTimestamp: 2021-09-07T23:01:08.527Z,
localTimezone: 'America/Los_Angeles',
serviceUrl: 'https://directline.botframework.com/',
channelId: 'directline',
from: { id: 'dl_16310556645490.nc93iu9jr1', name: '' },
conversation: { id: '5JgOxxxxxxxxxxxxv6sw-g' },
recipient: { id: 'somebot#QaeuoeEamLg', name: 'Some Bot' },
textFormat: 'plain',
locale: 'en-US',
text: 'Hi',
entities: [ [Object] ],
channelData: {
clientActivityID: '1631055668527tzwhm47a4qd',
clientTimestamp: '2021-09-07T23:01:08.527Z'
},
rawTimestamp: '2021-09-07T23:01:08.704318Z',
rawLocalTimestamp: '2021-09-07T16:01:08.527-07:00',
callerId: 'urn:botframework:azure'
},
{
type: 'message',
text: 'Echo: Hi',
inputHint: 'acceptingInput',
speak: 'Echo: Hi',
channelId: 'directline',
locale: 'en-US',
serviceUrl: 'https://directline.botframework.com/',
conversation: { id: '5JgOxxxxxxxxxxxxv6sw-g' },
from: { id: 'somebot#QaeuoeEamLg', name: 'Some Bot' },
recipient: { id: 'dl_16310556645490.nc93iu9jr1', name: '' },
replyToId: '5JgOxxxxxxxxxxxxv6sw-g|0000001',
timestamp: 2021-09-07T23:01:09.147Z
}
]
Logging activities only: Shows the last item to have passed thru from either the bot or user.
[
{
type: 'message',
text: 'Echo: Hi',
inputHint: 'acceptingInput',
speak: 'Echo: Hi',
channelId: 'directline',
locale: 'en-US',
serviceUrl: 'https://directline.botframework.com/',
conversation: { id: 'AURKxxxxxxxxxJHpO-f' },
from: { id: 'somebot#QaeuoeEamLg', name: 'Some Bot' },
recipient: { id: 'dl_16310605730140.3nrm4evq6um', name: '' },
replyToId: 'AURKxxxxxxxxxJHpO-f|0000001'
}
]

Thank you Rajeesh Menoth. Posting your suggestions as an answer to help other community members.
For updating existing message we can pass NewActivityObject with the existing activity ID to the UpdateActivity method of the TurnContext Object
Below is the sample to pass new object ID
const newActivity = MessageFactory.text('The new text for the activity');
newActivity.id = activityId;
await turnContext.updateActivity(newActivity);
To update the existing card on button selection, you can use ReplyToId of incoming activity.
const message = MessageFactory.attachment(card);
message.id = context.activity.replyToId;
await context.updateActivity(message);
For Further information check Update Messages.

Related

Serverless Event object failed validation at createError

I am working on a serverless/nodejs12 project. The project deploys fine, but when I try to invoke the endpoint with postman I get the following error. I have browsed through many postings of similar errors but still failed to understand what's going on. Will appreciate any pointers.
Thank you
at createError (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/util/index.js:259:1)
at validatorMiddlewareBefore (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/validator/index.js:55:1)
at runMiddlewares (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/core/index.js:120:1)
at runRequest (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/core/index.js:80:1) {
details: [
{
instancePath: '/body',
schemaPath: '#/properties/body/type',
keyword: 'type',
params: [Object],
message: 'must be object'
}
]
createNotification.js
--------------------------
async function createNotification(event, context) {
const { title } = event.body;
const { destination } = event.body;
const { destinationType } = event.body
const notification = {
id: uuid(),
title,
destination,
destinationType,
status: 'OPEN',
createdAt: new Date().toISOString(),
}
try {
await dynamodb.put({
TableName: process.env.NOTIFY_TABLE_NAME,
Item: notification
}).promise();
} catch (error) {
console.error(error);
throw new createError.InternalServerError(error);
}
return {
statusCode: 200,
body: JSON.stringify(notification),
};
}
export const handler = commonMiddleware(createNotification)
.use(validator({ inputSchema: createNotificationSchema }));
and the schema
----------------------
const schema = {
type: 'object',
properties: {
body: {
type: 'object',
required: ['status'],
default: { status: 'OPEN' },
properties: {
status: {
default: 'OPEN',
enum: ['OPEN', 'CLOSED'],
},
},
},
},
required: ['body'],
};
export default schema;
You're getting the error must be object. I'm guessing your input looks like { event: { body: 'JSON string' } }. You'll need to use another middy middleware to parse the body prior to validating the input. Which middleware will depend on what AWS event it's expecting. Middy >3.0.0 supports all AWS events.

How to push transaction EOS Blockchain (eosjs - unsatisfied_authorization)?

I use Anchor Wallet.
This is init code
const privateKeys = ["myprivatekey"];
const signatureProvider = new JsSignatureProvider(privateKeys);
const rpc = new JsonRpc(config.mainnet, { fetch });
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });
return {rpc, api};
Then i try to push transaction
const transaction = await api.transact({
actions: [{
account: 'eosio',
name: 'buyrambytes',
authorization: [{
actor: 'username',
permission: 'active',
}],
data: {
payer: 'username',
receiver: 'username',
bytes: 8192,
},
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
(docs example)
and receive error
details: [
{
message: `transaction declares authority '{"actor":"username","permission":"active"}', but does not have signatures for it.`,
file: 'authorization_manager.cpp',
line_number: 643,
method: 'get_required_keys'
}
],
json: {
code: 401,
message: 'UnAuthorized',
error: {
code: 3090003,
name: 'unsatisfied_authorization',
what: 'Provided keys, permissions, and delays do not satisfy declared authorizations',
details: [Array]
}
}
}
Maybe i enter wrong private key (Anchor -> Export private key -> Copy key) or something else, idk.
All other functions (for exampe get_block etc.) works fine
try with owner:
authorization: [{
actor: 'username',
permission: 'owner',
}],

Bot framework is not calling the sendGame method in the telegram

I am using the bot framework rest API and channelData to send the game to telegram. But the framework returns 200 and still it doesn't show any message on the telegram side, I don't know what I am doing wrong here, Pasting the code below for setting up the channelData:
const channel_data = { method: 'sendGame', parameters: { game_short_name: 'gamename' } };
let payload = {
type: type,
from: {
id: telegramResponse.recipient.id,
name: telegramResponse.recipient.name
},
recipient: {
id: telegramResponse.from.id,
name: telegramResponse.from.name
},
conversation: {
id: telegramResponse.conversation.id
},
text: text, channelData: channel_data
};
return payload;
}
}

How does admin. messaging. AndroidNotification need to be configured for localization?

In the firebase documentation I found that admin. messaging. AndroidNotification has properties to provide localization to your notifications. Or at least that is what I understand from it.
https://firebase.google.com/docs/reference/admin/node/admin.messaging.AndroidNotification
In the docs they have bodyLocArgs and bodyLocKey to localize the body and titleLocArgs and titleLocKey. How do these need to be configured in order to localize my notification?
So let's say my client (the android device) is using en_US as his current language. Is my clients locale used to localize the notification?
This is what my current message
const translator = deviceData.language !== 'nl' ? languages.en : languages.nl;
const title = `${translator['messageTitle' as keyof typeof translator]} ${group.displayName}`;
const body = `${sender.displayName} ${translator[type as keyof typeof translator]}`;
const systemTrayNotification: TokenMessage = {
token: deviceData.cloudMessagingToken,
notification: {
title: title,
body: body,
},
data: {
title: title,
body: body,
senderId: sender.id,
senderDisplayName: sender.displayName,
groupId: group.id,
type: 'groupMessage',
messageType: type,
sentAt: new Date().toISOString(),
},
android: {
priority: 'high',
notification: {
priority: 'max',
channelId: '59054',
clickAction: 'FLUTTER_NOTIFICATION_CLICK',
tag: 'groupMessage',
defaultSound: true,
defaultVibrateTimings: true,
bodyLocArgs: //what do I do here?,
bodyLocKey: //what do I do here?
titleLocArgs: //what do I do here?,
titleLocKey: //what do I do here?
}
},
apns: {
payload: {
aps: {
category: 'groupMessage',
headers:{
"apns-priority":"10"
},
alert: {
title: title,
body: body,
},
aps: {
sound: 'default',
},
customData: {
title: title,
body: body,
senderId: sender.id,
senderDisplayName: sender.displayName,
groupId: group.id,
type: 'groupMessage',
messageType: type,
sentAt: new Date().toISOString(),
}
}
},
}
}
Use like this.
body: jsonEncode({
'notification': <String, dynamic>{
'title_loc_key': 'BOOKING_RECEIVED_PUSH_SUBTITLE',
'title_loc_args': [booking.shopName],
'body_loc_key': 'BOOKING_RECEIVED_PUSH_BODY',
'body_loc_args': [
customerName,
'',
bookingStart
], //, bookingDate, bookingStart]),
'sound': 'true',
'mutable_content': 'true',
'content_available': 'true'
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done'
},
'to': customerFCMToken
})).whenComplete(() {
print('sendBookingReceived(): message sent');
}).catchError((e) {
print('sendBookingReceived() error: $e');
});
try this and let me know if it is working or not.

Allow object of objects within inputs in action

I'm wondering how I have objects of objects as inputs in an action - for example,
module.exports = {
friendlyName: 'Signup',
description: 'Signup a user for an account.',
inputs: {
bride: {
firstName: {
description: 'The first name of the bride',
type: 'string',
required: true
}
},
groom: {
lastName: {
description: 'The first name of the groom',
type: 'string',
required: true
}
}
}
exits: {},
fn: async function (inputs, exits) {
sails.log.debug(inputs.bride.firstName); // I would like to be able to reference input like this
return exits.success();
}
};
How can I do this and access inputs.bride.firstName (instead of having to do inputs.brideFirstName)?
I receive the following error trying to do this:
'Invalid input definition ("bride"). Must have `type`, or at least some more information. (If you aren\'t sure what to use, just go with `type: \'ref\'.)' ] } }
Another way is to implement a custom validation with objects of objects
module.exports = {
friendlyName: 'Signup',
description: 'Signup a user for an account.',
inputs: {
bride: {
description: 'The first name of the bride',
type: 'json', // {'firstName': 'luis'}
custom: function(value) {
return _.isObject(value) && _.isString(value.firstName)
}
},
groom: {
description: 'The first name of the groom',
type: 'json', // {'lastname': 'lazy'}
custom: function(value) {
return _.isObject(value) && _.isString(value.lastName)
}
}
}
exits: {},
fn: async function (inputs, exits) {
sails.log.debug(inputs.bride.firstName); // luis
return exits.success();
}
};
More information on: https://sailsjs.com/documentation/concepts/models-and-orm/validations#?custom-validation-rules
You should use a json type for this case. Sails don't check attributes in json type.
module.exports = {
friendlyName: 'Signup',
description: 'Signup a user for an account.',
inputs: {
bride: {
description: 'The first name of the bride',
type: 'json', // {'firstName': 'luis'}
required: true
},
groom: {
description: 'The first name of the groom',
type: 'json', // {'lastname': 'lazy'}
required: true
}
}
exits: {},
fn: async function (inputs, exits) {
sails.log.debug(inputs.bride.firstName); // luis
return exits.success();
}
};
More info about types: https://sailsjs.com/documentation/concepts/models-and-orm/attributes#?type

Resources