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]);
Related
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 am making a ticket bot and it sends a message upon startup, but once the message has been sent, nothing happens when I react to it until I've done something like send a message in the discord server. I am using Discord.JS.
I want to know if there is any possible way to cache the message or something so that I do not have to interact with the server for the reaction event to pick up my reaction.
My Startup Code:
client.on('ready', () => {
console.log(`[AUTH] Authenticated with discord!`);
client.guilds.cache.forEach(async function(dguild) {
let channel1 = dguild.channels.cache.find(channel => channel.name === 'new-ticket')
if(!channel1) {
await dguild.createChannel("actions", { type: 'text' })
channel1 = dguild.channels.cache.find(channel => channel.name === 'new-ticket')
}
const fetched1 = await channel1.messages.fetch({ limit: 100 });
channel1.bulkDelete(fetched1);
let departments1 = "";
departments(deps => deps.forEach(dep => departments1 += '``'+dep.reactionEmoji +' '+ dep.name + '`` :: ' + dep.description + '\n\n'));
let embed1 = new Discord.MessageEmbed()
.setTitle(nte.title)
.setColor(nte.color)
.addField("\u200B", nte.header)
.addField("Departments: \n", departments1)
.addField("\u200B", nte.footer);
channel1.send(embed1).then(async m => {
await departments(deps => deps.forEach(dep => m.react(dep.reactionEmoji)));
console.log(m.id +":"+channel1.id);
dguild.channels.cache.get(channel1.id).message.cache.get(m.id);
})
});
});
My Reaction Event:
client.on('messageReactionAdd', async (reaction, user) => {
if(user.id == client.user.id) return;
const userReactions = reaction.message.reactions.cache.filter(reaction => reaction.users.cache.has(user.id));
try {
for (const reaction of userReactions.values()) {
await reaction.users.remove(user.id);
}
} catch (error) {
console.error('Failed to remove reactions.');
}
departments(deps => deps.forEach(dep => {
if (reaction.emoji.name == dep.reactionEmoji) {
try {
ticket.create(user.id, dep.id, reaction.message);
console.log(dep.name + ": Ticket Opened");
} catch {
console.log('Failed to generate ticket.');
}
}
}))
});
Cheers.
Let's just get this started off with.
I've been looking around Google trying to find a guide on how to take images as arguments and then sending that same image with the message the user provided.
I'm making an announcement command.
Right now, my command only takes text as input, not files/images.
Here's my announce command:
module.exports = {
name: "afv!announce",
description: "announce something",
execute(msg, args, bot) {
if (msg.member.roles.cache.find((r) => r.name === "Bot Perms")) {
const prevmsg = msg;
const text = args.join().replace(/,/g, " ");
msg
.reply(
"Would you like to do `#here` :shushing_face: or `#everyone` :loudspeaker:?\nIf you would like to ping something else, react with :person_shrugging:. (you will have to ping it yourself, sorry)\n*react with :x: to cancel*"
)
.then((msg) => {
const areusure = msg;
msg
.react("🤫")
.then(() => msg.react("📢"))
.then(() => msg.react("🤷"))
.then(() => msg.react("❌"));
const filter = (reaction, user) => {
return (
["🤫", "📢", "🤷", "❌"].includes(reaction.emoji.name) &&
user.id === prevmsg.author.id
);
};
msg
.awaitReactions(filter, { max: 1, time: 60000, errors: ["time"] })
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === "🤫") {
areusure.delete();
prevmsg
.reply("<a:AFVloading:748218375909539923> Give me a sec...")
.then((msg) => {
bot.channels.cache
.get("696135322240548874")
.send("#here\n\n" + text);
msg.edit("<a:AFVdone:748218438551601233> Done!");
});
} else if (reaction.emoji.name === "📢") {
areusure.delete();
prevmsg
.reply("<a:AFVloading:748218375909539923> Give me a sec...")
.then((msg) => {
bot.channels.cache
.get("696135322240548874")
.send("#everyone\n\n" + text);
msg.edit("<a:AFVdone:748218438551601233> Done!");
});
} else if (reaction.emoji.name === "🤷") {
areusure.delete();
prevmsg
.reply("<a:AFVloading:748218375909539923> Give me a sec...")
.then((msg) => {
bot.channels.cache
.get("696135322240548874")
.send(
"Important: https://afv.page.link/announcement\n\n" +
text
);
msg.edit("<a:AFVdone:748218438551601233> Done!");
});
} else if (reaction.emoji.name === "❌") {
areusure.delete();
prevmsg.reply("Cancelled.");
}
})
.catch((collected) => {
msg.delete();
prevmsg.reply("you didn't react with any of the emojis above.");
});
});
}
},
};
Message has a property called attachments, which contains all of the attachments in the message. (A image uploaded by the user is counted as an attachment, however, a URL to an image, is not.)
Here's an example:
client.on('message', (message) => {
if (message.author.bot) return false;
if (message.attachments.size == 0)
return message.channel.send('No attachments in this message.');
const AnnouncementChannel = new Discord.TextChannel(); // This shall be announcement channel / the channel you want to send the embed to.
const Embed = new Discord.MessageEmbed();
Embed.setTitle('Hey!');
Embed.setDescription('This is an announcement.');
Embed.setImage(message.attachments.first().url);
AnnouncementChannel.send(Embed);
});
Avatar
To use images you can use this function :
message.author.displayAvatarURL(
{ dynamic: true } /* In case the user avatar is animated we make it dynamic*/
);
Then it will return a link you can use for an embed thumbnail or image. If you want to use it in an embed
let link = message.author.displayAvatarURL({ dynamic: true });
const embed = new Discord.MessageEmbed().setThumbnail(link);
Use Image Links
If you want to use an image link you'll have to transform it into a discord attachement.
const args = message.content.split(' ').slice(1);
const attach = new Discord.Attachement(args.join(' '), 'image_name.png');
message.channel.send(attach);
Hope I helped you. If not you can still search in the discord.js guide ^^
Not sure where the image link is
If you don't really know where the image link is in the message content you can separate it (you already did with arguments) and use a forEach function :
const args = message.content.split(' ').slice(1);
// a function to see if it's an url
function isvalidurl(string) {
try {
const a = new URL(string);
} catch (err) {
return false;
}
return true;
}
// check the function for each argument
args.forEach((a) => {
if (isvalidurl(a)) link = a;
});
if (link) {
// code
} else {
// code
}
How do I make it so that when someone reacts with the first emoji in this command, the bot deletes the message and sends it to another channel?
Current Code:
const Discord = require("discord.js");
module.exports.run = async (bot, message, args) => {
if (!message.member.hasPermission("MANAGE_MESSAGES"))
return message.channel.send("You are not allowed to run this command.");
let botmessage = args.join(" ");
let pollchannel = bot.channels.cache.get("716348362219323443");
let avatar = message.author.avatarURL({ size: 2048 });
let helpembed = new Discord.MessageEmbed()
.setAuthor(message.author.tag, avatar)
.setColor("#8c52ff")
.setDescription(botmessage);
pollchannel.send(helpembed).then(async msg => {
await msg.react("715383579059945512");
await msg.react("715383579059683349");
});
};
module.exports.help = {
name: "poll"
};
You can use awaitReactions, createReactionCollector or messageReactionAdd event, I think awaitReactions is the best option here since the other two are for more global purposes,
const emojis = ["715383579059945512", "715383579059683349"];
pollchannel.send(helpembed).then(async msg => {
await msg.react(emojis[0]);
await msg.react(emojis[1]);
//generic filter customize to your own wants
const filter = (reaction, user) => emojis.includes(reaction.emoji.id) && user.id === message.author.id;
const options = { errors: ["time"], time: 5000, max: 1 };
msg.awaitReactions(filter, options)
.then(collected => {
const first = collected.first();
if(emojis.indexOf(first.emoji.id) === 0) {
msg.delete();
// certainChannel = <TextChannel>
certainChannel.send(helpembed);
} else {
//case you wanted to do something if they reacted with the second one
}
})
.catch(err => {
//time up, no reactions
});
});
So i think i quite forgot some .then's beause the bot sends the B emoji message instanntly without a reaction from the user and even when i would provide a "suggestion" then it wouldnt send it to the specific channel, but idk where i have to put the missing .then's. Can someone help me please? I tried to figure it out myself and tested some but it didn't make anything better.
execute(message, client, args) {
const Discord = require('discord.js');
let Embed = new Discord.MessageEmbed()
.setColor('0x0099ff')
.setDescription(`Suggestion categories`)
.addField(`For what you want to suggest something?`, `\nA: I want to suggest something for the Website/Servers/Discord Server\nB: I want to suggest something for the CloudX Bot \n\nPlease react to this message with A or B`)
message.channel.send(Embed).then(function (message) {
message.react("🇦").then(() => {
message.react("🇧")
const filter = (reaction, user) => {
return ['🇦', '🇧'].includes(reaction.emoji.name) && user.id;
}
message.awaitReactions(filter, { max: 1 })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '🇦') {
const filter = m => m.author.id === message.author.id;
message.channel.send(`Please provide a suggestion for the Website/Servers/Discord Server or cancel this command with "cancel"!`).then(() => {
message.channel.awaitMessages(filter, { max: 1, })
.then(async (collected) => {
if (collected.first().content.toLowerCase() === 'cancel') {
message.reply("Your suggestion has been cancelled.")
}
else {
let embed1 = new Discord.MessageEmbed()
.setColor('0x0099ff')
.setAuthor(message.author.tag)
.addField(`New Suggestion:`, `${collected.first().content}`)
.setFooter(client.user.username, "attachment://CloudX.png")
.setTimestamp();
const channel = await client.channels.fetch("705781201469964308").then(() => {
channel.send({embed: embed1, files: [{
attachment:'CloudX.png',
name:'CloudX.png'
}]})
message.channel.send(`Your suggestion has been filled to the staff team. Thank you!`)
})
}
})
})
}
if (reaction.emoji.name === '🇧') {
const filter = m => m.author.id === message.author.id;
message.channel.send(`Please provide a suggestion for the CloudX Bot or cancel this command with "cancel"!`).then(() => {
message.channel.awaitMessages(filter, { max: 1, })
.then(async (collected) => {
if (collected.first().content.toLowerCase() === 'cancel') {
message.reply("Your suggestion has been cancelled.")
}
else {
let embed2 = new Discord.MessageEmbed()
.setColor('0x0099ff')
.setAuthor(message.author.tag)
.addField(`New Suggestion:`, `${collected.first().content}`)
.setFooter(client.user.username, "attachment://CloudX.png")
.setTimestamp();
const channel = await client.channels.fetch("702825446248808519").then(() => {
channel.send({embed: embed2, files: [{
attachment:'CloudX.png',
name:'CloudX.png'
}]})
message.channel.send(`Your suggestion has been filled to the staff team. Thank you!`)
})
}
})
})
}
})
})
})
},
I would suggest learning await/async functions.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
This will clean up your code and keep things steady without five thousand .then()
async execute(message, client, args) {
const { MessageEmbed } = require('discord.js');
const embed = new MessageEmbed()
.setColor('#0099ff')
.setDescription(`Suggestion categories`)
.addField(`For what you want to suggest something?`, `\nA: I want to suggest something for the Website/Servers/Discord Server\nB: I want to suggest something for the CloudX Bot \n\nPlease react to this message with A or B`)
const question = message.channel.send(embed)
await question.react("🇦")
await question.react("🇧")
const filter = (reaction, user) => {
return ['🇦', '🇧'].includes(reaction.emoji.name) && user.id;
}
This is just part of it but you should be able to get the gist...