I couldn't find a working Telegraf inline query project - node.js

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

Related

How to show list of field values of a collection of objects

I am making an API that shows a collection of ads with MongoDB and Node.js
I need to display the list of collection tags in a JSON string.
Example: 'home', 'mobile', 'motor'
This is the API initializer code:
const readline = require('readline');
const Product = require('./models/Product');
async function main() {
const advance = await question('Are you sure to continue with the deletion of the database? (yes or no) ')
if (!advance) {
process.exit();
}
const connection = require('./lib/connectMongoose')
await initProducts();
connection.close();
}
async function initProducts() {
const deleted = await Product.deleteMany();
console.log(`Remove ${deleted.deletedCount} products.`);
const inserted = await Product.insertMany([
{name: 'Table', sale: true, price: 150, photo: 'Table.png', tags: ['home']},
{name: 'Iphone 13 pro', sale: false, price: 950, photo: 'Iphone 13 pro.png', tags: ['mobile']},
{name: 'Car Mini Cooper', sale: true, price: 1000, photo: 'Car Mini Cooper.png', tags: ['motor']}
]);
console.log(`Create ${inserted.length} products.`)
}
main().catch(err => console.log('Hubo un error', err))
function question(text) {
return new Promise((resolve, reject) => {
const interface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
interface.question(text, answer => {
interface.close();
if (answer.toLowerCase() === 'yes') {
resolve(true);
return;
}
resolve(false);
})
})
}
I need to find a MongoDB method that allows me to show when the API route calls the list that shows in JSON format all the tags that the collection includes
If I've understood correctly, one option is $unwind the tags array to get all tags as strings and be able to $group adding to a set to avoid duplicates.
db.collection.aggregate([
{
"$unwind": "$tags"
},
{
"$group": {
"_id": null,
"tags": {
"$addToSet": "$tags"
}
}
}
])
I think this works but $unwind and $group the entire collection is not always a good idea. It may be a slow process.
Example here

Telegram bot inline mode. How to make it send local voice recordings?

I've got some problem with adding local voice file to results array in answerInlineQuery method of inline_query mode.
import TelegramBot from 'node-telegram-bot-api'
const bot = new TelegramBot('my bot token', { polling: true })
bot.on('inline_query', query => {
console.log(query)
const results = []
results.push({ id: 4, type: 'article', title: 'article 1', input_message_content: { message_text: 'article 1' } })
results.push({ id: 5, type: 'voice', title: 'voice 1', voice_url: 'voices/1.ogg' })
bot.answerInlineQuery(query.id, results, { cache_time: 10 })
})
bot.answerInlineQuery(query.id, results, { cache_time: 10 })
I know, that voice_url is useless for file path, but i don't see any other opportunity to add it.
I'd like to know if it is possible at all in inline mode, because non-inline method SendVoice supports this function.

Trying to edit a specific embed field on a user action

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.

Sails raw query populate

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.

Select User stories based on feature using Rally API

I'm trying to fetch all user stories that belong to certain feature, but which have children.
Here's how I created query for that using rally-node.
async.map(features, function(feature, cb) {
self.restApi.query({
type: 'hierarchicalrequirement',
limit: Infinity,
order: 'Rank',
fetch: ['FormattedID', 'Name', 'Children'],
parent: feature.ObjectID,
query: queryUtils.where('DirectChildrenCount', '>', 0)
}, cb);
}, function(err, results) {
//user stories
});
And here's how my feature looks like:
{ _rallyAPIMajor: '2',
_rallyAPIMinor: '0',
_ref: 'https://rally1.rallydev.com/slm/webservice/v2.0/portfolioitem/feature/18846103932',
_refObjectUUID: 'c01d7f828-a6d6-4efc-8160-c0c19ad0fabc',
_objectVersion: '7',
_refObjectName: 'Dashboard Widgets',
ObjectID: 18836103932,
FormattedID: 'F1',
DirectChildrenCount: 2,
Name: 'Dashboard Widgets',
UserStories:
{ _rallyAPIMajor: '2',
_rallyAPIMinor: '0',
_ref: 'https://rally1.rallydev.com/slm/webservice/v2.0/PortfolioItem/Feature/18846103932/UserStories',
_type: 'HierarchicalRequirement',
Count: 2 },
_type: 'PortfolioItem/Feature' },
I'm new to rally, so any further help regardind documentation, etc, is really appreciated.
Here is a full example where Feature is queried and its UserStories collection is fetched and then hydrated.
v2.0 removed the ability to return child collections in the same response for performance reasons. Now fetching a collection will return an object with the count and the url from which to get the collection data. Separate request is needed to hydrate a collection.
This change is documented here
I do not see a question in your post, I am not sure what problem you encounter, but his code gets user stories based on feature, filtered by ('DirectChildrenCount', '>', 0)
var rally = require('rally'),
queryUtils = rally.util.query;
mySettings = {
apiKey: '_secret',
server: 'https://rally1.rallydev.com', //this is the default and may be omitted
requestOptions: {
headers: {
'X-RallyIntegrationName': 'My cool node.js program',
'X-RallyIntegrationVendor': 'My company',
'X-RallyIntegrationVersion': '1.0'
},
}
},
restApi = rally(mySettings);
function queryFeature() {
return restApi.query({
type: 'portfolioitem/feature',
fetch: ['FormattedID', 'Name', 'UserStories'],
query: queryUtils.where('FormattedID', '=', 'F7')
});
}
function queryChildren(result) {
return restApi.query({
ref: result.Results[0].UserStories,
limit: Infinity,
order: 'Rank',
fetch: ['FormattedID', 'Name'],
query: queryUtils.where('DirectChildrenCount', '>', 0)
});
}
function onSuccess(result) {
console.log('Success!', result);
}
function onError(errors) {
console.log('Failure!', errors);
}
queryFeature()
.then(queryChildren)
.then(onSuccess)
.fail(onError);

Resources