Rewrite command handler - discord.js

I want to rewrite my command handler due to it breaking if I attempt to make a new command that's a little bit different, and somehow manages to break it. Someone can help by giving me a new code fully or just fixing mine. The error is somewhere in the: I don't know why, I think due to I didn't define config or name, but I would like some help with this please. Thank you!
let pull = require(`../src/commands/${dirs}/${file}`);
bot.commands.set(pull.config.name, pull);
if (pull.config.aliases) pull.config.aliases.forEach(a => bot.aliases.set(a, pull.config.name));
};
Heres the full code.
const logger = require("../utils/logger");
const Discord = require('discord.js')
const client = new Discord.Client();
const fs = require("fs")
const ms = require('ms');
module.exports = (bot) => {
const load = dirs => {
const commands = readdirSync(`./src/commands/${dirs}/`).filter(d => d.endsWith('.js'));
for (let file of commands) { //for each of these files
let pull = require(`../src/commands/${dirs}/${file}`);
bot.commands.set(pull.config.name, pull);
if (pull.config.aliases) pull.config.aliases.forEach(a => bot.aliases.set(a, pull.config.name));
};
};
readdir(`./src/commands/`, (err, directories) => {
if (err) logger.error(err);
var dirArray = [];
directories.forEach((f, i) => {
if (lstatSync(`./src/commands/${f}`)) {
dirArray.push(f);
}
});
dirArray.forEach(x => load(x));
});
};

You can take a look at mine if you want:
https://github.com/azul-i/shuxue
works with subdirs, required argument lengths, aliases, and admin requirement.
If you go with this, you will need to check main.js, handlers/commands.js and events/message.js
lmk if you need help understanding any of it.

Related

Discord JS - forEach looped embed

I'm quite new to Javascript, normally a Python person. I've looked at some other answers but my embed does not add the fields as expected. The embed itself is sent.
My Discord bot follows the guide provided by the devs (primary file, slash commands, command files). I am trying to loop through the entries in an SQLite query and add them as fields.
My command file is below.
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageEmbed } = require('discord.js')
const sqlite = require('sqlite3').verbose();
module.exports = {
data: new SlashCommandBuilder()
.setName('rank')
.setDescription('Rank all points.'),
async execute(interaction) {
const rankEmbed = new MessageEmbed()
.setColor('#0099ff')
.setTitle('Rank Board')
let db = new sqlite.Database('./databases/ranktest.db', sqlite.OPEN_READWRITE);
let queryall = 'SELECT name, points FROM pointstable ORDER BY points DESC'
db.all(queryall, [], (err, rows) => {
if (err) {
console.log('There was an error');
} else {
rows.forEach((row) => {
console.log(row.name, row.points)
rankEmbed.addField('\u200b', `${row.name}: ${row.points}`, true);
});
}
})
return interaction.reply({embeds: [ rankEmbed ] });
}
}
I would also like to convert row.name - held as Discord IDs - to usernames i.e. MYNAME#0001. How do I do this by interaction? I was able to obtain the User ID in another command by using interaction.member.id, but in this case I need to grab them from the guild. In Python I did this with await client.fetch_user but in this case the error await is only valid in async functions and the top level bodies of modules is thrown.
Thanks.
OK I've solved the first aspect, I had the return interaction.reply in the wrong place.
Relevant snippet:
rows.forEach((row) => {
console.log(row.name, row.points)
rankEmbed.addField('\u200b', `${row.name}: ${row.points}`, false);
})
return interaction.reply({embeds: [rankEmbed ]} );
Would still appreciate an answer to the converting row.name (user ID) to user name via fetch.
I've solved the second aspect also. Add the below into the loop.
rows.forEach((row) => {
let client = interaction.client
const uname = client.users.cache.get(row.name);
rankEmbed.addField('\u200b', `${uname}: ${row.points}`, false);

.toLowercase in client.on('message', async message => {

I want my bot to respond to commands that are typen with capital letters, but where should I put it, I really don't know... :heh:. So yea where should I put the .toLowercase for my bot to respond to capital letters?
client.on('message', async message => {
if(message.content.startsWith(";stats")){
cpuStat.usagePercent(function (error, percent) {
if (error) {
return console.error(error)
}
const cores = os.cpus().length // Counting how many cores your hosting has.
const cpuModel = os.cpus()[0].model // Your hosting CPU model.
const guild = client.guilds.cache.size.toLocaleString() // Counting how many servers invite your bot. Tolocalestring, meaning separate 3 numbers with commas.
const user = client.users.cache.size.toLocaleString() // Counting how many members in the server that invite your bot.
const channel = client.channels.cache.size.toLocaleString() // Counting how many channels in the server that invite your bot
const Node = process.version // Your node version.
const CPU = percent.toFixed(2) // Your CPU usage.
const d = moment.duration(message.client.uptime);
const days = (d.days() == 1) ? `${d.days()} day` : `${d.days()} days`;
const hours = (d.hours() == 1) ? `${d.hours()} hour` : `${d.hours()} hours`;
const minutes = (d.minutes() == 1) ? `${d.minutes()} minute` : `${d.minutes()} minutes`;
const seconds = (d.seconds() == 1) ? `${d.seconds()} second` : `${d.seconds()} seconds`;
const date = moment().subtract(d, 'ms').format('dddd, MMMM Do YYYY');
const embed = new Discord.MessageEmbed() // Stable or < below than 11.x.x use RichEmbed. More than 12.x.x or Master or https://github.com/discordjs/discord.js/ (github:discordjs/discord.js) use MessageEmbed.
embed.setTitle('Axmy#0102', message.author.displayAvatarURL());
embed.setDescription('Really non-useful bot, I know that everyone hates Axmy')
embed.addField('Servers 🏠', `\n${client.guilds.cache.size}`)
embed.addField('Users 🧑‍🤝‍🧑', `${client.guilds.cache.reduce((a, g) => a + g.memberCount, 0)}`)
embed.addField('Uptime <:tired:811194778149715979>', `${days}, ${hours}, ${minutes}, ${seconds}`)
embed.addField("Discord.js Version <:discord:811200194640216094> ", '12.3.1')
embed.addField("CPU Usage <:down:811195966714937395>", ` ${CPU}%`)
embed.addField("Node.js Version <:node:811196465095376896>", `${Node}`)
embed.setColor('PURPLE')
message.channel.send(embed)
})
}
})
A quick solution to your problem is this:
const prefix=";";
client.on('message', async message => {
if (message.author.bot) return;
if (!message.content.toLowerCase().startsWith(prefix)) return;
const args=message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
if (command==="stats") {
cpuStat.usagePercent(function (error, percent) {
if (error) {
return console.error(error)
}
//rest of the code...
But I suggest you to learn about command-handling, your codebase will look much better when you seperate commands into seperate files. There are a lot of youtube tutorials about it.

Call Exports.run async from a member phrase

Please help me understand how can i call that ping.js from user input, like if a user type ping it will Trigger cuz of the aliases but if a user types a full phrase it won't trigger.
Or in a non headic question how can i implent this to work -> if (message.content.includes('ping'))
Sorry in advance and thanks a lot
ping.js
const Discord = require('discord.js')
const colors = require('../lib/colors.json')
exports.run = async (client, message, args, level) => {
try {
const pingEmbed = new Discord.RichEmbed()
.setColor(colors.default)
.setFooter('ping)
.addField(`${message.author.id}`, 'hey')
const msg = await message.channel.send(pingEmbed)
const embed = new Discord.RichEmbed()
.setColor(colors.default)
.addField('...',
`${msg.createdTimestamp - message.createdTimestamp}ms`)
msg.edit(embed)
} catch (err) {
message.channel.send('There was an error!\n' + err).catch()
}
}
exports.conf = {
enabled: true,
aliases: ['ping'],
guildOnly: false,
permLevel: 'User'
}
exports.help = {
name: 'ping,
category: 'tools,
description: 'ping pong',
usage: 'ping'
}
If you want to check whether a message contains any of the aliases you can just use Array.some() like this:
let aliases = ['your', 'command', 'aliases']
client.on('message', message => {
if (aliases.some(trigger => message.content.includes(trigger))) {
// The message includes at least one of your keywords
}
})
In this example is just declared aliases, but you can use the array from your command and integrate this method in your normal command handler.

How do I return an array from an external function in Node

I have a file which contains the following:
const fs = require('fs');
var loadSingleCsv = function (filename) {
fs.readFileSync(filename, 'utf8', function (err, data) {
var dataArray = data.split(/\r?\n/);
dataArray.forEach((element,index, dataArray) => {
dataArray[index]= element.split(",");
});
dataArray.forEach((element,index, dataArray) => {
dataArray[index] = `${element[0]}, ${element[1]}, ${element[2]}, ${element[3]}, ${element[4]}`;
});
console.log(dataArray); // this prints to the console as expected
return dataArray;
});
}
module.exports = { loadSingleCsv };
When I call it from another file, the array shows as 'undefined'. Here is my code:
const loadCsv = require ('../../load-csv-file');
dataArray = loadCsv.loadSingleCsv('./csv-files/rcm-data-01.csv');
console.log(dataArray);
I'm assuming that this is a real newbie error, but I would appreciate any help you can give.
Thank you.
I think your problem is with loading the file
const loadCsv = require ('../../load-csv-file');
dataArray = loadCsv.loadSingleCsv('./csv-files/rcm-data-01.csv');
Please check the file path.

Is it possible to set state in Immer's produce()?

Now
await this.setState(produce(this.state, (draft) => {
draft.item.is_loading = true;
}));
this.setState(await produce(this.state, async (draft) => {
// is_loading is true now.
const name = await get_name();
draft.item.name = name;
draft.item.is_loading = false;
}));
Expected
this.setState(await produce(this.state, async (draft) => {
let name;
draft.item.is_loading = true;
// set state here first.
name = await get_name();
draft.item.name = name;
draft.item.is_loading = false;
}));
I want to set state in the middle of calling produce(). Is It possible? If there's any good idea, please let me know. Thanks. :D
That's because I think connecting two chunks together is more readable. Especially when I can reuse variable declared in the former. It can looks quite trivial, but the more complex a source code becomes, the more unnatural it becomes to me.

Resources