module.exports.run = (client, message, args) => {
if (message.member.roles.some(role => role.name === process.env.MODO)) {
const user = message.mentions.users.first();
// Parse Amount
const amount = !!parseInt(message.content.split(' ')[1]) ? parseInt(message.content.split(' ')[1]) : parseInt(message.content.split(' ')[2])
if (!amount) return message.reply('Vous devez spécifier un montant à supprimer !');
if (!amount && !user) return message.reply('Vous devez spécifier un utilisateur et le montant, ou juste une quantité de messages à purger !');
if (amount > 100) return message.reply('Malheureusement, discord ne permet pas la Suppression de plus de 100 messages en une fois ...');
// Fetch 100 messages (will be filtered and lowered up to max amount requested)
message.channel.fetchMessages({
limit: amount,
}).then((messages) => {
if (user) {
const filterBy = user ? user.id : Client.user.id;
messages = messages.filter(m => m.author.id === filterBy).array().slice(0, amount);
}
message.channel.bulkDelete(messages).catch(error => console.log(error.stack));
});
var purge = new Discord.RichEmbed()
.setAuthor(`Suppression de ${amount} Messages dans le salon ${message.channel.name}`)
.setFooter("Requête par " + message.member.user.tag, message.member.user.avatarURL)
.setTimestamp()
.setColor(0xF03434)
message.channel.send(purge).then(message => {
message.react('🗑')
client.on('messageReactionAdd', (reaction, user) => {
// on vérifie que ce soit bien la bonne réaction et on ne compte pas celui du bot
if (reaction.emoji.name === '🗑' && user.id !== client.user.id) {
message.delete()
}
})
});
}
}
What I would like is that at the level of the 'final' embed, when it tells me that the purge has been done, there is a reaction '🗑' and when we click it removes the message.
The problem is that the current code removes all the embed of the same type.
If I click on the reaction of the first embed, it also removes the second, and does not delete anything else...
Attaching a listener to the client's messageReactionAdd event is what's causing this; any reaction emits this event, and your code is executed for each one after a single purge. As long as the reaction is 🗑 and the user isn't the client, Message.delete() will be called on message.
(node: 10752) UnhandledPromiseRejectionWarning: DiscordAPIError: Unknown Message
at item.request.gen.end (/Users/jeremy/Desktop/BERRYBOT/node_modules/discord.js/src/client/rest/RequestHandlers/Sequential.js:85:15)
at then (/Users/jeremy/Desktop/BERRYBOT/node_modules/snekfetch/src/index.js:215:21)
at process._tickCallback (internal / process / next_tick.js: 68: 7)
(node: 10752) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated from the inside of the outside world, but it was not handled by .catch (). (rejection id: 14)
After adding that reaction that deletes the wrong message, it no longer exists. When you try to delete it again, this error will be thrown.
Furthermore, your code isn't waiting for the messages to be purged before sending the reply. Because of this, the message can be sent before and subsequently deleted by the TextChannel.bulkDelete() call. Then, when you try to react to the same message via Message.react(), your error is thrown because it no longer exists.
To make sure the code is executed in the proper order, make sure you're using your then() chains properly, or utilize the beauty of async/await.
Reorganizing the code, still using then() methods:
message.channel.fetchMessages({ limit: amount })
.then(fetchedMessages => {
const filterBy = user ? user.id : Client.user.id;
const toPurge = messages.filter(m => m.author.id === filterBy).array().slice(0, amount);
message.channel.bulkDelete(toPurge)
.then(deletedMessages => {
var embed = new Discord.RichEmbed()
.setAuthor(`Suppression de ${deletedMessages.size} Messages dans le salon ${message.channel.name}`)
.setFooter(`Requête par ${message.author.tag}`, message.author.avatarURL)
.setTimestamp()
.setColor(0xF03434)
message.channel.send(embed)
.then(reply => {
reply.react('🗑');
const filter = (reaction, user) => reaction.emoji.name === '🗑' && user.id !== client.user.id;
reply.createReactionCollector(filter, { maxMatches: 1 })
.on('collect', () => reply.delete());
});
});
})
.catch(console.error);
Alternatively, using await:
// You must define your callback function as async to use the 'await' keyword! It should look like...
// async (client, message, args) => { ... }
try {
const fetchedMessages = await message.channel.fetchMessages({ limit: amount });
const filterBy = user ? user.id : Client.user.id;
const toPurge = messages.filter(m => m.author.id === filterBy).array().slice(0, amount);
const deletedMessages = await message.channel.bulkDelete(toPurge);
var embed = new Discord.RichEmbed()
.setAuthor(`Suppression de ${deletedMessages.size} Messages dans le salon ${message.channel.name}`)
.setFooter(`Requête par ${message.author.tag}`, message.author.avatarURL)
.setTimestamp()
.setColor(0xF03434)
const reply = await message.channel.send(embed)
await reply.react('🗑');
const filter = (reaction, user) => reaction.emoji.name === '🗑' && user.id !== client.user.id;
reply.createReactionCollector(filter, { maxMatches: 1 })
.on('collect', async () => await reply.delete());
} catch(err) {
console.error(err);
}
You'll notice this code is using ReactionCollectors as opposed to attaching listeners to the messageReactionAdd event. The former are meant for this usage and will prevent memory leaks. Also, I've changed some of the variable names to make the code easier to read and understand. A few other very minor improvements are present as well.
Related
He is giving me this script of welcome/goodbye to Discord error and he has already tried many things if someone helps me I would appreciate it very much, Thanks
module.exports = (client) => {
const channelIdA = '718596514305277972'
client.on('guildMemberAdd', (member) => {
console.log("Se ha unido una nueva persona al servidor TPA")
const messageA = `message`
const channel = (channelIdA)
channel.send(messageA)
})
}
module.exports = (client) => {
const channelIdB = '890891192995303424'
client.on('guildMemberRemove', (member) => {
console.log("Se ha salido una persona del servidor TPA")
const messageB = `message`
const channel = (channelIdB)
channel.send(messageB)
})
}
You are attempting to send a message to a channel by calling the .send() method. However, you are calling the method on a string. The send() method only exists on text based channels. To send a message to a specific channel, replace your message sending code with this
client.on("guildMemberAdd", members => {
client.channels.cache.get("REPLACE WITH CHANNEL ID").send("message")
});
client.on("guildMemberRemove", members => {
client.channels.cache.get("REPLACE WITH OTHER CHANNEL ID").send(" other message")
});
If the above does not work, try this:
(works without cache)
client.on("guildMemberAdd", async (member) => {
const channel = await client.channels.fetch("REPLACE WITH CHANNEL ID")
channel.send(`${member.user.username}, welcome`)
});
client.on("guildMemberRemove", async (member) => {
const channel = await client.channels.fetch("REPLACE WITH OTHER CHANNEL ID")
channel.send(`${member.user.username} has left`)
});
You should be getting the channel using this. If you already have the channel in cache (something happened in the channel after the bot started), you can use the channels cache as well.
I'm trying to make a command where you can set up an LFG role (LFG = looking for game).
Right now, I need the bot to find a role by its name, but it doesn't work. I have no idea why, I have tried many other thing like finding the role by its ID or structuring the code differently but nothing... Heres is the code:
collector1.on('collect', () => {
// Si l'utilisateur a cliqué sur 1️⃣ LFG
message.reactions.removeAll();
const embed1 = new MessageEmbed()
.setTitle(
`**--------------------LFG role configuration--------------------**`,
)
.addField(
`You clicked on 1️⃣`,
`Send in the next 30 the name of the new LFG role.`,
true,
)
.addField(
`Missclicked?`,
`Wait 30 seconds for the bot to send a timeout message and try again.`,
true,
);
let filter = (m) => m.author.id === message.author.id;
m.edit(embed1).then(() => {
message.channel
.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time'],
})
.then((message) => {
message.reactions.removeAll();
message = message.first();
let role = message.guild.roles.cache.find((r) => r.name === message);
message.channel.send(`Alright, The new lfg role is ${role}!`);
})
.catch((collected) => {
message.channel.send('Timeout.');
});
});
});
Also, I have a second problem which is the bot doesn't remove all the reactions.
message is not a string- it's a Message object. I think you meant message.content
let role = message.guild.roles.cache.find((r) => r.name === message.content);
Also, I have a second problem which is the bot doesn't remove all the reactions
Maybe you meant m.reactions.removeAll()?
To find a role by name you can simply use
message.guild.roles.find(role => role.name === "Rolename");
I am developing my ticketing system in the last time. I saw an update of 'Ticketsbot' and turned curious "how is that possible???, i have never seen that!"
So, can you please help me how can I replace reactions with such buttons.
The part of my code (part which is responsible for reactions):
let embed = new discord.MessageEmbed()
.setAuthor(`Welcome to your ticket!`)
.addField('Here you can:', ':one: Report an issue or bug of the server.\n:two: Suggest any idea for the server.\n:three: Report a staff member of the server.')
.addField('Make sure to be patient, support will be with you shortly.', `<#&837064899322052628>`)
.setColor('#468DFF')
.setFooter(`AftNetwork`)
let embed2 = new discord.MessageEmbed()
.setAuthor(`React with ⛔ if your issue has been resolved.`)
.setColor('#468DFF')
.setFooter(`AftNetwork`)
let reactionMessage = null;
try {
reactionMessage = await channel.send(`${message.author}`, {
embed: embed,
}).then(message => message.channel.send(embed2));
} catch (error) {
console.log(error);
return message.channel.send(
'⚠️ Error sending message in ticket channel!',
);
}
try {
await reactionMessage.react('🔒');
await reactionMessage.react('⛔');
} catch (err) {
console.log(err);
return channel.send('⚠️ Error sending emojis!');
}
const collector = reactionMessage.createReactionCollector(
(reaction, user) => {
// collect only reactions from the original
// author and users w/ admin permissions
const isOriginalAuthor = message.author.id === user.id;
const isAdmin = message.guild.members.cache
.find((member) => member.id === user.id)
.hasPermission('MANAGE_MESSAGES');
return isOriginalAuthor || isAdmin;
},
{ dispose: true },
);
collector.on('collect', (reaction, user) => {
switch (reaction.emoji.name) {
// lock: admins only
case '🔒':
const isAdmin = message.guild.members.cache
.find((member) => member.id === user.id)
.hasPermission('MANAGE_MESSAGES');
if (isAdmin) {
channel.updateOverwrite(message.author, {
SEND_MESSAGES: false,
});
} else {
// if not an admin, just remove the reaction
// like nothing's happened
reaction.users.remove(user);
}
break;
// close: anyone i.e. any admin and the member
// created the ticket
case '⛔':
channel.send('Deleting this ticket in 5 seconds...');
setTimeout(() => channel.delete(), 5000);
break;
}
});
Have a good day!
For now there is no official wrapper so here is an unofficial library that you can use and also here is a small exemple. You can join their discord on the link provided for more help.
let button = new MessageButton()
.setLabel("I like")
.setStyle("blurple")
.setEmoji("🍕")
.setID("like_button")
what you will add is the above code and in the .send() funtion it will be this channel.send(`${message.author}`, {embed: embed, component: button})
and that's basically it.
I am developing this bot, and I want the user to be able to react only once in the emoji, and if he reacts other times the command does not work. Can someone help me?
let messagereturn = await message.channel.send(embed);
await messagereturn.react('🔁');
const reactions = ['🔁'];
const filter = (reaction, user) => reactions.includes(reaction.emoji.name) && user.id === User.id;
const collector = messagereturn.createReactionCollector(filter)
collector.on('collect', async emoji => {
switch(emoji._emoji.name) {
case('🔁'):
const embed1 = new Discord.MessageEmbed()
.setColor('#00ff00')
.setDescription(`${User} **deu um tapa em** ${message.author}`)
.setImage(rand)
await message.channel.send(embed1)
}
})
The createReactionCollector method has an optional options object, and it allows you to set the max reactions to collect, which in your case is 1.
example:
const collector = messagereturn.createReactionCollector(filter, { max: 1 })
Is there anything remotely wrong with this code?
no errors pop up and there isn't a reaction once the bot sends the messages.
any help would be appreciated, thank you in advance!
const a = msg.guild.roles.get('666712822985654322'); //Verified User
// the role constants are in the same chronological order as below.
const filter = (reaction,user) => ['668236468384169986'].includes(reaction.emoji.name);
const embed = new Discord.RichEmbed()
.setColor(0x00FF00)
.setTitle('Rules')
.setDescription(`
In order to gain access to the rest of the server you must read and abide by these rules:
By reacting with :white_check_mark: you agree to these rules
Roles:
:white_check_mark: ${a.toString()}`)
.setThumbnail(msg.author.avatarURL)
.addField('Rule #1:You do not talk about fight club', 'Second Rule: You do not TALK about fight club')
.setFooter("Use \'!command list\' to get aquainted with Peb 3000");
msg.channel.send(embed).then(async message => {
await message.react('668236468384169986'); //white check mark
message.awaitReaction(filter, {})
.then(collected =>{
const reaction = collected.first();
switch(reaction.emoji.name) {
case('\:white_check_mark:'):
message.member.addRole(a).catch(err => {
console.log(err);
return message.channel.send(`Error adding you to this role: **${err.message}**`);
});
message.channel.send(`You have been added to the **${a.name}** role!`).then(m => m.delete(3000));
break;
}
}).catch(collected => {
return msg.collected.send(`I couldn't add you to this role!`)
})
});
I'd recommend reading both An Idiot's Guide - Using Emojis as well as Discord.js Guide - Reactions, as your current approach for Unicode emojis won't work.
In your case, :white_check_mark: should be ✅ or an equivalent.
The collected options will triggeret when collector end collect, you no provide any options to stop collector, so its will never happen.
The 1 way to give member role on react follow this code. But when bot restart, you need again use this command and create collector.
const roleToAdd = msg.guild.roles.get('666712822985654322'); //Verified Role
if(!roleToAdd) return
let embed = new Discord.RichEmbed()
.setColor(0x00FF00)
.setTitle('Rules')
.setDescription(`
In order to gain access to the rest of the server you must read and abide by these rules:
By reacting with :white_check_mark: you agree to these rules
Roles:
:white_check_mark: ${a.toString()}`)
.setThumbnail(msg.author.avatarURL)
.addField('Rule #1:You do not talk about fight club', 'Second Rule: You do not TALK about fight club')
.setFooter("Use \'!command list\' to get aquainted with Peb 3000");
msg.channel.send(embed).then(message => {
const filter = (reaction, user) => reaction.emoji.name === '✅' && user.id === msg.author.id && reaction.message.id = message.id
const collector = message.createReactionCollector(filter, {});
collector.on('collect', r => {
if(r.emoji.name === '✅') {
let member = message.guild.members.get(reaction.users.last().id)
member.addRole(roleToAdd)
.then( member => {
message.channel.send(`You have been added to the **${roleToAdd.name}** role!`).then(m => m.delete(3000));
})
.catch(console.error)
}
})
collector.on('end', collected => console.log(`Collected ${collected.size} items`));
})
The way number 2 its listen reactionadd event. After restart its will work.
bot.on('messageReactionAdd', (reaction, user) => {
if(reaction.message.id === 'YOUR MESSAGE ID' && reaction.emoji.name === 'youreactionname') {
let meber = reaction.message.guild.members.get(user.id)
member.addRole('yourRole')
}
.catch(console.error)
});