Discord Giveaway bot always gives the bot as winner - javascript

The bot should return that "no one entered" when no one enters the giveaway, but even if that's the case, it still says "#Dbot winner". Am I missing something in the code?
let msg = await message.channel.send(
"**๐ŸฅณGIVEAWAY๐Ÿฅณ**",
{
embed: {
title: `${(args.slice(2, args.length)).join(" ")}`,
color: 3447003,
description: `React with ๐ŸŽ‰ to enter!\nTime to enter: ${args[0]}\nWinners: ${args[1]}`,
footer: {
text: `dbot 2021 ยฉ giveaway ends ${endTime.toLocaleTimeString()}`
}
}
});
await msg.react('๐ŸŽ‰')
setTimeout(() => {
msg.reactions.cache.get('๐ŸŽ‰').users.remove(msg.author.id)
setTimeout(() => {
let winner = msg.reactions.cache.get('๐ŸŽ‰').users.cache.random();
if (msg.reactions.cache.get('๐ŸŽ‰').users.cache.size < 1) {
msg.channel.send(`No one entered giveaway :sadge:`);
}
if (!msg.reactions.cache.get('๐ŸŽ‰').users.cache.size < 1) {
console.log(winner);
msg.channel.send(`${winner} is our winner!๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰ check 1`);
}
}, 3000);
}, timerMilliseconds);

It's because you first check if users.cache.size is less than 1, then if (!msg.reactions.cache.get('๐ŸŽ‰').users.cache.size < 1).
users.cache.size will return a number and in JavaScript !number will return a boolean. Check the snippet below:
const num0 = 0;
const num1 = 1;
const num2 = 2;
console.log(num0, !num0);
console.log(num1, !num1);
console.log(num2, !num2);
This means that with your second if statement, you're checking if false is less than 1, which is true in JavaScript.
To fix this, you simply need to convert the second if to an else statement:
if (msg.reactions.cache.get('๐ŸŽ‰').users.cache.size < 1) {
msg.channel.send(`No one entered giveaway :sadge:`);
} else {
console.log(winner);
msg.channel.send(`${winner} is our winner!๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰ check 1`);
}

You need to enable the MEMBERS intent on the Discord Developer Console and add that intent to your ClientOptions.

Related

Discord JS, how to not allow user to execute a command while answering another command's question, unless it's finished

So, I have these two (kind of messy) commands.
Here are the codes, though their content doesn't really matter (I guess so):
This one is a find the hidden ball inside the boxes game.
client.on("message", async message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
const { MessageCollector } = require("discord.js-collector");
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
const rndInt = randomIntFromInterval(1, 5)
console.log(rndInt)
let answerBox = "";
if (command === "b" || command === "box") {
const user = message.author.id
switch(rndInt) {
case 1:
answerBox = 1;
break;
case 2:
answerBox = 2;
break;
case 3:
answerBox = 3;
break;
case 4:
answerBox = 1;
break;
case 5:
answerBox = 2;
break;
default:
message.channel.send("ERROR: If you received this message, please contact the support.");
};
message.channel.send(`A ball is hidden under the boxes below!!
:gift: โ”€โ”€ :one:
:gift: โ”€โ”€ :two:
:gift: โ”€โ”€ :three:`);
const botMessage = await message.channel.send(`<#${user}>, Type how many coins you wanna bet.`);
const userMessage = await MessageCollector.asyncQuestion({
botMessage,
user: message.author.id,
});
let coinsBet = userMessage.content;
if (coinsTotal < coinsBet) {
await message.channel.send("You don't have enough coins to bet.");
} else if (isNaN(coinsBet) == false) {
const botMessage = await message.channel.send("Type which box do you think the ball is (1, 2 or 3).");
const userMessage = await MessageCollector.asyncQuestion({
botMessage,
user: message.author.id
});
let bet = userMessage.content;
if (userMessage.content == answerBox) {
await message.reply("You got it right and won double the coins!");
coinsTotal += coinsBet * 2;
} else if (isNaN(bet) == true || bet >= 4) {
await message.channel.send("That wasn't a valid input, please type =b ou =box.");
} else {
await message.reply(`You got it wrong and lost all the coins which you bet. The right answer was ${answerBox}.`);
coinsTotal -= coinsBet;
}
} else {
await message.channel.send("That wasn't a valid input, please type =b ou =box.");
}
};
});
And this other one opens up a store:
client.on("message", (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
if (command === "store") {
message.channel.send(`โ•ญโ‹Ÿโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”€โ”€โ€ข~ Type the product code (number) to buy it.
โœฆโœงโœฆโœง STORE
ยป 1 - Green Seed: 0 coins.
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ‹ž`)
message.channel.awaitMessages(m => m.author.id == message.author.id,
{max: 1, time: 10000}).then(collected => {
if (collected.first().content.toLowerCase() == '1') {
message.reply(`You bought 1 "Green seed" with success!`);
seedGreen++;
seedTotal++;
}
else
message.reply(`Something happened, and it wasn't possible to complete your order..`);
}).catch(() => {
message.reply('Your order was cancelled due to lack of response.');
});
};
});
Notice how none of that is actually connected to a database, but that's not the point. Thing is, everything is actually working without any issues, except one thing.
In the store code, if an user type "=b" or "=box" instead of "1" or another wrong answer, the bot starts the box game, and whenever an user answers the box game questions with "=store", it also starts the store code.
I tried to figure out how to prevent this from happening, once I created a "let isActive = false" variable on top of the code, and set it to true whenever the bot started the store or box code, and set to false when it was finished, so I could put (&& isActive === false) at the first if of those codes and let them execute only if they are "inactive" (not doing any event I coded).
But it was all in vain, it didn't really work, so I'm pretty much stuck here, and I would gladly accept any kind of help to overcome this.
There are many ways to solve this issue. Here's one that I thought out: At the beginning of the script, you can provide some sort of state prop to the client. I called it userState and set it to a Collection:
client.userState = new Discord.Collection();
Then whenever a user starts a multi-step command that you don't want them to execute while still in the command, you can set that user's id to some descriptive state, e.g. "boxGame":
client.userState.set(message.author.id, "boxGame");
And whenever you need to check if they're in a multi-step command, you can check with:
client.userState.get(message.author.id);
Which will either return "boxGame" or undefined, and you can easily differentiate between them to stop them or let them execute a command, for example, using a switch statement:
if (client.userState.has(message.author.id)) {
const state = client.userState.get(message.author.id);
switch (state) {
case "boxGame":
message.channel.send("you have to complete the box game first bro");
break;
default:
message.channel.send("You're doing something, finish that something first!");
}
}
And when they complete the box game, you can
client.userState.delete(message.author.id);
to clear their state.
Edit: Just reminding you again that this is only one solution on how to solve it, and there are probably better solutions to this than mine.

Reason after blacklisting command Discord.js

I want to add a reason to my blacklists (with the command !blacklist {userid} {reason}) which are visible in the embeds below like .addField ("๐Ÿ’ฌ Reason:", somecode) how can I fix this?
if (command === "blacklist") {
if(!config["allowed-users"].includes(message.member.id)) return;
const user = client.users.cache.get(args[0]);
if(!user) {
return message.channel.send("This user does not exist")
}
if(blacklist.has(user.id)) {
return message.channel.send("This user is already on the blacklist")
}
blacklist.set(user.id, 'blacklisted');
let set = db.fetch(`g_${message.guild.id}`);
var embed = new Discord.MessageEmbed()
.setTitle(":warning: Blacklisted :warning:")
.setColor('#fc5a03')
.addField("๐Ÿ‘ฎ Moderator:", message.author.tag)
.addField("๐Ÿ‘ค User:", user.username)
.addField("๐Ÿ†” User ID:", user.id)
.addField("๐Ÿ•’ Blacklisted on:", message.createdAt)
.setFooter("ยฉ 2020 - 2021 GlobalChat", "https://cdn.discordapp.com/avatars/759021875962576916/cc32b2b08fdd52ae86294516d34532c5.png?size=128")
.setThumbnail(user.avatarURL({ dynamic:true }))
.addField("Unblacklist?", "Please contact <#267818548431290369> or <#331736522782932993>");
client.guilds.cache.forEach(g => {
try {
client.channels.cache.get(db.fetch(`g_${g.id}`)).send(embed);
} catch (e) {
return;
}
});
}
First you'll want to check if there is no reason, this can be simple done by checking, for both approaches, if the second argument is undefined, like so
if (args[1] === undefined) {
const reason = "No reason.";
}
This solution will work for both approaches, since if the second argument is undefined there can be no more after it
You could take reason as an argument.
Inside the command add
const reason = args[1];
OR if you wanted to have the rest of the blacklist args dedicated to the reason you could add something along the lines of
let reason = ""
for (let i = 1; i < args.length; i++) {
// It's very important that i starts as 1, so we do not take the first argument into account for the reason
reason += args[i];
}
And then you can add to the embed
.addField("๐Ÿ’ฌ Reason:", reason);
If you went with the first approach, the blacklist command would work like this
!blacklist 012345678910111213 the_reason_here
// or
!blacklist 012345678910111213 reason
The limitation to this approach is that a multi word reason isn't very intuitive.
If you went with the second approach though, the blacklist command would work like this
!blacklist 012345678910111213 The reason the user was banned and it can go on and on and on as long as the writer wants
You'll want to fetch the reason in the same way that you fetched the user id, like this:
const reason = args[1];
After that, in order to make sure that the reason doesn't show as undefined, you'll want to add a check in the form of an if statement, like this:
if (!reason) {
reason = "No reason";
}
After that, add .addField("๐Ÿ’ฌ Reason:", reason) in the position of fields you want it to be.
Your code should look something like this:
if (command === "blacklist") {
if (!config["allowed-users"].includes(message.member.id)) return;
const user = client.users.cache.get(args[0]);
const reason = args[1];
if (!user) {
return message.channel.send("This user does not exist")
}
if (blacklist.has(user.id)) {
return message.channel.send("This user is already on the blacklist")
}
if (!reason) {
reason = "No reason";
}
blacklist.set(user.id, 'blacklisted');
let set = db.fetch(`g_${message.guild.id}`);
var embed = new Discord.MessageEmbed()
.setTitle(":warning: Blacklisted :warning:")
.setColor('#fc5a03')
.addField("๐Ÿ‘ฎ Moderator:", message.author.tag)
.addField("๐Ÿ‘ค User:", user.username)
.addField("๐Ÿ†” User ID:", user.id)
.addField("๐Ÿ•’ Blacklisted on:", message.createdAt)
.addField(("๐Ÿ’ฌ Reason:", reason)
.setFooter("ยฉ 2020 - 2021 GlobalChat", "https://cdn.discordapp.com/avatars/759021875962576916/cc32b2b08fdd52ae86294516d34532c5.png?size=128")
.setThumbnail(user.avatarURL({
dynamic: true
}))
.addField("Unblacklist?", "Please contact <#267818548431290369> or <#331736522782932993>");
client.guilds.cache.forEach(g => {
try {
client.channels.cache.get(db.fetch(`g_${g.id}`)).send(embed);
} catch (e) {
return;
}
});
}

Discord.js for loop behaving oddly

I'm working on a kick command for a Discord bot in Discord.js. How it works is a previous function passes an array of user IDs to attempt to kick from the server. For some reason, the for loop is repeating more than it should and the i value doesn't seem to change sometimes.
Here's my code:
exports.kick = async (guild, targets, member, reason, bot) => {
var modRoleQuery = await exports.queryModRole(guild, member, bot);
var outputMessage = '';
if (modRoleQuery === false && !member.hasPermission('ADMINISTRATOR') && member != guild.me) return `You do not have permission to execute this command.`;
else if (targets.length === 0) return `Command usage: ${config.prefix}kick <#mentions/IDs> [reason]`;
else if (!guild.me.hasPermission('KICK_MEMBERS')) return `I require the \`Kick Members\` permission to execute this command.`;
else if (targets.length > 10) return `You may only kick 10 members at a time.`;
else if (reason.length > 1000) return `The kick reason must not exceed 1000 characters. Currently, it is ${reason.length}.`;
for (i = 0; i < targets.length; i++) {
console.log(`checking ${targets[i]}, ${i}`);
let targetMember = guild.member(targets[i]);
if (targetMember) {
if (targetMember.kickable) {
let targetMemberModRole = await exports.queryModRole(guild, targetMember, bot);
if ((targetMemberModRole || targetMember.hasPermission('ADMINISTRATOR')) && !member.hasPermission('ADMINISTRATOR')) {
outputMessage += `Unable to kick \`${targetMember.user.tag}\`: Only administrators can kick people with the moderator role and/or admin perms.\n`
} else {
await targetMember.user.send(`You were kicked from ${targetMember.guild.name} by ${member.user.tag}:\nReason: \`${reason}\``).catch(err => {});
await targetMember.kick(`[${member.user.tag}] ${reason}`);
exports.modLogEvent(bot, guild, `KICK`, targetMember.user, member.user, reason);
outputMessage += `Successfully kicked \`${targetMember.user.tag}\`\n`;
}
} else {
outputMessage += `Unable to kick \`${targetMember.user.tag}\`: I don't have permission to kick them.\n`;
}
} else {
outputMessage += `Unable to kick \`${targets[i]}\`: They don't seem to be in this server.\n`;
console.log(`${targets[i]} is not a member`)
}
}
outputMessage += `**Kick Reason:**\n\`${reason}\``;
return outputMessage;
}
When the size of the array is 1, this works as expected, however when it is more than 1, it doesn't. I've put in some console.log() functions for debugging purposes.
For some reason, the i value gets stuck on 1. I also ran it a bit earlier (this is before I added the console.log()s) and it behaved even more oddly:
I've been trying to debug this for over a day now and I'm not getting anywhere. Any assistance would be greatly appreciated.

Error: Unexpected Identifier When using an eval command

Ok, so I follow a youtube video on how to make an Eval command (source code: https://github.com/MenuDocs/Discord.JS-Tutorial/blob/Episode-21/commands/owner/eval.js )and in their video they can just do eval message.author.id and bam it works. Whereas in my bot it appears with an error in chat: Error while evaluating: Unexpected identifier ( https://imgur.com/a/1NWuWEy *note i use 2 'a's to keep it separate from my the bot online, reducing duplicate messages).
case 'evaal':
const args = message.content.substring(PREFIX.length).trim().split(" ");
const ownerID = '285198963722944514';
if(message.author.id == ownerID) {
try {
let toEval = args.join(" ")
let evaluated = inspect(eval(toEval, { depth: 0 }));
if (!toEval) {
return message.channel.send("Error while evaluating: \`cannot evaluate air\`!");
} else {
let hrStart = process.hrtime()
let hrDiff;
hrDiff = process.hrtime(hrStart);
return message.channel.send(`*Executed in ${hrDiff[0] > 0 ? `${hrDiff[0]}s ` : ''}${hrDiff[1] / 1000000}ms.*\n\`\`\`javascript\n${evaluated}\n\`\`\``, { maxLength: 1900 })
}
} catch (e) {
return message.channel.send(`Error while evaluating: \`${e.message}\``)
}
} else {
return message.reply('You are not allowed to use this command. (Owner Only)').then(m => m.delete(5000))
}
break;
As linked above in the imgur image, the bot responds but only with the error message. I expect it to tell me the author's id of the message (me).

Javascript: Anti-spam Automoderator (Discord.js)

I am coding a multipurpose Discord bot to replace some of the more minor ones, and I am looking for a piece of code for a feature that recognizes repeated messages or messages sent in a very short time period (let's say 5000ms).
Here is what could be used to implement this idea.
client.on("message", (message) => {
//let's use something like a spam variable for 10 or more messages sent within 5000ms
if(message.content === spam) {
message.reply("Warning: Spamming in this channel is forbidden.");
console.log(message.author.username + " (" + message.author.id + ") has sent 10 messages or more in 5 seconds in " + message.channel.name + ".");
}
});
For reference, I also made a feature that deletes messages, using a ~delete [n] command. It looks like this:
//this will only delete one message in the channel, the most recent one.
message.delete(1000);
//1000 represents the timeout duration. it will only delete one message, regardless of the value.
//we can delete multiple messages with this, but note it has to come before the reply message.
message.channel.bulkDelete(11);
I was thinking of somehow combining the delete command with recognizing spam messages. If you have any ideas, that would be perfect.
Try This:
const usersMap = new Map();
const LIMIT = 7;
const DIFF = 5000;
client.on('message', async(message) => {
if(message.author.bot) return;
if(usersMap.has(message.author.id)) {
const userData = usersMap.get(message.author.id);
const { lastMessage, timer } = userData;
const difference = message.createdTimestamp - lastMessage.createdTimestamp;
let msgCount = userData.msgCount;
console.log(difference);
if(difference > DIFF) {
clearTimeout(timer);
console.log('Cleared Timeout');
userData.msgCount = 1;
userData.lastMessage = message;
userData.timer = setTimeout(() => {
usersMap.delete(message.author.id);
console.log('Removed from map.')
}, TIME);
usersMap.set(message.author.id, userData)
}
else {
++msgCount;
if(parseInt(msgCount) === LIMIT) {
message.reply("Warning: Spamming in this channel is forbidden.");
message.channel.bulkDelete(LIMIT);
} else {
userData.msgCount = msgCount;
usersMap.set(message.author.id, userData);
}
}
}
else {
let fn = setTimeout(() => {
usersMap.delete(message.author.id);
console.log('Removed from map.')
}, TIME);
usersMap.set(message.author.id, {
msgCount: 1,
lastMessage : message,
timer : fn
});
}
})

Categories

Resources