I am trying to run a AwaitMessage function inside the user's DM's, but its not working. Can anyone help?
Error: TypeError: Cannot read property 'awaitMessages' of undefined
const discord = require('discord.js')
module.exports = {
name: "team",
description: "You can create a new team",
usage: "team",
category: "info",
run: (client, message) => {
const member = message.member;
const user = message.author;
member.send("Do you want continue ? (Yes/No)");
message.dmChannel.awaitMessages(user == message.author, {max: 1 , time: 40000})
.then (collect => {
if (collected.first().content.toLowerCase() == 'yes') {
member.send("Test")
} else {
member.send("Test")
}
});
}
}```
Firstly, I'd recommend using async/await for more than one awaitMessages, as the code can get very nest-y and hard to look at.
Instead of
message.dmChannel.awaitMessages(user == message.author, { max: 1 , time: 40000 })
Use
let collected = await message.dmChannel.awaitMessages(filter, { max: 1, time: 400000 });
If you're trying to only allow the user who triggered the command to pass the filter, just match IDs like this:
let filter = (m) => { m.author.id == message.author.id; }
And lastly, in case a user fails to reply, simply use a try/catch block, like this
let filter = (m) => {
m.author.id == message.author.id;
};
try {
let collected = await message.dmChannel.awaitMessages(filter, {
max: 1,
time: 400000,
});
let response = collected.first().content.toLowerCase();
if (response == "yes") {
member.send("Test");
} else {
member.send("Test");
}
} catch (e) {
return message.reply("Looks like you took too long to reply!");
}
I hope this can serve you.
Related
I have another question concerning my catch cmd. If I wanted to make it so that it was no longer an activable command but instead had a small chance of triggering when anyone speaks ever, how would I go about that? Would I need to put it in my message.js file? I know if I put it there as is it will trigger every time someone uses a command. However, I don't want it limited to someone using a command and I don't want it to happen every time. I've also heard of putting it in a separate json file and linking it back somehow. Any help is appreciated.
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 filter = ({ content }) => whenCaught.some((caught) => caught.toLowerCase() == content.toLowerCase());
const collector = message.channel.createMessageCollector({ max: 1, filter, time: 15000 });
const earnings = Math.floor(Math.random() * (20 - 5 + 1)) + 5;
collector.on('collect', async (m) => {
if(m.content?.toLowerCase() === 'catch') {
const user = m.author;
const userData = await profileModel.findOne({ userID: user.id });
message.channel.send(`${userData.name} caught the ${chosenPrey}! You gained ${earnings} coins.`);
}
await profileModel.findOneAndUpdate(
{
userID: m.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!`);
}
}
message.js file 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);
}
const prefix = '-';
if(!message.content.startsWith(prefix) || message.author.bot) return;
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;
if(!cooldowns.has(command.name)){
cooldowns.set(command.name, new Discord.Collection());
}
const current_time = Date.now();
const time_stamps = cooldowns.get(command.name);
const cooldown_amount = (command.cooldown) * 1000;
if(time_stamps.has(message.author.id)){
const expiration_time = time_stamps.get(message.author.id) + cooldown_amount;
if(current_time < expiration_time){
const time_left = (expiration_time - current_time) / 1000;
return message.reply(`Slow down there! You have to wait ${time_left.toFixed(0)} seconds before you can perform ${command.name} again.`);
}
}
if(command) command.execute(client, message, args, cmd, Discord, profileData);
}
Yes...that can be possible. In your command handler, create and export a variable with a boolean
Make sure to do this in global scope (outside any function)
let canBeActivated = true;
module.exports.getCanBeActivated = function () { return canBeActivated };
module.exports.setCanBeActivated = function(value) { canBeActivated = value };
Then, in your command file, import it and check whether it can be activated
const { getCanBeActivated, setCanBeActivated } = require("path/to/message.js")
module.exports = {
...
execute(...) {
// command wont run
if(!getCanBeActivated()) return
}
You can make some logic to make the command run if canBeActivated is false (like get a random number between 1-100 and if it matches 4 run it).In case you need to change it, just run, setCanBeActivated
I have slash command that collects messages from users. Users should input their nicknames from the game, and then bot should return in embeded 2 teams. I managed to filter and collect nicknames, and call calculation functions. This works if I enter maximum number of nicknames, but now I want to add feature, where I would manually stop collecting by sending message "stop". Now I don't know where to add condition
if(m.content==="stop") {collector.stop();}
const { SlashCommandBuilder } = require("#discordjs/builders");
const { getSummonerProfile } = require("./../functions/summonerData");
const { MessageEmbed } = require("discord.js");
let arrayOfSummoners = [];
let arrayOfNicknames = [];
async function checkIfSummonerExist(m) {
const test = await getSummonerProfile(m.content);
if (test && m.author.bot == false && !arrayOfNicknames.includes(m.content)) {
m.react("👍");
return true;
} else if (test == false && m.author.bot == false) {
m.react("👎");
return false;
}
if (arrayOfNicknames.includes(m.content)) {
m.react("👎");
}
}
module.exports = {
data: new SlashCommandBuilder()
.setName("custom")
.setDescription("Enter the name of the user."),
async execute(interaction) {
await interaction.deferReply();
interaction.editReply("Insert users");
const exampleEmbed = new MessageEmbed()
.setColor("#0099ff")
.setTimestamp();
// `m` is a message object that will be passed through the filter function
const filter = (m) => checkIfSummonerExist(m);
const collector = interaction.channel.createMessageCollector({
filter,
max: 4,
});
if(m.content==="stop")
{
collector.stop();
}
collector.on("collect", (m) => {
arrayOfNicknames.push(m.content);
exampleEmbed.addFields({
name: "Regular field title",
value: m.content, inline:true
});
});
collector.on("end", (collected) => {
interaction.followUp({ embeds: [exampleEmbed] });
});
},
};
If I add this condition in filter fuction (checkIfSummonerExist(m), I get error collector is not defined and I if call it in execute, like in example above, I get error m is not defined
I would put the if statement inside the collector.on callback. Something like this:
collector.on("collect", m => {
if(m.content === "stop") return collector.stop()
// Other code
})
I'm attempting to make a suggestions command, where if the user types =suggest in the server, it would create a prompt in their DM's, asking for different specifications.
However, I am unsure how to obtain user input and use that input in an embed. How would I do this?
For example:
The bot would ask in DM's "What would you like the title to be?", and then the user would respond with their desired title, and it would set that input as the title.
You can use a message collector. I used channel.awaitMessages here:
const prefix = '!';
client.on('message', (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'suggest') {
// send the question
message.channel.send('What would you like the title to be?');
// use a filter to only collect a response from the message author
const filter = (response) => response.author.id === message.author.id;
// only accept a maximum of one message, and error after one minute
const options = { max: 1, time: 60000, errors: ['time'] };
message.channel
.awaitMessages(filter, options)
.then((collected) => {
// the first collected message's content will be the title
const title = collected.first().content;
const embed = new MessageEmbed()
.setTitle(title)
.setDescription('This embed has a custom title');
message.channel.send(embed);
})
.catch((collected) =>
console.log(`After a minute, only collected ${collected.size} messages.`),
);
}
});
I've just noticed that you wanted to send it in a DM. In that case, you can .send() the first message, wait for it to be resolved, so you can add a message collector in the channel using channel.createMessageCollector(). I've added some comments to explain it:
const prefix = '!';
client.on('message', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const MINUTES = 5;
if (command === 'suggest') {
const questions = [
{ answer: null, field: 'title' },
{ answer: null, field: 'description' },
{ answer: null, field: 'author name' },
{ answer: null, field: 'colour' },
];
let current = 0;
// wait for the message to be sent and grab the returned message
// so we can add the message collector
const sent = await message.author.send(
`**Question 1 of ${questions.length}:**\nWhat would you like the ${questions[current].field} be?`,
);
const filter = (response) => response.author.id === message.author.id;
// send in the DM channel where the original question was sent
const collector = sent.channel.createMessageCollector(filter, {
max: questions.length,
time: MINUTES * 60 * 1000,
});
// fires every time a message is collected
collector.on('collect', (message) => {
// add the answer and increase the current index
questions[current++].answer = message.content;
const hasMoreQuestions = current < questions.length;
if (hasMoreQuestions) {
message.author.send(
`**Question ${current + 1} of ${questions.length}:**\nWhat would you like the ${questions[current].field} be?`,
);
}
});
// fires when either times out or when reached the limit
collector.on('end', (collected, reason) => {
if (reason === 'time') {
return message.author.send(
`I'm not saying you're slow but you only answered ${collected.size} questions out of ${questions.length} in ${MINUTES} minutes. I gave up.`,
);
}
const embed = new MessageEmbed()
.setTitle(questions[0].answer)
.setDescription(questions[1].answer)
.setAuthor(questions[2].answer)
.setColor(questions[3].answer);
message.author.send('Here is your embed:');
message.author.send(embed);
// send a message for confirmation
message.author.send('Would you like it to be published? `y[es]/n[o]`');
message.author.dmChannel
.awaitMessages(
// set up a filter to only accept y, yes, n, and no
(m) => ['y', 'yes', 'n', 'no'].includes(m.content.toLowerCase()),
{ max: 1 },
)
.then((coll) => {
let response = coll.first().content.toLowerCase();
if (['y', 'yes'].includes(response)) {
// publish embed, like send in a channel, etc
// then let the member know that you've finished
message.author.send('Great, the embed is published.');
} else {
// nothing else to do really, just let them know what happened
message.author.send('Publishing the embed is cancelled.');
}
})
.catch((coll) => console.log('handle error'));
});
}
});
PS: You can learn more about message collectors on DiscordJS.guide.
I'm encountering an error while making a command for my discord.js bot which says UnhandledPromiseRejectionWarning: ReferenceError: client is not defined even tho i defined client in the main bot file so i'm pretty confused the code for the command i'm making:
let ticketGen = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".split("");
let ticketStr = "";
for(let i = 0; i < 3; i++) {
ticketStr += ticketGen[Math.floor(Math.random() * ticketGen.length)];
}
return ticketStr;
}
const fsn = require("fs-nextra");
const colors = require("colors");
module.exports = {
name: 'order',
description: 'Ordering something',
aliases: ['o'],
execute(message) {
let order = message.content.substring(8);
let customer = message.author.id
fsn.readJSON("./blacklist.json").then((blacklistDB) => {
let entry = blacklistDB[message.guild.id];
// Checks is server is blacklisted or not.
if(entry === undefined) {
// Gets ticket ID.
const ticketID = generateID();
// Sends ticket information to tickets channel.
client.guilds.cache.get("745409671430668389").channels.get("746423099871985755").send({embed: {
color: 0xFFFFFF,
title: message.author.username,
fields: [{
name: "New Order",
value: `${message.author.username} would like to order something.`,
}, {
name: "Order Description",
value: order,
}, {
name: "Order ID",
value: ticketID,
}, {
name: "Guild Infomation",
value: `This order came from ${message.guild} (${message.guild.id}) in ${message.channel} (${message.channel.id}).`,
}, {
name: "Order Status",
value: "Unclaimed",
}],
timestamp: new Date(),
footer: {
text: "Taco Bot"
}
}}).then((m) => {
m = m.id;
//rest of the code
forgive me if it was an stupid error i'm completely new to coding and was watching youtube videos to learn the code for the main bot file:
const fs = require("fs");
const { prefix, token, ownerID } = require('./config.json');
const Discord = require('discord.js');
const client = new Discord.Client();
client.commands = new Discord.Collection();
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
client.commands.set(command.name, command);
}
client.on("ready", () => {
console.log(`ready!.`);
console.log(token);
// Activities
const activities_list = [
`Serving Tacos | .help`,
`Preparing Orders | .help`
];
setInterval(() => {
const index = Math.floor(Math.random() * (activities_list.length - 1) + 1);
client.user.setActivity(activities_list[index]);
}, 10000);
});
//Joined Guild
client.on("guildCreate", (guild) => {
console.log(colors.green(`Joined New Guild, ${guild.name}`));
});
//Left Guild
client.on("guildDelete", (guild) => {
console.log(colors.green(`Left Guild, ${guild.name}`));
});
client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();
const command = client.commands.get(commandName)
|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command) return;
if (command.guildOnly && message.channel.type === 'dm') {
return message.reply('I can\'t execute that command inside DMs!');
}
if (command.args && !args.length) {
let reply = `You didn't provide any arguments, ${message.author}!`;
if (command.usage) {
reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
}
return message.channel.send(reply);
}
try {
command.execute(message, args);
} catch (error) {
console.error(error);
message.reply('there was an error trying to execute that command!');
}
});
process.on("error", () => {
console.log("Oops something happened!");
});
client.login(token);
There is no need to create a new client, and absolutely no need to pass it in as an additional argument in your execute method. As you have seen in the comments, the issue is that while client is defined in your main bot file, it is not defined in your command's file. Variables defined in one file aren't accessible in all other files, unless you specifically export that variable using module.exports.
But luckily, you don't need to export your client or pass it as a parameter; discord.js conveniently has a message.client property on the message object which allows you to access your client easily. All you need to do to fix your code is add a single line to the top of your execute() method in your command file:
module.exports = {
name: 'order',
description: 'Ordering something',
aliases: ['o'],
execute(message) {
const client = message.client; //<- Line added right here
let order = message.content.substring(8);
let customer = message.author.id
fsn.readJSON("./blacklist.json").then((blacklistDB) => {
let entry = blacklistDB[message.guild.id];
// Checks is server is blacklisted or not.
if(entry === undefined) {
// Gets ticket ID.
const ticketID = generateID();
// Sends ticket information to tickets channel.
client.guilds.cache.get("745409671430668389").channels.get("746423099871985755").send({embed: {
color: 0xFFFFFF,
title: message.author.username,
fields: [{
name: "New Order",
value: `${message.author.username} would like to order something.`,
}, {
name: "Order Description",
value: order,
}, {
name: "Order ID",
value: ticketID,
}, {
name: "Guild Infomation",
value: `This order came from ${message.guild} (${message.guild.id}) in ${message.channel} (${message.channel.id}).`,
}, {
name: "Order Status",
value: "Unclaimed",
}],
timestamp: new Date(),
footer: {
text: "Taco Bot"
}
}}).then((m) => {
m = m.id;
//rest of the code
And that's all! Problem solved. That message.client property is amazingly convenient.
Relevant Resources:
https://discord.js.org/#/docs/main/stable/class/Message?scrollTo=client
I will suggest you to add the client in the command.execute() too, because it is easier to use. So you will have:
try {
command.execute(client, message, args);
} catch (error) {
console.error(error);
message.reply('there was an error trying to execute that command!');
}
And in every command file you just simply do this.
execute(client, message, args) {
//code
}
In the command I've posted below, I have the bot react with two emojis to the message that is sent to a certain channel. But for some reason when I specify the message as msg, it says it's not defined, any help?
I tried using both msg and message but for msg it showed an error saying that it isn't defined, but for message, it just reacted to the original message I sent to run the command.
Thanks, Blu.
Code:
const Discord = require("discord.js");
let TicketChannelID = "729912166337216575";
let GuildID = "710634001513185371";
const talkedRecen = new Set();
module.exports.run = async (bot, message, args) => {
let avatar = message.author.avatarURL({
size: 2048
});
const filter = m => m.author.id === message.author.id;
let description = "";
let price = "";
const emojis = ["715383579059945512", "715383579059683349"];
if (talkedRecen.has(message.author.id)) {
message.reply(
"please wait till your two hours are up before you type this again."
);
} else {
let Prompt1 = new Discord.MessageEmbed()
.setTitle("Description")
.setDescription(
"Please specify a description for the asset you are selling below."
)
.setColor("#8c52ff")
.setTimestamp();
let Prompt2 = new Discord.MessageEmbed()
.setTitle("Price")
.setDescription(
"Please specify the price for the asset you are selling below."
)
.setColor("#8c52ff")
.setTimestamp();
message.channel.send("Redirected prompt to your DMs. If you didn't receive a DM from me, check your privacy settings and try again.");
message.author.send(Prompt1).then(p1 => {
let Description = new Discord.MessageCollector(p1.channel, filter, {
max: 1,
time: 60000
});
Description.on("collect", async newMS => {
let collectedMessage = newMS.content.toLowerCase();
if (collectedMessage.length >= 2048) {
collectedMessage.reply(
"The description you set for your asset is too long. Please try running the command again."
);
Description.stop();
return;
}
Description.stop();
description = collectedMessage;
p1.channel
.send(Prompt2)
.then(p2 => {
let Price = new Discord.MessageCollector(p2.channel, filter, {
max: 1,
time: 1200000
});
Price.on("collect", collectedMessage => {
if (collectedMessage.length >= 2048) {
collectedMessage.reply(
"The price you set for your asset is too long. Please try running the command again."
);
Price.stop();
return;
}
Price.stop();
price = collectedMessage.content;
let Prompt3 = new Discord.MessageEmbed()
.setTitle("Do you wish to send this for review?")
.setAuthor(message.author.tag, avatar)
.setColor("#8c52ff")
.addField("Description", description)
.addField("Price", price)
.addField("Contact", `<:discord:715391744090308700> - <#${message.author.id}>`)
.setFooter("Please respond with yes or no.")
.setTimestamp();
message.author.send(Prompt3).then(ex => {
let confirmationListener = new Discord.MessageCollector(
ex.channel,
filter, {
max: 1,
timer: 100000
}
);
confirmationListener.on("collect", collectedMessage => {
confirmationListener.stop();
let Message1 = collectedMessage.content.toLowerCase();
if (Message1 === "yes") {
let sellingembed = new Discord.MessageEmbed()
.setAuthor(message.author.tag, avatar)
.setColor("#8c52ff")
.addField("Description", description)
.addField("Price", price)
.addField("Contact", `<:discord:715391744090308700> - <#${message.author.id}>`)
.setTimestamp();
bot.guilds.cache
.get(GuildID)
.channels.cache.get(TicketChannelID)
.send(sellingembed)
.then(succ => {
collectedMessage.reply(
"Sent selling message for review."
);
msg.react(emojis[0]);
msg.react(emojis[1]);
const filter = (reaction, user) => emojis.includes(reaction.emoji.id) && user.id != bot.user.id;
const options = {
errors: ["time"],
time: 86400000,
max: 1
};
msg.awaitReactions(filter, options)
.then(collected => {
const first = collected.first();
if (emojis.indexOf(first.emoji.id) === 0) {
msg.delete();
let certainChannel = bot.channels.cache.get("715758259713212448");
certainChannel.send(sellingembed);
collectedMessage.reply("your selling message has been approved.");
} else {
msg.delete();
collectedMessage.reply("your selling message has been declined.");
}
})
.catch(err => {
console.log(err)
});
})
.catch(err => {
collectedMessage.reply("Error:\n" + err);
});
}
});
confirmationListener.on("end", (col, res) => {
if (!col.size && res == "time") {
return ex.reply(
"Timed out, try to repond within the given time."
);
}
});
});
});
Price.on("end", (col, res) => {
if (!col && res == "time") {
return message.reply(
"Timed out, try to respond within the given time."
);
}
});
})
.catch(err => {
p1.reply("Error: " + err);
});
Description.on("end", (col, res) => {
if (!col.size && res == "time") {
return p1.reply("Timed out, try to respond within the given time.");
}
});
});
});
talkedRecen.add(message.author.id);
setTimeout(() => {
talkedRecen.delete(message.author.id);
}, 7200000);
}
};
module.exports.help = {
name: "selling"
};
In the following section of your code, msg does not exist and message refers to the original message:
.send(sellingembed)
.then(succ => {
collectedMessage.reply(
"Sent selling message for review."
);
msg.react(emojis[0]);
msg.react(emojis[1]);
The sent message is stored in the succ variable, so if you want to react to the sent message, you need to use succ.react().
You also need to use async and await to ensure that the reactions happen in order. For more information, please read the reactions section of the Discord.js guide.
Here is the modified code:
.send(sellingembed)
.then(async succ => {
collectedMessage.reply(
"Sent selling message for review."
);
await msg.react(emojis[0]);
await msg.react(emojis[1]);