Telegram bot inline keyboard via Node.JS - javascript

I'm using the node-telegram-bot-api module,
How can I make my keyboard to inline Keyboard?
This is my code:
bot.onText(/^\/start$/, function (msg) {
const opts = {
reply_to_message_id: msg.message_id,
reply_markup: {
resize_keyboard: true,
one_time_keyboard: true,
keyboard: [ ['Level 1'] ]
}
};
bot.sendMessage(msg.chat.id, "I'm a test robot", opts);
});

I answered a question similar to this link: How can create menu for telegram bot in bot father?
in your case you could use:
keyboard: [["uno :+1:"],["uno \ud83d\udc4d", "due"],["uno", "due","tre"],["uno", "due","tre","quattro"]]

In your case the solution would be:
const opts = {
reply_to_message_id: msg.message_id,
reply_markup: JSON.stringify({
inline_keyboard:
[
[{text: 'Level 1'}],
]
})
};

You could use:
https://github.com/RealPeha/telegram-keyboard
The library if focused on Telegraf, but you could use without it.

You just need to provide an InlineKeyboardButton object instead of plain text in your keyboard array of arrays.
bot.onText(/^\/start$/, function (msg) {
const opts = {
reply_to_message_id: msg.message_id,
reply_markup: {
resize_keyboard: true,
one_time_keyboard: true,
keyboard: [
[{text: 'Level 1'}],
],
}
};
bot.sendMessage(msg.chat.id, "I'm a test robot", opts);
});

Related

Unhandled Runtime Error. TypeError: Failed to fetch. Next.js

I have an adult-content website, and I have an error when I take one filter (name of my partner website):
When I refresh the page, the error disappears, and also if I go through the link in the new tab - it works fine, but if I want to take this filter from my website it crashes...
I don't have this problem inside the incognito browser window.
If I clear cache and cookies, I also don't have this problem for a while, but then it comes back.
I make my fetch inside getStaticProps inside try catch and catch does not detect the error.
Here is my next.config.js
const securityHeaders = [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), geolocation=()',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin',
},
];
const nextConfig = {
reactStrictMode: false,
swcMinify: true,
redirects: async () => [
{
source: '/:path*',
has: [{ type: 'host', value: 'www.example.com' }],
destination: 'https://example.com/:path*',
permanent: true,
},
],
images: {
dangerouslyAllowSVG: true,
contentSecurityPolicy: 'default-src "self"; script-src "none"; sandbox;',
minimumCacheTTL: 300,
domains: [
'galleryn0.awemdia.com',
],
},
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders,
},
{
source: '/_next/:path*',
headers: [
{
key: 'Access-Control-Allow-Origin',
value: '*',
},
],
},
];
},
};
module.exports = nextConfig;
I have tried to find something similar, but I could not get it
I have fixed if by changing filter naming (name of my partner website) inside URL.

How to connect "html-minifier" to gulp?

I am using gulp and I get an error on startup...
How do I fix this?
The returned value is not a function.
I've been trying to fix this for hours now, but I don't understand what's wrong.
Maybe this is somehow possible using this plugin? vinyl-source-stream
const htmlMinify = require('html-minifier').minify
function html() {
const postcssPlugins = [
autoprefixer({
overrideBrowserslist: [
'>0.25%',
'not ie 11',
'not op_mini all'
]
}),
pxtorem({
rootValue: 16,
unitPrecision: 5,
propList: ['font', 'font-size', 'line-height', 'letter-spacing'],
replace: false,
mediaQuery: false,
minPixelValue: 0,
})
];
const postcssOptions = { from: undefined }
const filterType = /^text\/css$/
const plugins = [
posthtmlPostcss(postcssPlugins, postcssOptions, filterType)
];
const options = {
includeAutoGeneratedTags: true,
removeAttributeQuotes: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortClassName: true,
useShortDoctype: true
}
return src(config.app.html)
.pipe(include({ prefix: '##' }))
.pipe(posthtml(plugins))
.pipe(htmlMinify(options))
.pipe(dest(config.build.html))
}
exports.stream = series(clear, html, stream)
If using plugin "vinyl-source-stream".
The solution to this question would be the following code.
In this code, I used plugins that work with streams.
But this code only converts one file!
You can read more details about each plugin on npmjs.
html-minifier, vinyl-fs, vinyl-source-stream, map-stream
const { src, dest, series } = require('gulp');
const htmlMinify = require('html-minifier');
const vfs = require('vinyl-fs');
const source = require('vinyl-source-stream');
const map = require('map-stream');
const options = {
includeAutoGeneratedTags: true,
removeAttributeQuotes: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortClassName: true,
useShortDoctype: true,
collapseWhitespace: true
};
function sol() {
let minify = function(file, cb) {
cb(null, htmlMinify.minify(file.contents.toString(), options));
};
return vfs
.src(['app/index.html'])
.pipe(map(minify))
.pipe(source('index.html'))
.pipe(vfs.dest('build'));
}
exports.sol = series(sol);
This was the answer to this particular question.
There is a more elegant solution to this problem.
No third party plugins required. I described it in this post.

How can i convert an object in a specific format into another format

I am having a hard time trying to convert an object supplied in a specific format from API into a target format using javascript. Please note that in the target format, the false values are not present. This is intentional. Can someone please help by showing how I can do the this kind of conversion. Thank you
// Original format
const rules= [
{
dealer: {
view: true,
edit: false,
add: false
},
franchise: {
view: true,
edit: true,
add: true
},
branch: {
view: true,
edit: false,
add: false
}
}
]
// Target format
const rules = [
{
actions: ["view"],
subject: ["dealer"]
},
{
actions: ["view"],
subject: ["franchise"]
},
{
actions: ["edit"],
subject: ["franchise"]
},
{
actions: ["add"],
subject: ["franchise"]
},
{
actions: ["view"],
subject: ["branch"]
}
];
I implemented mapping function which take each item and map it according to the value if true
let rules = [
{
dealer: {
view: true,
edit: false,
add: false
},
franchise: {
view: true,
edit: true,
add: true
},
branch: {
view: true,
edit: false,
add: false
}
}
]
rules = rules.map(item => {
const keys = Object.keys(item);
let mappedItem = []
keys.forEach(key => {
for (const property in item[key]) {
if (item[key][property]) {
mappedItem.push({ subject: [key], actions: [property] })
}
}
})
return mappedItem;
});
let rules= [
{
dealer: {
view: true,
edit: false,
add: false
},
franchise: {
view: true,
edit: true,
add: true
},
branch: {
view: true,
edit: false,
add: false
}
}
];
const result = rules.map(obj => Object.keys(obj).map(k => ({
subject: [k],
actions: Object.keys(obj[k]).filter(action => obj[k][action])
})).reduce((acc, cur) => ([
...acc,
...cur.actions.map(a => ({subject: cur.subject, actions: [a]}))
]),[]))
console.log(result);

inquirer package, present questions based on previous answers

I'm using NPM 'inquirer' package in order to present the user various questions. One of them is a 'choices' selection.
Is there a way to present follow up questions based on the 'choices' selection?
Here's my code:
const { prompt } = require('inquirer');
require('colors');
const questions = [
{
type: 'input',
name: 'appName',
message: 'Enter application name:'
},
{
type: 'input',
name: 'appDescription',
message: 'Enter app description:'
},
{
type: 'input',
name: 'appAuthor',
message: 'Enter app author:'
},
{
type: 'checkbox',
name: 'plugins',
message: 'Select plugins to install:',
choices: [
{
name: 'Cassandra'
}
]
}
];
module.exports.performQuestions = async () => {
console.log('\nWelcome to Chef!\n'.underline.italic.cyan);
const answers = await prompt(questions);
if (!answers.appName) {
console.error('\nPlease provide app name!\n'.red);
process.exit(1);
}
answers.appType = 'service';
return answers;
};
Here I want to present a few more questions if the user selects 'Cassandra' is that possible?
Thanks.
You can use "when" and like in the example bellow, the second question will popup only if "Cassandra" is selected:
const QUESTIONS = [
{
name: 'your-name',
type: 'list',
message: 'Your name:',
choices: ['Batman', 'Superman', 'Ultron', 'Cassandra'],
},
{
name: 'hello-cassandra',
type: 'confirm',
message: 'Oh, hello Cassandra!',
when: (answers) => answers['your-name'] === 'Cassandra',
},
];
inquirer.prompt(QUESTIONS)
.then(answers =>
{
console.log(answers);
});

dojo Autocomplete

I can use dijit.form.FilteringSelect to show the Dropdown box. But It requests all data from the store dojo.data.ItemFileReadStore at once that I Don't want. I want it to query the store with the current value of the textbox and show the Autocompleter options.
A more complete example as above but equals of valid. But in my case I use QueryReadStore
this.store = new dojox.data.QueryReadStore({
url: 'url',
sortFields : [{attribute: 'attribute', descending: true}],
requestMethod : "get"}
);
callSuggest : function(){
var fetch = {
query: {attribute: "*"},
queryOptions: {
ignoreCase: true,
deep: true
},
serverQuery: this.searchParam,
onComplete: dojo.hitch(this, function(result, dataObject){
//do something
}),
onError: function(errText){
console.error('error');
}
};
this.store.fetch(fetch);
},
You would have to perform something like this I assume,
itemStore .fetch({ query: { name: "pepper", aisle: "Spices" },
queryOptions: { ignoreCase: true }, onComplete: ... });
Please see this link for a complete listing and details.
http://dojotoolkit.org/reference-guide/quickstart/data/usingdatastores/filteringitems.html

Categories