I'm developing a simple telegram bot with node.js telegram-bot.
https://github.com/yagop/node-telegram-bot-api
For now I want user to stop typing messages (with letters), just pressing one of a few buttons. And when he clicks on the button, his telegram's client has to send back to my bot another message (something like "clicked yes" or "clicked no").
I've found that it can be made with
var options = {
reply_markup: JSON.stringify({
inline_keyboard: [
[{ text: 'Some button text 1', callback_data: '1' }],
[{ text: 'Some button text 2', callback_data: '2' }],
[{ text: 'Some button text 3', callback_data: '3' }]
]
})
};
bot.sendMessage(msg.chat.id, "answer.", option);
So user receives 3 kind of messages, and when he clicks them, he doesn't send me back anything.
I need another type of buttons (which will be in the bottom of client's app).
You need to listen for the callback_query .. As outlined :
bot.on('callback_query', function onCallbackQuery(callbackQuery) {
const action = callbackQuery.data;
const msg = callbackQuery.message;
const opts = {
chat_id: msg.chat.id,
message_id: msg.message_id,
};
let text;
if (action === '1') {
text = 'You hit button 1';
}
bot.editMessageText(text, opts);
});
More info can be found in the library itself. : https://github.com/yagop/node-telegram-bot-api/blob/0174b875ff69f6750fc80a049315c9a0d7a5e471/examples/polling.js#L78
Some further reading indicates : https://core.telegram.org/bots/api#callbackquery
TelegramBot emits callback_query when receives a Callback Query
This relates to this documentation here : https://core.telegram.org/bots/api#callbackquery
If the button was attached to a message sent via the bot (in inline mode), the field inline_message_id will be present.
Exactly one of the fields data or game_short_name will be present.
You are using inline keyboard, instead you can try reply keyboard markup which appears in the bottom of telegram screen as you said.
It is implemented easily and you can find some useful information about it here and here.
Related
I'm making an admin dashboard and I need to ask for data (for example when creating or updating data) a lot. I am already using vue-sweetalert2 which made me aware of how easy it is to use this.$swal.fire().then()...
I was wondering, how would I go about making my own kind of thing like that (without using TypeScript)?
let reply = await this.$ask(fields)
alert("You entered: " + reply.yourname.answer)
Then in the component that I load in on every page, I would have a modal which takes the fields and allows for user input. When a user clicked submit or exited the modal, it needs to return a / the value(s).
I'm thinking of using it this way:
// Ask for new team name & description
let modalResult = await this.$ask({
fields: [
{
title: "Team name",
placeholder: "Give youre team a name!",
key: "teamName",
type: "text"
}, {
title: "Team description",
placeholder: "What's your team about?",
key: "teamDescription",
type: "text"
}
],
modal: {
variant: "primary",
icon: null,
title: "Make a new team",
confirmButtonText: "Create team",
cancelButtonText: "Cancel"
}
});
console.log("Team name: " + modalResult.data.teamName);
console.log("Team description: " + modalResult.data.teamDescription);
However, I honestly have no idea how I'd go about making this possible. What I've thought of:
Mixins: Of what I've learnt so far, I don't know how to put a template file in it. (so a .vue file, only a .js file).
Here's a screenshot of :
what I'm trying to say
Thanks in advance! :-)
When you're setting up your vue instance (usually in main.js), you can put your method on as a prototype
Vue.prototype.$ask= (your function or your object);
Here's some vuejs docs on the subject
https://v2.vuejs.org/v2/cookbook/adding-instance-properties.html
I am using Tagify with a custom AngularJS directive that I built, Tagify mixed input returns the JSON objects of selected tags and text in one single string, for example:
var tagify = new Tagify(myElement, {
mode: 'mix',
pattern: /#/,
whitelist: [{ value: "User Name", code: '$name' }, { value: "Phone Number", code: '$phone' }],
enforceWhitelist: true,
dropdown: {
maxItems: 20,
classname: "tags-look",
enabled: 0,
closeOnSelect: true
}
});
tagify.on('change', () => console.log(tagify.DOM.input.value))
The user input would be:
Hello User Name ×, the SMS has been sent to your phone Phone Number ×.
This simple example returns:
Hello [[{ value: "User Name", code: '$name' }]], the SMS has been
sent to your phone [[{ value: "Phone Number", code: '$phone' }]].
(and the JSON returned is escaped)
What I am doing later is replacing the tags that the user selected (by typing the # character and selecting them from the dropdown) with my own dynamic variables.
I was able to get a nice result with tagify.DOM.input.textContent as it rendered the following result:
Hello User Name, the SMS has been sent to your phone Phone Number.
However, since the whitelist is translatable and can be in other languages that I can't find and replace easily later, what I need is the code attribute from the JSON whitelist and not the value. The expected result that I couldn't find a way to reach yet is:
Hello $name, the SMS has been sent to your phone $phone.
Thanks.
You can create your custom transform function, to transform it the way you like, you can do something like this.
function transformer(value) {
return value.replace(/\[\[(.*?)\]\]/g, (arr => {
let json = JSON.parse(arr);
return json[0].map(e => e.code).join(', ');
}))
}
And then you can call it on change (or rather on/or before submit), like this:
tagify.on('change', (e) => transformer(e.detail.value));
I`m creating bot for MS Teams and using JS Microsoft Bot Framework V4 SDK.
In my work, I use search message extension and to work with it, I implemented the onSelectItem method that returns a adaptive card. I will give an example of the code below.
return Promise.resolve({
type: "result",
attachmentLayout: "list",
attachments: [CardFactory.heroCard(
`${file.name}`,
`${text}`,
undefined,
CardFactory.actions([
{
type: "openUrl",
title: "Open",
value: `${openLink}`
},
{
type: "openUrl",
title: "Download",
value: `${downloadLink}`
},
]),
)]
});
Where I pass undefined, this should be the path to the picture, but in my implementation I don't need it. So and this code works great in the browser and on the desktop version here is a screenshot
however, on the mobile version, I get the following result
this is absolutely not the right card, it has no content or buttons
I think I found the answer myself. When the message extension search is triggered, the onQuery method is called and suppose you made a query and received an array of values that you want to display. And here, in the same method, iterating over the array, you must draw two cards at once. For example
files.forEach((file: IDocumentInfo): void => {
const card: any = CardFactory.heroCard(
cutString(file.name, LIMIT),
text,
undefined,
[
{
type: "openUrl",
title: "Open",
value: "", // some value
},
{
type: "openUrl",
title: "Download",
value: "" //some value,
},
]
);
const preview: any = {
contentType: "application/vnd.microsoft.card.thumbnail",
content: {
title: `${cutString(file.name, LIMIT)}`,
text: "", // some text
}
};
And here the variable preview in my case will respond to a small view of information after the search and the variable card will be responsible for the view after selection. And after the card is selected, the onSelectItem method is triggered, which I need to get more information about the document
It turns out that the adaptive heroCard is not to blame here, the onSelectItem method is not called in the mobile application, or I am doing something wrong
I'm trying to create a bot, and one of its commands is user-info
for eg. !user-info #<username>
and i want it to display username, id and the avatar
like:
username:<username>
Id:<User Id>
Avatar:<the avatar >
Below is the code i used:
else if (message.content.startsWith(`${prefix}user-info`)) {
var member = message.mentions.users.first();
message.channel.send(`Username: ${member.username}\n ID:${member.id}\n Avatar:${member.displayAvatarURL()}` );
}
However it doesn't work, when i remove the avatar part the output comes out as :
Username:undefined
Id:<the id>
When I add the avatar part I just get a huge error on the command module when I use the bot command. What's the right way and what did I get wrong?
I'd suggest you use an Embed for this, as those can display images in a better way, the code for your request would be:
var user = message.mentions.users.first();
message.channel.send({
embed: {
title: `Profile of ${user.tag}`,
thumbnail: {
url: user.displayAvatarURL(),
},
fields: [
{
title: "ID:",
value: user.id
}
]
}
});
You can find more on this here
For the application I am currently building, there is a dataset of links associated with certain customer profiles and the user receives a list, which looks like the following:
function getList(customItems){
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: []
}
}
}
};
customItems.forEach(function(item) {
var url = item._id;
var listItem = {
title: item.title,
subtitle: "",
item_url: url,
image_url: "http://random.image.com",
buttons: [{
type: "postback",
title: "Get other items",
payload: "TEST",
}]
};
messageData.message.attachment.payload.elements.push(listItem);
Anyway, I would like to generate some image from given url the same way it appears in messenger if the link is pasted directly into the text box and haven't figured out yet how to do it. Also, by the way, if I try to display some random image for testing purpposes (http://random.image.com replaced by some valid image url), the image doesn't appear.
Does anyone know how to generate images to be displayed for given urls dynamically?
You either have to implement your own (or open source) thumbnail image processor (with something like ImageMagick, GraphicsMagick, G'MIC, gd, PhantomJS + HTML5 Canvas), or use a SaaS solution like imgix.com