Collector goes wrong | discord.js - javascript

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');

Related

Discord.js doesn't collect DM from user

I'm trying to do a bot to verify members on a special guild.
They need to send "verify" into a specific channel, then they have to answer several questions. However, the collector doesn't seem to work properly. Nothing shows in console.
client.on('messageCreate', async message => {
if(message.author.id === botId) return;
if(message.channel.type != "dm") {
if(message.channelId == verifyChannelId && message.content == "verify") {
let appChannel = (await message.author.send('Hello, I\'m gonna asking you a few questions..')).channel;
appChannel.send('Are you on european server? (Yes/No)');
const filter = m => (appChannel.type === "dm");
const collector = appChannel.createMessageCollector({ filter, time: 15000 });
collector.on('collect', m => {
console.log(`Collected ${m.content}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
message.delete({ timeout: 1000 });
} else {
message.delete({ timeout: 1000 });
}
}
});
There are a couple of errors with this. First, you're using v13 of discord.js and as MrMythical mentioned in their comment, channel types are now uppercase, so checking if(message.channel.type != "dm") won't do much as it will always return true. Checking if (appChannel.type === "dm") won't work either as it will always returns false. And I'm not even sure why you'd check if the appChannel's type is DM anyway, it can't be anything else. Your filter should probably check if the answer is yes or no.
Another error is that you haven't enabled the DIRECT_MESSAGES intents. Without it, your createMessageCollector won't work in DM channels. Check out the working code below:
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.DIRECT_MESSAGES,
],
});
// ...
client.on('messageCreate', async (message) => {
// it could be if (message.author.bot) return;
if (message.author.id === botId) return;
if (message.channel.type === 'DM') return;
if (message.channelId !== verifyChannelId) return;
if (message.content.toLowerCase() === 'verify') {
let sentMessage = await message.author.send(
"Hello, I'm gonna asking you a few questions..",
);
let dmChannel = sentMessage.channel;
dmChannel.send('Are you on a European server? (Yes/No)');
const filter = (m) => ['yes', 'no'].includes(m.content.toLowerCase());
const collector = dmChannel.createMessageCollector({
filter,
// max: 1,
time: 15000,
});
collector.on('collect', (m) => {
console.log(`Collected ${m.content}`);
});
collector.on('end', (collected) => {
console.log(`Collected ${collected.size} items`);
});
}
// delete the message even if it wasn't "verify"
message.delete({ timeout: 1000 });
});

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);

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();
});
};

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

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);
}
}
});

How to use awaitReactions in guildMemberAdd

I send messages to users when they connect to my server, and I want to continue authorization by clicking on reactions.
How can I create this? I'm using the following code:
robot.on("guildMemberAdd", (gMembAdd) =>
{
gMembAdd.send(`Hi ${gMembAdd.toString()} welcome to the server Test`).then(msg => {
msg.react('βœ…')
.then(() => msg.react('❎'));
//--------------------Developmend-------------------------------------
let filter = (reaction, user) => reaction.emoji.name === 'βœ…' || reaction.emoji.name === '❎';
let col = msg.createReactionCollector(filter);
col.on('collect', r =>
{
if (r.users.last().id !== msg.author.id)
{
gMembAdd.addRole(gMembAdd.guild.roles.find("name", "Autorize")).catch(console.error)
r.remove(r.users.last().id);
console.log(` ${gMembAdd.user.id} ΠΈ ${gMembAdd.user.username} and ${r.emoji}`);
}
});
//--------------------------------------------------------------------
});
I need a reaction check and role assignment if the response is positive and kick if not. I don't understand how to continue.
Will this code be used correctly?
To check the reaction you can use MesssageReaction.emoji.name, as you did above.
For the other thing, you can use GuildMember.addRole() & GuildMember.kick().
Here's a sample you can check out:
robot.on('guildMemberAdd', async member => {
let msg = await member.send(`Hi ${member} welcome to the server Test`);
await msg.react('βœ…');
await msg.react('❎');
msg.createReactionCollection(r => ['βœ…', '❎'].includes(r.emoji.name))
.on('collect', r => {
if (r.emoji.name == 'βœ…')
member.addRole(member.guild.roles.find("name", "Authorize"))
.then(() => { console.log(`Added ${member.user.username} (${member.id}).`); })
.catch(console.error);
else if (r.emoji.name == '❎') member.kick("You got rejected.");
r.remove(r.users.last());
});
});
You can also use Message.awaitReactions(), which is better because it doesn't go on after the reaction is added:
robot.on('guildMemberAdd', async member => {
let msg = await member.send(`Hi ${member} welcome to the server Test`);
await msg.react('βœ…');
await msg.react('❎');
msg.awaitReactions(r => ['βœ…', '❎'].includes(r.emoji.name), {max: 1})
.then(collected => {
let r = collected.first();
if (r.emoji.name == 'βœ…')
member.addRole(member.guild.roles.find("name", "Authorize"))
.then(() => { console.log(`Added ${member.user.username} (${member.id}).`); })
.catch(console.error);
else if (r.emoji.name == '❎') member.kick("You got rejected.");
r.remove(r.users.last())
});
});

Categories

Resources