Why does the bot react itself? (discord.js) - javascript

I'm setting up a bot, who will await for a user's reaction to write a short message. Currently, the bot responds itself to his reaction! Why?
const { Client, RichEmbed, Discord } = require('discord.js');
const config = require('./config.json');
const client= new Client();
client.on('ready', () => {
console.log('je suis pret!');
client.user.setActivity("/help pour appeler de l'aide (avec le code NOMAD bien sur)", { type: 'WATCHING' });
})
client.on('messageReactionAdd', (reaction, user) => {
console.log(`${user.username} reacted with "${reaction.emoji.name}".`);
});
client.on('messageReactionRemove', (reaction, user) => {
console.log(`${user.username} removed their "${reaction.emoji.name}" reaction.`);
});
client.on('message', async message => {
if (message.author.bot) return;
if (message.content.toLowerCase().startsWith('!rea')) {
try {
const sentMessage = await message.channel.send('Select a number.');
for (let n = 1; n <= 5; n++) await sentMessage.react(`${n}⃣`);
const filter = (reaction, user) => ['1', '2', '3', '4', '5'].includes(reaction.emoji.name.slice(0, 1)) && user.id === message.author.id;
const collected = await sentMessage.awaitReactions(filter, { maxMatches: 1, time: 60000 });
if (collected.size === 0) {
await sentMessage.clearReactions();
await message.channel.send('Your time ran out.');
} else {
const reaction = collected.first();
switch(reaction.emoji.name.slice(0, 1)) {
case '1':
await message.channel.send('You chose `one`.');
break;
}
}
} catch(err) {
console.error(err);
}
}
});
client.login(config.token);
I found the problem: the bot considers the first message: "!rea", so if I add the reaction below !rea, it answers!
How can I fix this, because I want that he considered the embed reactions!
Thank you for your help

Your client's message event is emitted by any message, including those sent by itself.
To prevent bots (and therefore your client as well) from triggering the code, add a condition checking the author's User.bot property at the beginning of the callback, and return if it's true.
if (message.author.bot) return; // Stop if the author is a bot.
// Continue with your code.
Additionally, you're collecting reactions on the wrong message, and on every one. message outside of your first then() callback is the one the bot received.
To make things much more simple and readable, we can use the await keyword (note that it can only be used asynchronous context, like in a function declared as async).
Combining these changes...
client.on('message', async message => {
if (message.author.bot) return;
if (message.content.toLowerCase().startsWith('!rea')) {
try {
const sentMessage = await message.channel.send('Select a number.');
for (let n = 1; n <= 5; n++) await sentMessage.react(`${n}⃣`);
const filter = (reaction, user) => ['1', '2', '3', '4', '5'].includes(reaction.emoji.name.slice(0, 1)) && user.id === message.author.id;
const collected = await sentMessage.awaitReactions(filter, { maxMatches: 1, time: 60000 });
if (collected.size === 0) {
await sentMessage.clearReactions();
await message.channel.send('Your time ran out.');
} else {
const reaction = collected.first();
switch(reaction.emoji.name.slice(0, 1)) {
case '1':
await message.channel.send('You chose `one`.');
break;
}
}
} catch(err) {
console.error(err);
}
}
});

Related

How do I delete a user's new message

I'm pretty trash at coding so I need a little bit of help. I'm trying to code my discord bot to delete someone's messages for one minute after they click a react emoji. It sounds simple but for my tiny pea brain, it's not. This is what I have got so far. It deletes all messages from different users and guilds it's in, forever. I want it so it only delete messages in one channel for one minute.
client.once('message', async userMessage => {
if (userMessage.content.startsWith(''))
{
botMessage = await userMessage.channel.send('Who here likes goats?')
await botMessage.react("πŸ‘")
await botMessage.react("πŸ‘Ž")
const filter = (reaction, user) => {
return (
["πŸ‘", "πŸ‘Ž"].includes(reaction.emoji.name) && user.id === userMessage.author.id
);
};
botMessage
.awaitReactions(filter, { max: 1, time: 60000, errors: ["time"] })
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === "πŸ‘Ž") {
userMessage.channel.send(`${userMessage.author}, how dare you. I guess no on here likes me. Hmmm, because of that I shall now eat all your messages! BAAAAAHAHAHHAHAHA!`)
setTimeout(() => {
client.on("message", async msg => {
if (author.msg.content.startsWith("")) {
userMessage.channel = await msg.delete();
}
});
}, 2000);
} else {
userMessage.reply("Thanks!");
}
})
.catch((_collected) => {
userMessage.channel.send("Hehe")
});
}
});
Btw, the code is in discord.js!
Your problem is this chunk of code
setTimeout(() => {
client.on("message", async msg => {
if (author.msg.content.startsWith("")) {
userMessage.channel = await msg.delete();
}
});
}, 2000);
This is not how you use events.
A) Your message event is nested within another which could cause memory leaks.
B) To get the content you need to use msg.content, author.msg Is not a thing.
C) I assume your intention here: msg.content.startsWith("") is to always fire the if statement, in that case why not do if (true).
Here's how I would do it:
Create a Set in the namespace which will hold id's of users who's messages should be deleted
const toDelete = new Set();
If they react with a πŸ‘Ž add them to the set.
if (reaction.emoji.name === "πŸ‘Ž") {
userMessage.channel.send('Your message here');
if (!toDelete.has(userMessage.author.id)) {
toDelete.add(userMessage.author.id);
}
}
On each message event check if the author of the message has their id in the set, If so delete their message
client.once('message', async userMessage => {
if (toDelete.has(userMessage.author.id)) {
return userMessage.delete()
.catch(console.error);
}
if (userMessage.content.startsWith('')) {
// Rest of your code
I think your problem in understanding how everything works.
I took everything from discord.js documentation.
Type reaction command to see how it works.
const Discord = require("discord.js");
require("dotenv").config();
const TOKEN = process.env.TOKEN||"YOUR TOKEN";
const PREFIX = process.env.PREFIX||"YOUR PREFIX";
const bot = new Discord.Client();
bot.on("ready", async function(e) {
console.log("Loaded!");
})
bot.on("message", async function(message) {
if (message.author.bot) return;
if (!message.content.startsWith(PREFIX)) return;
let args = message.content.slice(PREFIX.length).trim().split(/\s+/);
let command = args.splice(0, 1).toString().toLowerCase();
if (command == "reaction") {
message.delete();
let msg = await message.channel.send("Click on the reaction");
await msg.react("πŸ‘");
await msg.react("πŸ‘Ž");
let filter = (reaction, user) => {
return ["πŸ‘", "πŸ‘Ž"].includes(reaction.emoji.name) && user.id == message.author.id;
}
msg.awaitReactions(filter, {max: 1, time: 10000, errors: ["time"]}).then(collected => {
let reaction = collected.first();
if (reaction.emoji.name == "πŸ‘Ž") {
return message.channel.send("downvote");
}
return message.channel.send("upvote");
}).catch(e => {
message.channel.send("user didn't vote");
})
}
})
bot.login(TOKEN);

How can i count the reactions in discord.js and after that display it (slappey version)

I'm trying to display who win the poll but i run into a problem. While I want to get the number of the reactions with
.addField("πŸ”΄:", `${results.get("πŸ”΄").count}`)
My console says that the count is undefined. I've tried to search it but I didn't find anything and I tried so many ways but nothing.
The code:
const BaseCommand = require('../../utils/structures/BaseCommand');
const Discord = require("discord.js")
module.exports = class HelpCommand extends BaseCommand {
constructor() {
super('vote', 'moderation', []);
}
async run(client, message, args) {
const filter = m => m.author.id == message.author.id;
let embed = new Discord.MessageEmbed()
.setFooter(`${message.author.tag} started the poll`)
.setTimestamp();
message.channel.send('what the question is?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.setTitle(msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
message.channel.send('first option?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.addField(`[πŸ”΄] the first option:`, msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
message.channel.send('second option?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.addField(`[πŸ”΅] the second option`, msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
try {
await message.channel.bulkDelete(7)
.then(message.channel.send(embed).then(sentMessage => sentMessage.react('πŸ”΄')).then(reaction => reaction.message.react('πŸ”΅')));
} catch (err) {
console.log(err);
}
const filters = (reaction) => reaction.emoji.name === "πŸ”΄" || reaction.emoji.name === "πŸ”΅";
const results = await message.awaitReactions(filters, { time: 15000 })
let resultsEmbed = new Discord.MessageEmbed()
.setTitle(`the poll result`)
.setDescription(`the result of the poll: ${args.join(" ")}`)
.addField("πŸ”΄:", `${results.get("πŸ”΄").count}`)
.addField("πŸ”΅:", `${results.get("πŸ”΅").count //if i dont type here the .count then i've got this embed but after the "πŸ”΅": says'undefined' }`)
.setColor("#84daf8")
.setTimestamp()
message.channel.send(resultsEmbed);
}
}
A szavazΓ‘s eredmΓ©nye = The poll result in my language. I see this when i dont write the .count there: .addField("πŸ”΄:", `${results.get("πŸ”΄").count}`)
and i see this when i write .count
The problem was that the bot was trying to retrieve the reactions of a deleted message I believe. In order to fix this, you'll have to put your resultsEmbed code inside of your chained then methods.
Code:
try {
await message.channel.bulkDelete(7)
.then(message.channel.send(embed)
.then(sentMessage => sentMessage.react('πŸ”΄'))
.then(reaction => reaction.message.react('πŸ”΅'))
.then(reaction => {
const filters = (reaction) => reaction.emoji.name === "πŸ”΄" || reaction.emoji.name === "πŸ”΅";
reaction.message.awaitReactions(filters, { time: 15000 }).then(collected => {
console.log(collected);
if (collected.get("πŸ”΄") !== undefined && collected.get("πŸ”΅") !== undefined) {
let optionOne = collected.get("πŸ”΄").count;
let optionTwo = collected.get("πŸ”΅").count;
let resultsEmbed = new Discord.MessageEmbed()
.setTitle("the poll result")
.setDescription(`the result of the poll: ${args.join(" ")}`)
.addField("πŸ”΄:", `${optionOne}`)
.addField("πŸ”΅:", `${optionTwo}`)
.setColor('#')
.setTimestamp()
message.channel.send(resultsEmbed);
} else {
//there were no votes for one of the options, thus it will not be able to get property
message.channel.send("There were no votes for one of the options.");
}
})
})
);
} catch (err) {
console.log(err);
}

Collector goes wrong | discord.js

I want people to be able to react to a message and then be contacted by the bot with 3 questions. The problem is that it skips all questions for its own and answers it for its own.
I would be happy if you can describe the problem to me well so that it no longer occurs. Here is my code:
client.on('messageReactionAdd', async (reaction, user) => {
if (reaction.message.partial) await reaction.message.fetch();
if (reaction.partial) await reaction.fetch();
if (user.bot) return;
if (reaction.message.channel.id === '809490905236373558') {
if (reaction.emoji.name === 'βœ…') {
const questions = [`Test1`, `Test2`, `Test3`];
const dmChannel = await reaction.message.guild.members.cache
.get(user.id)
.send('**Beantworte die Fragen du keks**');
const collector = dmChannel.channel.createMessageCollector(() => true);
let i = 0;
const res = [];
dmChannel.channel.send(questions[0]);
collector.on('collect', async (msg) => {
if (questions.length == i) return collector.stop('MAX');
const answer = msg.content;
res.push({ question: questions[i], answer });
i++;
if (questions.length == i) return collector.stop('MAX');
else {
dmChannel.channel.send(questions[i]);
}
});
collector.on('end', async (collected, reason) => {
if (reason == 'MAX') {
const data = reaction.message.guild.channels.cache.find(
(ch) =>
ch.name.toLowerCase() == 'apply-final-bewerbungen' &&
ch.type == 'text',
);
await data.send(
`${reaction.message.member || reaction.message.author} (${
reaction.message.author.tag
}) hat eine Bewerbung abgegeben!\n\n${res
.map((d) => `**${d.question}** \n ${d.answer}`)
.join('\n\n')}`,
);
}
});
}
}
});
It sends all questions without waiting because you don't check if the incoming message in your message collector is coming from the member. As the bot sends the first question, there is an incoming message your collector catches (the bot's message) and it sends the next ones till it reaches the end.
You can check if the msg.author is a bot in your collector and stop responding if it is. The following should work:
collector.on('collect', async (msg) => {
if (msg.author.bot) return;
if (questions.length == i) return collector.stop('MAX');

is there can delete message when click this reaction emoji DIscord.js

How to fix this ? i want to delete message when user click reaction X
client.on('message', async message => {
if (message.channel.id === emojiChannelID) {
try {
await message.react('βœ…');
await message.react('βœ–');
} catch(err) {
console.error(err);
}
}
});```
There's an message.awaitReaction() in discord.js, that will return reactions from users
// Filter for only
const filter = function(reaction, user) {
return reaction.emoji.name === 'βœ…' || reaction.emoji.name === 'βœ–';
}
// {...}
let reactionMessage = await message.react('βœ…');
// Make sure to set max: 1 so that the promise returns after the first reaction
let reactionCollection = await reactionMessage.awaitReactions(filter, { max: 1});
// reactionCollection is a Collection<string, MessageReaction>
// Use first() to get the first (and only)
let reaction = reactionCollection.first();
Kian here,
This code should work for you,
if you would like I can go through and explain each line :)
Have a good day chief!
async function emojiMessage(message, validReactions) {
for (const reaction of validReactions) await message.react(reaction);
const filter = (reaction, user) => validReactions.includes(reaction.emoji.name) && (!user.bot)
return message
.awaitReactions(filter, {
max: 1,
time: 42000
})
.then(collected => collected.first() && collected.first().emoji.name);
}
async function deleteMessage(message) {
const emoji = await emojiMessage(message, ["βœ…", "❌"]);
console.log(emoji)
// if the emoji is a tick:
if (emoji === "βœ…") {
// delete their message
console.log("tick")
if (message.deletable == true) {
console.log("can delete")
console.log("attempting to delete")
message.delete()
}
if (!message.deletable == false) {
"cannot delete"
}
} else if (emoji === "❌") { // if the emoji is a cross
/*
* do something else
*/
return;
}
}
client.on('message', message => {
if (message.channel.id === emojiChannelID) {
// runs the function
deleteMessage(message)
}
/*
* do something else
*/
})
Note:
First upload πŸŽ‰
I've tried my best to make the code understandable/work , if there is any issues feel free to comment, I'll fix it :)
Example Usage:
const m = await message.channel.send('hi!');
reactionDelete(m, message, 20000); // assuming 'message' is the actual sent message
async function reactionDelete (botMessage, playerMessage, timeout) {
const filter = (reaction, user) => {
return ['πŸ—‘οΈ'].includes(reaction.emoji.name) && user.id === playerMessage.author.id;
};
botMessage.react('πŸ—‘οΈ');
botMessage.awaitReactions(filter, { max: 1, time: timeout})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === 'πŸ—‘οΈ') {
botMessage.delete();
}
})
.catch(collected => {
if (botMessage.deletable) botMessage.reactions.removeAll();
});
};

Discord.js currency to command handler

I am trying to move all of my currency/shop commands/ Sequelize database into the command handler from index.js (works perfectly in index.js file) but I am running into issues transferring data from the index.js file into the individual command files. Any help on how to properly integrate the index.js commands into the command handler would be greatly appreciated. I realize this is a lot to go through but it would really mean a lot to me if anyone was able to help me out
index.js:
Reflect.defineProperty(currency, 'add', {
value: async function add(id, amount) {
const user = currency.get(id);
if (user) {
user.balance += Number(amount);
return user.save();
}
const newUser = await Users.create({ user_id: id, balance: amount });
currency.set(id, newUser);
return newUser;
},
});
Reflect.defineProperty(currency, 'getBalance', {
value: function getBalance(id) {
const user = currency.get(id);
return user ? user.balance : 0;
},
});
client.once('ready', async () => {
const storedBalances = await Users.findAll();
storedBalances.forEach(b => currency.set(b.user_id, b));
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', async message => {
if (message.author.bot) return;
currency.add(message.author.id, 1);
if (!message.content.startsWith(prefix)) return;
const input = message.content.slice(prefix.length).trim();
if (!input.length) return;
const [, command, commandArgs] = input.match(/(\w+)\s*([\s\S]*)/);
if (command === 'balance') {
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${currency.getBalance(target.id)}πŸ’°`);
} else if (command === 'buy') {
const item = await CurrencyShop.findOne({ where: { name: { [Op.like]: commandArgs } } });
if (!item) return message.channel.send('That item doesn\'t exist.');
if (item.cost > currency.getBalance(message.author.id)) {
return message.channel.send(`You don't have enough currency, ${message.author}`);
}
const user = await Users.findOne({ where: { user_id: message.author.id } });
currency.add(message.author.id, -item.cost);
await user.addItem(item);
message.channel.send(`You've bought a ${item.name}`);
} else if (command === 'shop') {
const items = await CurrencyShop.findAll();
return message.channel.send(items.map(i => `${i.name}: ${i.cost}πŸ’°`).join('\n'), { code: true });
} else if (command === 'leaderboard') {
return message.channel.send(
currency.sort((a, b) => b.balance - a.balance)
.filter(user => client.users.cache.has(user.user_id))
.first(10)
.map((user, position) => `(${position + 1}) ${(client.users.cache.get(user.user_id).tag)}: ${user.balance}πŸ’°`)
.join('\n'),
{ code: true }
);
}
});
converting balance command to balance.js
balance.js:
const { currency, getBalance, id, tag } = require('../index.js');
module.exports = {
name: "balance",
description: "checks balance",
execute(message) {
const target = message.mentions.users.first() || message.author;
message.channel.send(`${target.tag} has ${currency.getBalance(target.id)}πŸ’°`);
},
};
error:
TypeError: Cannot read property 'getBalance' of undefined
Command Handler
client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const commandName = args.shift().toLowerCase();
const command = client.commands.get(commandName)
|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command) return;
if (command.guildOnly && message.channel.type !== 'text') {
return message.reply('I can\'t execute that command inside DMs!');
}
if (command.args && !args.length) {
let reply = `You didn't provide any arguments, ${message.author}!`;
if (command.usage) {
reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
}
return message.channel.send(reply);
}
if (!cooldowns.has(command.name)) {
cooldowns.set(command.name, new Discord.Collection());
}
const now = Date.now();
const timestamps = cooldowns.get(command.name);
const cooldownAmount = (command.cooldown || 3) * 1000;
if (timestamps.has(message.author.id)) {
const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
if (now < expirationTime) {
const timeLeft = (expirationTime - now) / 1000;
return message.reply(`please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command.name}\` command.`);
}
}
timestamps.set(message.author.id, now);
setTimeout(() => timestamps.delete(message.author.id), cooldownAmount);
try {
command.execute(message, args);
} catch (error) {
console.error(error);
message.reply('there was an error trying to execute that command!');
}
});
the bot sends an error from the command handler as seen above
EDIT: Cherryblossom's post seems to work. i have 1 more issue with immigrating the buy command though I dont know how to make the async work as async doesnt work in command handler. here is what i tried
const { currency, CurrencyShop} = require('../index.js');
const item = await CurrencyShop.findOne({ where: { name: { [Op.like]: commandArgs } } });
if (!item) return message.channel.send('That item doesn\'t exist.');
if (item.cost > currency.getBalance(message.author.id)) {
return message.channel.send(`You don't have enough currency, ${message.author}`);
}
const user = await Users.findOne({ where: { user_id: message.author.id } });
currency.add(message.author.id, -item.cost);
await user.addItem(item);
message.channel.send(`You've bought a ${item.name}`);```
What's happening is that in balance.js, currency is undefined. You need to export currency from index.js:
module.exports = { currency }
Also, in balance.js, you don't need to (and actually can't) import/require properties of other objects (getBalance, tag, id). Sorry if that doesn't make sense but basically you only need to require currency:
const { currency } = require('../index.js')
Edit
await can only be used in an async function. Edit the execute function so it is like this:
async execute(message) {
// your code here
}
When calling execute, use await. You'll need to make the message handler async as well:
client.on('message', async message => {
// code...
try {
await command.execute(message, args);
} catch (error) {
console.error(error);
message.reply('there was an error trying to execute that command!');
}
}

Categories

Resources