Limit user reaction to message - javascript

I'm building a simple poll bot for Discord in JavaScript, right now I'm trying to implement max number of reactions per user to a message.
For example, suppose we have the following options for a poll question:
The Question?
Option A
Option B
Option C
Option D
Option E
Each "option" is a reaction to the message given from the bot, I want to make sure that a user cannot react to more than 3 of those options.
My train of thought was to make a messageReactionAdd listener and
then when the user reacted for the 4th time, remove the last
reaction, sending him a message like "You've already voted 3 times,
please remove a reaction to vote again".
Still, I'm stuck trying to navigate through the objects to find the
total reaction count per user I can find the total reaction count
per emoji but that's not what I need.
Could someone give me some insight on this?
EDIT
Code used to send messages:
Embed = new Discord.MessageEmbed()
.setColor(0x6666ff)
.setTitle(question)
.setDescription(optionsList);
message.channel.send(Embed).then(messageReaction => {
for (var i = 0; i < options.length; i++){
messageReaction.react(emojiAlphabet[i][0]);
}
message.delete().catch(console.error);
});

Try this:
const {Collection} = require('discord.js')
// the messages that users can only react 3 times with
const polls = new Set()
// Collection<Message, Collection<User, number>>: stores how many times a user has reacted on a message
const reactionCount = new Collection()
// when you send a poll add the message the bot sent to the set:
polls.add(message)
client.on('messageReactionAdd', (reaction, user) => {
// edit: so that this does not run when the bot reacts
if (user.id === client.user.id) return
const {message} = reaction
// only do the following if the message is one of the polls
if (polls.has(message)) {
// if message hasn't been added to collection add it
if (!reactionCount.get(message)) reactionCount.set(message, new Collection())
// reaction counts for this message
const userCount = reactionCount.get(message)
// add 1 to the user's reaction count
userCount.set(user, (userCount.get(user) || 0) + 1)
if (userCount.get(user) > 3) {
reaction.users.remove(user)
// <#!id> mentions the user (using their nickname if they have one)
message.channel.send(`<#!${user.id}>, you've already voted 3 times, please remove a reaction to vote again.`)
}
}
})
client.on('messageReactionRemove', (reaction, user) => {
// edit: so that this does not run when the bot reacts
if (user.id === client.user.id) return
const {message} = reaction
const userCount = reactionCount.get(message)
// subtract 1 from user's reaction count
if (polls.has(message)) userCount.set(user, reactionCount.get(message).get(user) - 1)
})

Related

Is there a way to personalise collectors to a user? Discord.js

To put it simply, my bot is reading off another bot to see if a drop has been dropped, however, there are some problems occurring.
Current Scenario:
User 1 drops
User 2 drops
The bot my bot is reading off (ID:733122859932712980, hence the filter) sends the first drop
My bot pings the role twice before the second drop has dropped.
The bot my bot is reading off sends the second drop
No ping from my bot
What I want is for the second ping to happen after the second drop happens
Current code:
const Discord = require('discord.js');
module.exports = {
name: "drop",
aliases:["d"],
async execute(client, msg, args) {
const filter = m => m.author.id === "733122859932712980";
const collector = msg.channel.createMessageCollector({
filter
});
collector.on("collect", m => {
if (m.embeds[0]){
const embed = m.embeds[0]
if(embed.author?.name.includes("K-DROP")){
for (var i=0; i<embed.fields.length ; i++){
if(embed.fields[i].name) {
if(embed.fields[i].value.includes("Winner")){
return;
}
else
{
m.channel.send("<#&980128851495641101>")
break;
}
}
}
}
collector.stop();
}
})}};

Discord.js: MessageCollector, messages doesn't trigger collect event

I'm trying to code a giveaway bot in discord.js, it is the first time that I code in Javascript so if you have any recommendations I would be happy to hear them !
I am trying to launch a giveaway on a specific channel, the channel is usually locked for #everyone, when the giveaway starts, I open the channel and start listening for inputs.
I would like to listen for every messages, check if it is a correct ethereum wallet, if it is, gather it, if it is not, delete the message from the channel.
I wanted to use a createMessageCollector without any filter, and manually check everything. However, messages doesn't trigger the collect event..
Here is the code:
async function launch_giveaway(interaction) {
const giveawayChannel = interaction.options.getChannel("in");
const giveawayName = interaction.options.getString("name");
const numWinner = interaction.options.getInteger("num_winners");
const hours = interaction.options.getInteger("hours");
const minutes = interaction.options.getInteger("minutes");
const channelWinner = interaction.options.getChannel("winner_channel")
let endTime = Math.round(Date.now()/1000) + hours*3600 + minutes*60;
await interaction.reply(`Starting the giveaway of **${giveawayName}** in ${giveawayChannel} for ${hours}:${minutes}, I will put the ${numWinner} winners in ${channelWinner} !`);
await open_giveaway(interaction, giveawayChannel, giveawayName, numWinner, endTime, channelWinner)
await interaction.followUp(`Done ! ${giveawayChannel} is now open and members can send there wallets !`);
setTimeout(close_channel, hours*3600000 + minutes*60000, interaction, giveawayChannel, channelWinner, giveawayName);
let wallets = [];
const filter = m => {return true;};
const collector = giveawayChannel.createMessageCollector({ filter, time: 15000 });
collector.on('collect', m => {
console.log("someone typed in #giveaway");
// check ethereum wallet regex etc
// add to wallets list
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} wallets`);
});
}
I even tested with the default code from this tutorial, but it doesn't log anything on my console.
Thank you very much for your help,
Chronoxx

How can I link an invite code to a user? DISCORD.JS

I have an invite create command, but whenever it creates an invite it does it under the bots ID. I'm wondering if there is a way I can add the invite code to a different user ID so when they use an invites command, it will show the amount of invites that specific code has sent. Bump
module.exports = {
commands: 'invites',
requiredRoles: ['Affiliate'],
callback: (message) => {
if (message.channel.id === '824652970410770443'){
var user = message.author
message.guild.fetchInvites()
.then
(invites =>
{
const userInvites = invites.array().filter(o => o.inviter.id === user.id);
var userInviteCount = 0;
for(var i=0; i < userInvites.length; i++)
{
var invite = userInvites[i];
userInviteCount += invite['uses'];
}
const embed = new Discord.MessageEmbed()
.setColor('#1AA2ED')
.setTitle(message.author.username + "'s Invites")
.setDescription(`Invites: ${userInviteCount}`)
message.reply(embed).then((msg) => {
message.delete()
})
}
)
}
if (message.channel.id !== '824652970410770443'){
message.reply(`You can't do that here`)
}
}
}; ```
You can not change the Invite Creator that Discord knows, however you could locally store which user created which invite link.
This would however have to be done when in the command that creates an invite.
You have multiple options on how to store this data, but the simplest one would just be writing the data to an Object that associates the User ID to the Invite ID, then stringifying and saving that Object to a file whenever your bot exits and loading and parsing that file whenever your bot starts.
Then, whenever you need to know which user created an invite link, look it up in that Object.

How to store messages sent by specific user in discordjs?

I'm trying to create a discord js bot which can send a random message by a specified user.
Here's my attept:
const ch = client.channels.cache.get("12345");
const soma = client.users.cache.get("4321");
if(message.content.startsWith(prefix+'test')){
console.log(`${ch}`);
ch.messages.fetch({ limit: 100 }).then(messages => {
console.log(`Received ${messages.size} messages`);
messages.forEach(message => message.author.id)
messages.forEach(function (message){
if (message.author.id === {soma}){
console.log(message.content);
}
})
})
};
I just can't figure out how to put the author id and the message content into an array or just go thru it when the command is executed.
Ok i read ur script and at the const soma = client.users.cache.get("4321"); part i noticed that ur trying to get the id from the users of the bot which isnot needed u can just use the id instantly so all u ahve to do is making soma defined as ur id no need for client.cache.get just like this const soma = "332036461669122048" for example, and for the channel you can just make it into const ch = message.channel.id instead of getting the channel from the client cuz ur getting it in a wrong way
Edit: and at the if (message.author.id === {soma}) you dont need to add the "{","}" its not needed

Discord.js deleteMessage() doesn't work

I am creating a Discord bot with discord.js and I'd like to create a command that can clear messages. For now, I have this code (only the interesting part) and I can't figure out why it doesn't work:
// Importing discord.js, creating bot and setting the prefix
const Discord = require('discord.js');
const bot = new Discord.Client();
const prefix = "/";
// Array that stores all messages sent
messages = [];
bot.on('message', (message) => {
// Store the new message in the messages array
messages.push(message);
// Split the command so that "/clear all" becames args["clear", "all"]
var args = message.content.substring(prefix.length).split(" ");
// If the command is "/clear all"
if(args[0] == "clear" && args[1] == "all") {
bot.deleteMessages(messages); // Code that doesn't work
// Resets the array
messages = [];
}
}
// CONNECT !!!
bot.login('LOGING TOKEN HERE');
Can you help me ?
You should use <TextChannel>.bulkDelete instead.
Example:
msg.channel.bulkDelete(100).then(() => {
msg.channel.send("Purged 100 messages.").then(m => m.delete(3000));
});
This would delete 2 - 100 messages in a channel for every call to this method so you would not receive 429 (Too many Requests) Error frequently which might result in your token being revoked.
I see two problems:
the messages array is always empty; there is no code that adds items to the array, so the call to bot.deleteMessages will always get an empty array;
it does not appear that deleteMessages is an available method on Discord.Client;
Based on the documentation, I think what you want is sweepMessages. The description of that states:
Sweeps all text-based channels' messages and removes the ones older than the max message lifetime. If the message has been edited, the time of the edit is used rather than the time of the original message.
Try changing the code to instead call bot.sweepMessages(1);, which I think will tell the client to clear all messages older than one second.
Another way to do this, without sweepMessages is by using fetchMessages:
let user = message.mentions.users.first();
let amount = !!parseInt(message.content.split(' ')[1]) ? parseInt(message.content.split(' ')[1]) : parseInt(message.content.split(' ')[2])
var prefix = '!'
if (message.content.startsWith(prefix + 'clear') && !amount)
return message.reply('Must specify an amount to clear!');
if (message.content.startsWith(prefix + 'clear') && !amount && !user) return message.reply('Must specify a user and amount, or just an amount, of messages to clear!');
message.channel.fetchMessages({
limit: amount,
}).then((messages) => {
if (user) {
const filterBy = user ? user.id : bot.user.id;
messages = messages.filter(m => m.author.id === filterBy).array().slice(0, amount);
}
message.channel.bulkDelete(messages).catch(error => console.log(error.stack));
});
This will allow users to use the command !clear [#] to delete that number of messages when sent. If it is run as just !clear you can set how many get deleted, without a specified number.
discord.js Documentation - TextChannel#fetchMessages
You can swap
bot.deleteMessages()
to:
messages.forEach(x => x.delete())
Its not like that. you should fetch the messages first then use bulkDelete to delete them
, here is a simple example
// Normal Javascript
<Message>.channel.fetchMessages()
.then(messages => {
// Here you can use bulkDelete(101) to delete 100 messages instead of using fetchMessages and deleting only 50
<Message>.channel.bulkDelete(messages);
});
// ES6
let messages = await <Message>.channel.fetchMessages();
// Here you can use bulkDelete(101) to delete 100 messages instead of using fetchMessages and deleting only 50
await <Message>.channel.bulkDelete(messages);

Categories