Collecting the first one to respond's userID - javascript

I recently made this command where users have 15 seconds to type 'catch' to win coins. The only issue is that I'm not sure how to make it so that the coins go to the person who typed 'catch' first. Right now it's set up so that the coins always goes to the person who triggered the command. I tried using the discord.js guide for collectors but I kept getting errors. I'm still pretty new at this, anything helps thanks.
const profileModel = require("../models/profileSchema");
module.exports = {
name: "catch",
description: "users must type catch first to catch the animal",
async execute(client, message, msg, args, cmd, Discord, profileData) {
const prey = [
"rabbit",
"rat",
"bird",
];
const caught = [
"catch",
];
const chosenPrey = prey.sort(() => Math.random() - Math.random()).slice(0, 1);
const whenCaught = caught.sort(() => Math.random() - Math.random()).slice(0, 1);
const earnings = Math.floor(Math.random() * (20 - 5 + 1)) + 5;
const filter = ({ content }) => whenCaught.some((caught) => caught.toLowerCase() == content.toLowerCase());
const collector = message.channel.createMessageCollector({ max: 1, filter, time: 15000 });
collector.on('collect', async (m) => {
if(m.content?.toLowerCase() === 'catch') {
message.channel.send(`You caught the ${chosenPrey}! You gained ${earnings} coins.`);
}
await profileModel.findOneAndUpdate(
{
userID: message.author.id,
},
{
$inc: {
coins: earnings,
},
}
);
});
collector.on('end', (collected, reason) => {
if (reason == "time") {
message.channel.send('Too slow');
}
});
message.channel.send(`Look out, a ${chosenPrey}! Type CATCH before it gets away!`);
}
}
The profileSchema just in case
const profileModel = require("../../models/profileSchema");
const cooldowns = new Map();
module.exports = async (Discord, client, message) => {
let profileData;
try {
profileData = await profileModel.findOne({ userID: message.author.id });
if(!profileData){
let profile = await profileModel.create({
name: message.member.user.tag,
userID: message.author.id,
serverID: message.guild.id,
coins: 0,
});
profile.save();
}
} catch (err) {
console.log(err);
}

It looks like your collector is using two different variables for message:
collector.on('collect', async (m) => {
if(m.content?.toLowerCase() === 'catch') {
message.channel.send(`You caught the ${chosenPrey}! You gained ${earnings} coins.`);
}
await profileModel.findOneAndUpdate(
{
userID: message.author.id,
},
{
$inc: {
coins: earnings,
},
}
);
});
You're checking whether the message m (collected by your collector) has the content 'catch', and then finding the userID of the user that checking the author of the message (from your execute() parameters up top, so, the message that triggered this command) when you should be using m.
So, to fix this, you should change userID: message.author.id to userID: m.author.id

Related

How do I make the bot react to its own message and edit the previous sent embed?

I'm making a discord bot in discord.js and here's the problem:
When I react to the message, the bot gives me an error... maybe because I've tried multiple codes...
(please also read the comments)
TypeError: Function.prototype.apply was called on #< Object >, which is a object and not a function
module.exports = {
name: 'emoji',
group: 'misc',
aliases: ['emoticon'],
description: 'mostra ajuda.',
use:'.help <comando>',
async execute(message,args){
try{
const filter = (reaction, user) => reaction.emoji.name === '▶️' && user.id === message.author.id;
let newEmbed = new Discord.MessageEmbed() //I was using this to test the part where the bot edited the embed but I just ended up deleting that to see where the error was coming from.
.setDescription('a')
let ajuda = new Discord.MessageEmbed()
.setColor('#0099ff')
.setAuthor(`Comando por ${message.author.username}`, message.author.displayAvatarURL({dynamic: true}),message.url)
.setTitle(`**Ajuda**`)
.setDescription('**Modo de uso:** .help <comando> \n _Exemplo: .help config_')
.addFields(
{name: '**configuração**', value: 'mostra comandos de.'},
)
.setTimestamp()
.setFooter('[PRD] Corridas todos os direitos reservados.')
await message.channel.send({embed: ajuda})
.then(function (message) {
message.react("▶️")
message.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const collect = collected.first();
if(emojis.first(collect.emoji) === '▶️') {
message.reply('code worked')// HERE SHOULD GO THE CODE TO EDIT THE EMBED INSTEAD.
}
})
.catch(err => {
console.log(err)
})
}).catch(function(){
})
}
catch(error){
console.log(error)
}
}
}
I have tested your code and came up with a solution.
When you call the reaction collector you do:
message.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
And filter is your filter function, however I determined that the filter function is meant to be the first argument in the function, and the rest of the options is the second argument, thus the line should look something like this:
message.awaitReactions(filter, { max: 1, time: 60000, errors: ["time"] })
You got the code to edit the embed right
Essentially Your final code should look something like:
I took some liberties in formating the code and moving a few things around
module.exports = {
name: "emoji",
group: "misc",
aliases: ["emoticon"],
description: "mostra ajuda.",
use: ".help <comando>",
async execute(message, args) {
try {
const filter = (reaction, user) =>
reaction.emoji.name === "▶️" && user.id === message.author.id;
let ajuda = new Discord.MessageEmbed()
.setColor("#0099ff")
.setAuthor(
`Comando por ${message.author.username}`,
message.author.displayAvatarURL({ dynamic: true }),
message.url
)
.setTitle(`**Ajuda**`)
.setDescription(
"**Modo de uso:** .help <comando> \n _Exemplo: .help config_"
)
.addFields({
name: "**config**",
value: "shows config commands",
})
.setTimestamp()
.setFooter("[PRD] Corridas todos os direitos reservados.");
await message.channel
.send({ embed: ajuda })
.then(function (message) {
message.react("▶️");
message
.awaitReactions(filter, {
max: 1,
time: 60000,
errors: ["time"],
})
// When a reaction is collected
.then((collected) => {
let newEmbed =
new Discord.MessageEmbed().setDescription("a");
// Edit the embed
message.edit(newEmbed);
})
.catch((err) => {
console.log(err);
});
})
.catch(function () {
//Something
});
} catch (error) {
console.log(error);
}
},
};
const filter = (reaction, user) => reaction.emoji.name === "▶️" && user.id === message.author.id;
const ajuda = new Discord.MessageEmbed()
.setColor('#0099ff')
.setDescription('...');
const sentEmbed = await message.channel.send({ embed: ajuda });
await sentEmbed.react("▶️");
const emojiCollector = await msg.createReactionCollector(Filter, {
time: 60000,
max: 1 //can be ignored for unlimited amount of event-firing.
});
emojiCollector.on("collect", async (r) => {
if (r.emoji.name === "▶️") {
console.log("If statement fired.");
//do something
}
});

Discord.js: how can I make paticular permissons for each reaction?

I am coding a !ticket command and cannot handle allowing members without any permissions to react ⛔.
Code
module.exports = {
name: "ticket",
slash: true,
aliases: [],
permissions: [],
description: "open a ticket!",
async execute(client, message, args) {
let chanel = message.guild.channels.cache.find(c => c.name === `ticket-${(message.author.username).toLowerCase()}`);
if (chanel) return message.channel.send('You already have a ticket open.');
const channel = await message.guild.channels.create(`ticket-${message.author.username}`)
channel.setParent("837065612546539531");
channel.updateOverwrite(message.guild.id, {
SEND_MESSAGE: false,
VIEW_CHANNEL: false,
});
channel.updateOverwrite(message.author, {
SEND_MESSAGE: true,
VIEW_CHANNEL: true,
});
const reactionMessage = await channel.send(`${message.author}, welcome to your ticket!\nHere you can:\n: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.\n\nMake sure to be patient, support will be with you shortly.\n<#&837064899322052628>`)
try {
await reactionMessage.react("🔒");
await reactionMessage.react("⛔");
} catch (err) {
channel.send("Error sending emojis!");
throw err;
}
const collector = reactionMessage.createReactionCollector(
(reaction, user) => message.guild.members.cache.find((member) => member.id === user.id).hasPermission("ADMINISTRATOR"),
{ dispose: true }
);
collector.on("collect", (reaction, user) => {
switch (reaction.emoji.name) {
case "🔒":
channel.updateOverwrite(message.author, { SEND_MESSAGES: false });
break;
case "⛔":
channel.send("Deleting this ticket in 5 seconds...");
setTimeout(() => channel.delete(), 5000);
break;
}
});
message.channel
.send(`We will be right with you! ${channel}`)
.then((msg) => {
setTimeout(() => msg.delete(), 7000);
setTimeout(() => message.delete(), 3000);
})
.catch((err) => {
throw err;
});
},
};
It is related to the following part of the code.
const collector = reactionMessage.createReactionCollector(
(reaction, user) => message.guild.members.cache.find((member) => member.id === user.id).hasPermission("ADMINISTRATOR"),
{ dispose: true }
);
I want it to allow lock the ticket for administrators, and allow to close for everyone.
Not sure if I understand you correctly, but it seems you have two reactions and only want admins to use the 🔒, and both admins and the original author to use the ⛔.
Your current code only collects reactions from members who have ADMINISTRATOR permissions. You should change the filter to also collect reactions from the member who created the ticket.
The following filter does exactly that.
const filter = (reaction, user) => {
const isOriginalAuthor = message.author.id === user.id;
const isAdmin = message.guild.members.cache
.find((member) => member.id === user.id)
.hasPermission('ADMINISTRATOR');
return isOriginalAuthor || isAdmin;
}
There are other errors in your code, like there is no SEND_MESSAGE flag, only SEND_MESSAGES. You should also use more try-catch blocks to catch any errors.
It's also a good idea to explicitly allow the bot to send messages in the newly created channel. I use overwritePermissions instead of updateOverwrite. It allows you to use an array of overwrites, so you can update it with a single method.
To solve the issue with the lock emoji... I check the permissions of the member who reacted with a 🔒, and if it has no ADMINISTRATOR, I simply delete their reaction using reaction.users.remove(user).
Check out the working code below:
module.exports = {
name: 'ticket',
slash: true,
aliases: [],
permissions: [],
description: 'open a ticket!',
async execute(client, message, args) {
const username = message.author.username.toLowerCase();
const parentChannel = '837065612546539531';
const ticketChannel = message.guild.channels.cache.find((ch) => ch.name === `ticket-${username}`);
if (ticketChannel)
return message.channel.send(`You already have a ticket open: ${ticketChannel}`);
let channel = null;
try {
channel = await message.guild.channels.create(`ticket-${username}`);
await channel.setParent(parentChannel);
await channel.overwritePermissions([
// disable access to everyone
{
id: message.guild.id,
deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
},
// allow access for the one opening the ticket
{
id: message.author.id,
allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
},
// make sure the bot can also send messages
{
id: client.user.id,
allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
},
]);
} catch (error) {
console.log(error);
return message.channel.send('⚠️ Error creating ticket channel!');
}
let reactionMessage = null;
try {
reactionMessage = await channel.send(
`${message.author}, welcome to your ticket!\nHere you can:\n: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.\n\nMake sure to be patient, support will be with you shortly.\n<#&837064899322052628>`,
);
} 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('ADMINISTRATOR');
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('ADMINISTRATOR');
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;
}
});
try {
const msg = await message.channel.send(`We will be right with you! ${channel}`);
setTimeout(() => msg.delete(), 7000);
setTimeout(() => message.delete(), 3000);
} catch (error) {
console.log(error);
}
},
};

Mongoose Only Updating Once?

So I'm making a setnote command so people can keep track of how much they have donated. However, It will only add it when I add them to the database and not after. I don't know why. So it just isn't updating or sending the message that it's even updated.
const { MessageEmbed } = require('discord.js')
const notesModel = require('../models/notesSchema')
module.exports = {
name: 'setnote',
aliases: ['sn'],
description: 'Add a note to a user.',
async execute(message, args, client, cmd, Discord, notesData) {
const mentionedMember = message.mentions.members.first() || message.guild.members.cache.get(args[0])
if (!args[0]) return message.channel.send('Please mention someone to add note to.')
if (!args[1]) return message.channel.send('Please state an amount to add to the user.')
const amountToAdd = args[1]
if (isNaN(args[1])) return message.channel.send('You have to add a number when setting note.')
let userData = await notesModel.findOne({
userID: mentionedMember.id,
serverID: message.guild.id,
})
if (!userData) {
userData = await notesModel.create({
userID: mentionedMember.id,
serverID: message.guild.id,
notes: 0
})
const response = await notesModel.findOneAndUpdate({
serverID: message.guild.id,
userID: mentionedMember.id
}, {
$inc: {
notes: +amountToAdd
}
})
userData = await notesModel.findOne({serverID: mentionedMember.guild.id, userID: mentionedMember.id});
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
const addedNote = new MessageEmbed()
.setTitle(`<a:red_check:845104782833352704> Successfully Added Note <a:red_check:845104782833352704>`)
.setDescription(`${mentionedMember.user.tag} has now donated \`${numberWithCommas(userData.notes)}\``)
.setColor('GREEN')
message.channel.send(addedNote)
}
}
}

How can i count the reactions in discord.js and after that display it (slappey version)

I'm trying to display who win the poll but i run into a problem. While I want to get the number of the reactions with
.addField("🔴:", `${results.get("🔴").count}`)
My console says that the count is undefined. I've tried to search it but I didn't find anything and I tried so many ways but nothing.
The code:
const BaseCommand = require('../../utils/structures/BaseCommand');
const Discord = require("discord.js")
module.exports = class HelpCommand extends BaseCommand {
constructor() {
super('vote', 'moderation', []);
}
async run(client, message, args) {
const filter = m => m.author.id == message.author.id;
let embed = new Discord.MessageEmbed()
.setFooter(`${message.author.tag} started the poll`)
.setTimestamp();
message.channel.send('what the question is?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.setTitle(msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
message.channel.send('first option?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.addField(`[🔴] the first option:`, msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
message.channel.send('second option?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.addField(`[🔵] the second option`, msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
try {
await message.channel.bulkDelete(7)
.then(message.channel.send(embed).then(sentMessage => sentMessage.react('🔴')).then(reaction => reaction.message.react('🔵')));
} catch (err) {
console.log(err);
}
const filters = (reaction) => reaction.emoji.name === "🔴" || reaction.emoji.name === "🔵";
const results = await message.awaitReactions(filters, { time: 15000 })
let resultsEmbed = new Discord.MessageEmbed()
.setTitle(`the poll result`)
.setDescription(`the result of the poll: ${args.join(" ")}`)
.addField("🔴:", `${results.get("🔴").count}`)
.addField("🔵:", `${results.get("🔵").count //if i dont type here the .count then i've got this embed but after the "🔵": says'undefined' }`)
.setColor("#84daf8")
.setTimestamp()
message.channel.send(resultsEmbed);
}
}
A szavazás eredménye = The poll result in my language. I see this when i dont write the .count there: .addField("🔴:", `${results.get("🔴").count}`)
and i see this when i write .count
The problem was that the bot was trying to retrieve the reactions of a deleted message I believe. In order to fix this, you'll have to put your resultsEmbed code inside of your chained then methods.
Code:
try {
await message.channel.bulkDelete(7)
.then(message.channel.send(embed)
.then(sentMessage => sentMessage.react('🔴'))
.then(reaction => reaction.message.react('🔵'))
.then(reaction => {
const filters = (reaction) => reaction.emoji.name === "🔴" || reaction.emoji.name === "🔵";
reaction.message.awaitReactions(filters, { time: 15000 }).then(collected => {
console.log(collected);
if (collected.get("🔴") !== undefined && collected.get("🔵") !== undefined) {
let optionOne = collected.get("🔴").count;
let optionTwo = collected.get("🔵").count;
let resultsEmbed = new Discord.MessageEmbed()
.setTitle("the poll result")
.setDescription(`the result of the poll: ${args.join(" ")}`)
.addField("🔴:", `${optionOne}`)
.addField("🔵:", `${optionTwo}`)
.setColor('#')
.setTimestamp()
message.channel.send(resultsEmbed);
} else {
//there were no votes for one of the options, thus it will not be able to get property
message.channel.send("There were no votes for one of the options.");
}
})
})
);
} catch (err) {
console.log(err);
}

findOneAndUpdate is not a function of mongoose

I know this question has been answered before but I can't seem to implement the changes into what im working with. I'm trying to create a daily command that rewards a user for doing s!daily. I get the error,
TypeError: profileData.findOneAndUpdate is not a function
at Object.execute (C:\Users--\Desktop\DiscBot\commands\daily.js:35:43)
at module.exports (C:\Users--\Desktop\DiscBot\events\client\message.js:34:13)
daily.js, one having error at line 35 for findOneAndUpdate is not a function
const Schema = require('../models/profileSchema')
//cache users that claim daily rewards
let claimedCache = []
const clearCache = () => {
claimedCache = []
setTimeout(clearCache, 1000 * 60 * 10)
}
clearCache()
//message to make it easier later
const alreadyClaimed = 'You have already claimed your daily rewards'
module.exports = {
name: "daily",
aliases: ["day", "d"],
permissions: [],
description: "Claim your daily rewards!",
async execute(message, args, cmd, client, Discord, profileData) {
const { serverID, member } = message
const { id } = member
//If user is in cache return message
if (claimedCache.includes(id)) {
console.log('Returning from cache')
message.reply(alreadyClaimed)
return
}
//Put everything in object for later
const obj = {
guildId: serverID,
userId: id,
}
//Results is an update that either updates if is user is not in array and doesn't if they are, but it doesn't know what findOneAndUpdate is (thought it was just a mongo/mongoose function??)
try {
const results = await profileData.findOneAndUpdate(obj)
console.log('RESULTS:', results)
if (results) {
const then = new Date(results.updatedAt).getTime()
const now = new Date().getTime()
const diffTime = Math.abs(now - then)
const diffDays = Math.round(diffTime / (1000 * 60 * 60 * 24))
if (diffDays <= 1) {
claimedCache.push(id)
message.reply(alreadyClaimed)
return
}
}
//after the update increase coins by 50 and send claimed message
await profileRewardsSchema.findOneAndUpdate(obj, obj, {
upsert: true,
})
claimedCache.push(id)
const amount = 50;
await profileModel.findOneAndUpdate(
{
userID: id,
},
{
$inc: {
coins: amount,
},
}
);
message.reply('You have claimed your daily rewards!')
}catch (err) {
console.log(err);
}
}
}
message.js, heres where I make profileModel a thing using mongoose to pass it into my commands
const profileModel = require("../../models/profileSchema");
const config = require('../../config.json');
module.exports = async (Discord, client, message) => {
//command handler start
const prefix = 's!';
if (!message.content.startsWith(prefix) || message.author.bot) return;
//database junk
let profileData;
try {
profileData = await profileModel.findOne({ userID: message.author.id });
if (!profileData) {
let profile = await profileModel.create({
userID: message.author.id,
serverID: message.guild.id,
coins: 10,
bank: 0,
});
profile.save();
}
} catch (err) {
console.log("Error creating new database profile");
}
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) || client.commands.find(a => a.aliases && a.aliases.includes(cmd));
if(!command) return message.channel.send(":x: This is not a valid command");
try {
command.execute(message, args, cmd, client, Discord, profileData);
} catch (err) {
message.reply('There was an error executing that command!');
}
};
profileSchema.js, Where profile is made into mongo database
const mongoose = require("mongoose");
const profileSchema = new mongoose.Schema({
userID: { type: String, require: true, unique: true },
serverID: { type: String, require: true },
coins: { type: Number, default: 10 },
bank: { type: Number },
},
{
timestamps: true,
}
)
const model = mongoose.model("ProfileModels", profileSchema);
module.exports = model;
main.js, where mongoose is connected, then passed on
mongoose.connect(process.env.MONGODB_SRV, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
})
You are trying to call findOneAndUpdate on the document, which you passed to execute function at message.js. Check the example of how to use findOneAndUpdate
https://mongoosejs.com/docs/tutorials/findoneandupdate.html
Most of the time this error happen when you call findOneAndUpdate in mongoose when you call it on the instance of the model NOT the actual model
so instead of this
var NewUser = new User(req.user);
NewUser.findOneAndUpdate...
do this
var NewUser = new User(req.user);
User.findOneAndUpdate(
{ name: NewUser.name },
{ name: NewUser.name},
{ upsert: true });

Categories

Resources