How to avoid the image parameter in Hero card bot framework so that I can display only the options.
following code is not working, only BotFramework Hero Card title is diplaying
createHeroCard() {
return CardFactory.heroCard(
'BotFramework Hero Card',
CardFactory.actions([
{
type: 'imBack',
title: 'ABC',
value: 'ABC'
},
{
type: 'imBack',
title: 'DATA',
value: 'DATA'
},
])
);
}
I am noob at node.js I did same on C# which worked as expected. You could try converting the same. Here is the code snippet for your assistance.
public IMessageActivity YesCreateSolutionFlow()
{
try
{
var yesNoActivity = Activity.CreateMessageActivity();
var buttonList = new List<CardAction>();
//Btn 1
buttonList.Add(
new CardAction()
{
Value = "https://partner.microsoft.com/en-US/solutions/my-solutions/create-solution",
Type = "openUrl",
Title = "Yes, please"
});
//Btn 2
buttonList.Add(
new CardAction()
{
Value = "I Would like a tutorial first",
Type = "imBack",
Title = "I Would like a tutorial first"
});
var responseCard = new HeroCard()
{
Text = "",
Subtitle = string.Empty,
Buttons = buttonList
};
// Create the attachment.
var attachment = responseCard.ToAttachment();
yesNoActivity.Attachments.Add(attachment);
yesNoActivity.AttachmentLayout = AttachmentLayoutTypes.Carousel;
return yesNoActivity;
}
catch (Exception ex)
{
throw new NotImplementedException(ex.Message, ex.InnerException);
}
}
Finally, pass this card on turnContext.SendActivityAsync like below:
var yesCreateSolutionFlow= _customFlowRepository.YesCreateSolutionFlow();
await turnContext.SendActivityAsync(yesCreateSolutionFlow).ConfigureAwait(false);
Bot Conversation Output:
Hope that would help.
CardFactory.heroCard is expecting 3 or 4 parameters, You have only provided 2, so I believe the method is trying to interpret your buttons as images. if you pass an empty array as your second argument, I believe it will work as expected i.e.
createHeroCard() {
return CardFactory.heroCard(
'BotFramework Hero Card',
[],
CardFactory.actions([
{
type: 'imBack',
title: 'ABC',
value: 'ABC'
},
{
type: 'imBack',
title: 'DATA',
value: 'DATA'
},
])
);
}
If you don't want a title at all, you can just pass a blank string (i.e. '') as the first argument.
Related
I'm trying to make the bot basically edit the message of any specific case mentioned for example if i do -case 5 test it will look for case 5 and it's message. So far when i do it, it basically changes the recent case number message, instead of the one i want it to change. like if i do case 5 test and the latest case is #9, it will change 9 instead of 5.
This is how i send the message:
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id }, { $inc: { 'caseID': 1 } }, { new: true }, async function (err, doc) {
if (err) throw err;
if (!doc) return;
if (doc.modLog.enabled) {
if (msg.channel.guild.channels.get(doc.modLog.channelID)) {
let m = await msg.channel.guild.channels.get(doc.modLog.channelID).createMessage({
embed: {
title: `${action} | Case #${doc.caseID}`,
color: colour,
fields: [
{
name: 'User',
value: user,
inline: true
},
{
name: 'Moderator',
value: moderator ? moderator : 'No issuer.',
inline: true
},
{
name: 'Reason',
value: reason ? reason : 'No reason.'
}
]
}
});
doc.messageID = m.id;
doc.type = action;
doc.caseID = doc.caseID;
//doc.caseID = m.id
doc.moderatorID = moderator,
doc.targetID = user
doc.save();
}
}
})
that is how i send my message. And you can see i'm storing the things so when someone changes a specific case's reason, for example: case 5 spamming, i would want it to look for caseID 5, and then edit the message through it's ID. but i'm not sure how am i doing it wrong. I'm trying to make each case store it's own message ID and i would really appreciate any help. This is what i use to look for the case and edit's reason.
Modlog.findOne({ guildID: msg.guildID }, async (err, doc) => {
if (err) throw err;
if (!doc.modLog.enabled) return msg.channel.createMessage(`Modlog is not enabled in this server! ${this.emoji.cross}`);
if (isNaN(Number(caseID))) return msg.channel.createMessage(`Case \`#${caseID}\` was not a number! ${this.emoji.cross}`);
if (doc.caseID === undefined) return msg.channel.createMessage(`Couldn\'t find case \`#${caseID}\`! ${this.emoji.cross}`);
const moderator = this.bot.users.get(doc.moderatorID) || {
username: 'Unknown User',
discriminator: '0000'
}
const target = this.bot.users.get(doc.targetID) || {
username: 'Unknown User',
discriminator: '0000'
}
let embed = {
title: `${doc.type} | Case #${doc.caseID}`,
fields: [
{
name: 'User',
value: `${target.username}#${target.discriminator} (${target.id})`,
inline: true
},
{
name: 'Moderator',
value: `${moderator.username}#${moderator.discriminator} (${moderator.id})`,
inline: true
},
{
name: 'Reason',
value: reason
}
]
};
try {
await this.bot.editMessage(doc.modLog.channelID, doc.messageID, { embed: embed });
await msg.channel.createMessage(`Case **#${caseID}** has been updated. ${this.emoji.tick}`);
} catch (e) {
await msg.channel.createMessage(`I\'m unable to edit that case or it has been deleted. ${this.emoji.cross}`);
}
});```
Solution: Search for Case ID
It seems you didn't look for the case ID, and only looked for the guild's ID in the filter parameter.
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id }, { ... }, { ... }, ... {
...
}
In your code, only guildID was passed into the filter parameter. This causes Mongoose to look for the most recently initialized document for the server. For your case, you should also pass caseID into the filter parameter.
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id, caseID: caseIDArg }, { ... }, { ... }, ... {
...
}
Replace caseIDArg with your supposed caseID argument in the message's content. For example, args[1] or however you programmed your argument handler to work.
Hope this helped to answer your question!
I want to make a telegram bot about algebra. I need to send code to http://api.mathjs.org/v4/?expr=2*(7-3) after the expr part. I want to send numbers with inline query, but how can I do it?
The original example uses context object deconstruction, which doesn't seem to work and spits out error: TypeError: Cannot read property 'assert' of undefined
Here is the code without object deconstruction, which works for me (I've made it superfluously verbose for better understanding ):
bot.on('inline_query', async (ctx) => {
const offset = parseInt(ctx.inlineQuery.offset) || 0;
let items = [];
for(var i = 0; i < 100; i++) {
items.push({ title: 'Item '+i, desc: 'item '+i+' desc', id: '0000'+i, moreinfo: 'More info about item'+i+', mucho importante information'})
}
let results = items.slice(offset, offset+10).map((item) => ({
type: "article",
id: item.id,
title: item.title,
description: item.desc,
input_message_content: {
message_text: '*'+item.title+'*\n'+item.desc,
parse_mode: 'Markdown'
},
reply_markup: {
inline_keyboard: [
[{ text: 'More info', callback_data: 'moreinfo' }]
]},
hide_url: true,
url: 'http://www.domain.se/'+item.id,
}));
console.log('hello');
let ourReturn = ctx.answerInlineQuery(results, {is_personal: true, next_offset: offset+results.length, cache_time: 10});
return ourReturn;
});
Here is the article that helped me to solve this problem.
You can find multiple examples of Telegraf usage at https://github.com/telegraf/telegraf/tree/develop/docs/examples
Here is an example of a bot utilizing an inline query
I have this array list of objects.
var list = [{
'ID':1,
'name' : 'Vikas Yadav',
'mobile':8095638475,
'sent':false
},
{
'ID':2,
'name' : 'Rajat Shukla',
'mobile':7486903546,
'sent':false
},
{
'ID':3,
'name' : 'Munna Bhaiya',
'mobile':9056284550,
'sent':false
},
{
'ID':4,
'name' : 'Guddu Pandit',
'mobile':7780543209,
'sent':false
},
{
'ID':5,
'name' : 'Srivani Iyer',
'mobile':8880976501,
'sent':false
}];
Now I want to push two more datas in specific element of this array via forLoop as:
var timeAndOTPArray = {
"time" : new Date(),
"OTP": req.params.ran
}
I am retrieving the list data via cookies into one of the route.
Below is the code I am trying to push the element according to the matching condition.
var lists = req.cookies.list;
Object.keys(lists).forEach(function(item) {
if(req.params.ID == lists[item].ID){ //look for match with name
(lists[item]).push(timeAndOTPArray);
newAddedList.push(lists[item]);
console.log(item, lists[item]);
}
});
Perhaps it's not the correct way. Please help!
Wish you a happy and a prosperous Diwali.
Cheers!
You can use findIndex and append to update the object into list like this:
//List only with ID, easier to read the code
var list = [{'ID':1,},{'ID':2,}]
//your object
var timeAndOTPArray = {
"time" : new Date(),
"OTP": "otp"
}
//Index where object with ID == 2 is
var index = list.findIndex(obj => obj.ID == 2);
//Append the 'timeAndOTPArray' properties into the object itself
list[index] = {"time": timeAndOTPArray.time, "OTP":timeAndOTPArray.OTP, ...list[index]}
console.log(list)
I guess this will help
var lists = req.cookies.list;
Object.keys(lists).forEach(function(item) {
if(req.params.ID == lists[item].ID){ //look for match with ID
Object.keys(timeAndOTPArray).forEach(key=>{
lists[item][key]=timeAndOTPArray[key];
})
}
});
Good evening) I can advice you the best option is update with map
const listItems = [
{
ID: 1,
name: 'Vikas Yadav',
mobile: 8095638475,
sent: false,
},
{
ID: 2,
name: 'Rajat Shukla',
mobile: 7486903546,
sent: false,
},
{
ID: 3,
name: 'Munna Bhaiya',
mobile: 9056284550,
sent: false,
},
{
ID: 4,
name: 'Guddu Pandit',
mobile: 7780543209,
sent: false,
},
{
ID: 5,
name: 'Srivani Iyer',
mobile: 8880976501,
sent: false,
},
];
const paramId = 4;
const result = listItems.map((item) => {
if (paramId === item.ID) {
return {
...item,
time: new Date(),
OTP: 'smth',
};
}
return item;
});
console.log('result', result);
for appending, you can do this,
lists[index] = Object.assign(lists[index], timeAndOTPArray);
If you are using es6,
lists[index] = {...lists[index], timeAndOTPArray};
Here lists is an array of objects.
so lists[item] is an object, so you cant push an object to an object.
In your code timeAndOTPArray is an object.
In your lists object, initialize an empty array called timeAndOTPArray
var index = lists.findIndex(function(item){ return item.ID == req.params.ID});
lists[index].timeAndOTPArray.push(timeAndOTPArray);
I'm trying to triggering an edit on my embedded (already sent) message while keeping all the other fields the same value
I have found this answer as an inspiration (which works with the example): Embed message doesn't update but that doesn't seem to get all the fields, only the first. There isn't much more on the subject to find (or i'm not good at Googling :)).
So the new embed is just the first field and not all the (not changed) fields.
activityMsg = new Discord.RichEmbed({
title: 'Some text',
description: 'Description',
color: 3447003,
footer: {
icon_url: image,
text: image
},
thumbnail: {
url: image
},
fields: [
{
name: 'Text',
value: 'Text2',
},
{
name: 'Date and time',
value: '2pm',
},
{
name: 'Participants',
value: '#User',
},
{
name: 'Waiting list',
value: '#user2',
},
{
name: 'Max players',
value: '22',
}
]
});
const reactionFilterPlus = (reaction, user) => reaction.emoji.name === emoji_plus;
if(typeof title != undefined && title != null && data.length == 4 && error == ''){
var title = title[0].replace('[','').replace(']','');
// add reaction emoji to message
msg.channel.send(activityMsg)
.then(msg => msg.react(constants.emoji_plus))
.then(mReaction => {
// createReactionCollector - responds on each react, AND again at the end.
const collector = mReaction.message
.createReactionCollector(reactionFilterPlus, {
time: 15000
});
// set collector events
collector.on('collect', r => {
// immutably copy embed's Like field to new obj
let embedLikeField = Object.assign({}, activityMsg.fields[0]);
// update 'field' with new value
embedLikeField.value = `${user} <3`;
// create new embed with old title & description, new field
const newEmbed = new Discord.RichEmbed({
title: activityMsg.title,
description: activityMsg.description,
fields: [embedLikeField]
});
// edit message with new embed
// NOTE: can only edit messages you author
r.message.edit(newEmbed)
.catch(console.log);
});
})
.catch(console.log);
}
I expected this line to get all the fields, but that isn't the case.
// immutably copy embed's Like field to new obj
let embedLikeField = Object.assign({}, activityMsg.fields[0]);
I have tried let embedLikeField = Object.assign({}, activityMsg.fields[0] === 'Participants') but then I get the following error about a fieldname not present.
{ DiscordAPIError: Invalid Form Body
embed.fields[0].name: This field is required
at item.request.gen.end (/usr/src/app/node_modules/discord.js/src/client/rest/RequestHandlers/Sequential.js:79:15)
at then (/usr/src/app/node_modules/snekfetch/src/index.js:215:21)
at process._tickCallback (internal/process/next_tick.js:68:7)
English isn't my native language and I'm stilling learning nodejs sorry sorry in advance about these points.
Object.assign() performes a shallow clone on the source, Are you trying to clone your entire embed or only its first field?
activityMsg.fields[0] refers to the first element in the list called fields within your activityMsg object. Try calling your assign() with activityMsg as source.
var Promise = require('bluebird');
var userQueryAsync = Promise.promisify(Article.query);
userQueryAsync("SELECT article.slug, article.title, __user.name AS user___name, __user.phone AS user___phone FROM article JOIN user AS __user ON __user.id = article.user")
.then(function(article) {
var parsed = new Article._model(article);
console.log(parsed);
});
I would like to create model objects thanks to a raw query in Sails.
Data I retrieve with the code above is :
{ '0':
{
slug: 'article-1',
title: 'Article 1',
user: 1,
user___name: 'Cainzer',
user___phone: '0000000'
}
}
I wish :
{ '0':
{
slug: 'article-1',
title: 'Article 1',
user: {
name: 'Cainzer',
phone: '0000000'
}
}
}
Is there a way to do it without looping ?
I know that I could do it easily with Article.find().populate("user"), but I'm showing you a simple example to make it work and apply solution on a more tricky situation.
I'm forced to use a raw query because Waterline doesn't implement WHERE clause in populate() yet with MySQL.