Warm tip: This article is reproduced from stackoverflow.com, please click
discord.js javascript node.js

Delete an embed when a reaction is added

发布于 2020-03-27 10:20:21
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.

Questioner
Asgarrrr
Viewed
128
slothiful 2019-07-04 11:45

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.