I am back again with a question :). I am building my own ticket function, and I just started but if I create a channel for a ticket, its only saying ticket-(Discord account ID) And thats also the case by the embed. Anyone who can look at it?
const discord = require("discord.js");
const { MessageEmbed, Collection, Permissions} = require('discord.js');
const { execute } = require("./ticket");
module.exports = {
name: 'create',
description: 'create your own ticket.',
execute(message, client, args){
if(message.guild.channels.cache.find(channel => channel.name === "Ticket from <#" + message.author + ">")) {
message.reply(`${message.member.user.toString()} **You have successfully created a ticket, Please click on ${channel} to view your ticket**`).then(m => m.delete({ timeout: 14000 }).catch(e => {}));
if(message.guild.channels.cache.find(channel => channel.name === `ticket-${message.author.id}`)) {
return message.reply('<a:no:784463793366761532> **You already have a ticket, please close your exsisting ticket first before opening a new one**');
}
message.delete();
message.guild.channels.create(`Ticket ${message.author}`, {
permissionOverwrites: [
{
id: message.author.id,
allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
},
{
id: message.guild.roles.everyone,
deny: ['VIEW_CHANNEL'],
},
],
type: 'text',
}).then(async channel => {
const embed = new MessageEmbed()
.setTitle("<#" + message.author + "> Ticket")
.setDescription(`**${message.author}, Welcome to your channel! Support will be arriving soon**\n**While you wait please tell us what your problem is**\n**If you want to close the ticket please type .close\`**`)
.setColor("BLUE")
channel.send({ embeds: [embed] })
});
}
}
}
I cleaned up the code a fair bit, less is more. Text channels do not have spaces in them so I replaced them with what Discord uses, hypens. The below code will check if a channel already exists and create one if it doesn't.
const {
MessageEmbed,
} = require('discord.js');
module.exports = {
name: 'create',
description: 'create your own ticket.',
async execute(message, client, args) {
const channelName = `ticket-${message.author.username}`
const existing = message.guild.channels.cache.find(channel => channel.name === channelName.toLowerCase());
if (existing) {
return message.reply({
content: `<a:no:784463793366761532> **You already have a ticket, please close your exsisting ticket first before opening a new one**\n${existing}.`,
}).then((m) => {
setTimeout(() => {
m.delete();
}, 14000);
})
}
message.delete();
message.guild.channels.create(channelName, {
type: 'GUILD_TEXT',
permissionOverwrites: [{
id: message.guild.id,
deny: ['VIEW_CHANNEL'],
}, {
id: message.author.id,
allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
}],
}).then(async channel => {
const embed = new MessageEmbed()
.setColor("BLUE")
.setTitle(`${message.author.username} Ticket`)
.setDescription(`**${message.author}, Welcome to your channel! Support will be arriving soon**\n**While you wait please tell us what your problem is**\n**If you want to close the ticket please type .close\`**`)
channel.send({
embeds: [embed]
})
});
}
}
Related
I have been getting an error as mentioned in the title. Whenever I use that command, the bot creates a channel that brings up a select menu, through which the user can "teleport" to another channel while deleting the newly created channel in the process. This code successfully works twice, after which it gives the error. What should be done to fix the error so that the user can use the command as many times as they'd like? I'll work on this code further once the solution is found, but until then, I'm really stumped here. (Questions shall be answered upon questioning; apologies for the messy coding)
module.exports.run = async (client, msg, args) => {
const guild = client.guilds.cache.get('855845132879921214')
const channel = guild.channels.cache.get('959851265456734319')
const newChannel = await msg.guild.channels.create(`teleporter`)
await newChannel.permissionOverwrites.edit(msg.author.id, {
SEND_MESSAGES: false,
VIEW_CHANNEL: true,
})
const {MessageActionRow, MessageSelectMenu, MessageEmbed} = require('discord.js')
const embed = new MessageEmbed()
.setTitle(`Teleporter!`)
.setDescription("Through this interaction, you can now teleport to the main channel of the desired category!")
const row = new MessageActionRow()
.addComponents(
new MessageSelectMenu()
.setCustomId('teleport')
.setPlaceholder('Choose a channel')
.addOptions([
{
label: 'Rules',
description: "Click to check the rules",
value: 'rules',
},
{
label: 'General',
description: "Click to go to the main chat",
value: 'general',
},
{
label: 'Media',
description: "Click to go to media channel",
value: 'media',
},
{
label: 'Bots',
description: "Click to go to the bots channel",
value: 'bots',
}
]),
)
await newChannel.send({content: `<#${msg.author.id}>`,embeds: [embed], components: [row]})
const wait = require('util').promisify
client.on('interactionCreate', async interaction => {
const member = await interaction.guild.members.fetch({
user: interaction.user.id,
force: true
})
if(!interaction.isSelectMenu()) {
interaction.deferUpdate()}
else if (interaction.values == 'general'){
msg.member.roles.add('958421069650337822')
msg.member.roles.remove('943159431800172584')
let tele = msg.guild.channels.cache.find(channel => channel.name == 'teleporter')
tele.delete()
msg.member.roles.add('943159431800172584')
msg.member.roles.remove('958421069650337822')
}
}
)
}
Don't cache.find and delete, do it like;
const newChannel = await client.channels.fetch("id")
newChannel.delete()
This code should be separated with the first section as your command and the second part as a separate listener, so I have coded as such.
const {
MessageActionRow,
MessageSelectMenu,
MessageEmbed,
} = require('discord.js');
module.exports.run = async (client, msg, args) => {
const guild = client.guilds.cache.get('855845132879921214');
const channel = guild.channels.cache.get('959851265456734319');
const newChannel = await msg.guild.channels.create(`teleporter-${msg.author.username}`, {
permissionOverwrites: [{
id: guild.id,
deny: ["VIEW_CHANNEL"],
}, {
id: msg.author,
deny: ["SEND_MESSAGES"],
allow: ["VIEW_CHANNEL"],
}],
});
// In the event that more than one person uses this command at once, you will need to be able to tell the diffrence when you look up the channel later. So I added the username to the channel name.
const embed = new MessageEmbed()
.setTitle(`Teleporter!`)
.setDescription("Through this interaction, you can now teleport to the main channel of the desired category!");
const row = new MessageActionRow()
.addComponents(
new MessageSelectMenu()
.setCustomId('teleport')
.setPlaceholder('Choose a channel')
.addOptions([{
label: 'Rules',
description: "Click to check the rules",
value: 'rules',
}, {
label: 'General',
description: "Click to go to the main chat",
value: 'general',
}, {
label: 'Media',
description: "Click to go to media channel",
value: 'media',
}, {
label: 'Bots',
description: "Click to go to the bots channel",
value: 'bots',
}]),
);
await newChannel.send({
content: `${msg.author}`,
embeds: [embed],
components: [row],
});
};
This section would go either in the main bot.js file, or if you have your events in seperate files, it would go in the interactionCreate file (may need to be changed a bit if you don't have one, let me know)
const wait = require('util').promisify;
client.on('interactionCreate', async interaction => {
const member = interaction.member;
const guild = interaction.guild;
if (interaction.isSelectMenu()) {
const menuName = interaction.customId;
interaction.deferUpdate();
if (menuName === 'teleport') {
const tele = guild.channels.cache.find(channel => channel.name == `teleporter-${member.user.username}`);
// lookup the channel using the previously mentioned channel name setup
const choice = interaction.value;
if (choice === 'general') {
member.roles.add('958421069650337822');
member.roles.remove('943159431800172584');
} else if (choice === 'rules') {
member.roles.add('roleID');
member.roles.remove('roleID');
} else if (choice === 'media') {
member.roles.add('roleID');
member.roles.remove('roleID');
} else if (choice === 'bots') {
member.roles.add('roleID');
member.roles.remove('roleID');
}
tele.delete();
}
}
});
When a person sends my command, a channel is created that only they have access to. Also, when creating a channel, a message is sent with the "accept" button, when another person clicks on the button, his rights in the created channel should be added. I can add rights, but when more than one message with a button arrives in a special channel, the person who clicked the button is added to all created channels
An example of how it works
let myreportChannel = ''
await interaction.guild.channels.create(channelNameMy, {
type: 'text', parent: `${categoryTiket}`, permissionOverwrites: [
{
id: `${permUser}`, // permUser - who sent the command
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY', 'ATTACH_FILES']
},
{
id: `${evryOneRolle}`,
deny: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY']
},
]
})
//Prvivate embed
.then(async reportChannel => {
const exampleEmbed = new MessageEmbed()
.setDescription(`Reported: <#${tagBan.id}>\nReason: ${reason}\ntiket: <#${reportChannel.id}>`)
.setColor("#2F3136")
.setImage(`${settings.reportgif}`)
myreportChannel = reportChannel.id // save new channel id
await interaction.reply({embeds: [exampleEmbed], ephemeral: true})
//Report embed
const reportEmbed = new MessageEmbed()
.setDescription(`Intruder: ${tagBan}\nReason: ${reason}`)
.setColor("#2F3136")
.setImage(`${settings.reportgif}`)
await client.channels.cache.get(`${reportChannel.id}`).send({
embeds: [reportEmbed]
})
})
client.on('interactionCreate', async interaction => {
if (interaction.isButton()) {
if (interaction.customId.includes(`acceptB`)) {
const editEmbRep = new MessageEmbed()
.setDescription(`Author: <#${interaction.user.id}>\nIntruder: <#${tagBan.id}>\nStatus: ${dmStatusAc}\nTiket: <#${myreportChannel}>`)
.setColor("#2F3136")
.setImage(`${settings.reportgif}`)
interaction.message.edit({
content: 'updated text',
embeds: [editEmbRep],
components: []
})
let channelx = interaction.guild.channels.cache.get(myreportChannel) // set channel by id
if (channelx) {
channelx.permissionOverwrites.edit(interaction.user.id, {
VIEW_CHANNEL: true,
SEND_MESSAGES: true,
ATTACH_FILES: true,
READ_MESSAGE_HISTORY: true
}) //edit permision channel. add the permission of the user who clicked on the "accept" button
}
So I adjusted the code above and made some notes along the way, but this should work as expected. I split the command from the button push.
const reportChannel = await interaction.guild.channels.create(channelNameMy, {
type: 'text',
parent: `${categoryTiket}`,
permissionOverwrites: [{
id: `${permUser}`, // permUser - who sent the command
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY', 'ATTACH_FILES']
},
{
id: `${evryOneRolle}`,
deny: ['VIEW_CHANNEL'] //denying view channel will stop all other ones from working too
},
]
})
//Prvivate embed
const exampleEmbed = new MessageEmbed()
.setDescription(`Reported: <#${tagBan.id}>\nReason: ${reason}\nticket: <#${reportChannel.id}>`)
.setColor("#2F3136")
.setImage(`${settings.reportgif}`)
interaction.reply({
embeds: [exampleEmbed],
ephemeral: true
})
//Report embed
const reportEmbed = new MessageEmbed()
.setDescription(`Intruder: ${tagBan}\nReason: ${reason}\nticket:<#${reportChannel.id}>`)
.setColor("#2F3136")
.setImage(`${settings.reportgif}`)
.setFooter({
text: `${reportChannel.id}` // I added the channel ID here again (critical part of the code to not change
})
// adds the new channel id to the footer to be used later when someone clicks the accept button
const acceptButton = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId(`acceptB`)
.setLabel('Accept')
.setStyle('SUCCESS')
.setEmoji('✅')
)
client.channels.cache.get(reportChannel.id).send({
embeds: [reportEmbed],
components: [acceptButton]
})
client.on('interactionCreate', async interaction => {
if (interaction.isButton()) {
if (interaction.customId.includes(`acceptB`)) {
// when someone clicks the accept button it grabs the embed
const oldEmbed = interaction.message.embeds[0]
// adds a line to that embed
const editEmbRep = new MessageEmbed()
.addField('Status:', `${dmStatusAc}`)
// updates the embed and removes the button
interaction.message.edit({
embeds: [editEmbRep],
components: []
})
// finds the channel using the channel id placed in the footer earlier
const channelx = interaction.guild.channels.cache.get(oldEmbed.footer.text)
channelx.permissionOverwrites.edit(interaction.user.id, {
VIEW_CHANNEL: true,
SEND_MESSAGES: true,
ATTACH_FILES: true,
READ_MESSAGE_HISTORY: true
}) // adds them to the channel
}
}
})
I am making a tickets bot.
When I try click of any of the embeds, it will run the code and create a new channel, then continue to ping me in it like I wanted, but then shows this error.
DiscordAPIError: Invalid Form Body
components[0].components[1].emoji.name: Invalid emoji
at RequestHandler.execute (C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\node_modules\discord.js\src\rest\RequestHandler.js:350:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async RequestHandler.push (C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\node_modules\discord.js\src\rest\RequestHandler.js:51:14)
at async TextChannel.send (C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\node_modules\discord.js\src\structures\interfaces\TextBasedChannel.js:175:15)
The full error is here (sorry for link wouldn't let me post full error) :
https://sourceb.in/dOCoUtAQVx
The code is here:
const { ButtonInteraction, MessageEmbed, MessageActionRow, MessageButton } = require("discord.js");
const DB = require("../../Structures/Handlers/Schemas/Ticket");
const { PARENTID, EVERYONEID } = require("../../Structures/config.json");
const Ticket = require("../../Structures/Handlers/Schemas/Ticket");
module.exports = {
name: "interactionCreate",
/**
*
* #param {ButtonInteraction} interaction
*/
async execute(interaction) {
if(!interaction.isButton()) return;
const { guild, member, customId } = interaction;
if (!["player", "bug", "other"].includes(customId)) return;
const ID = Math.floor(Math.random() * 90000) + 10000;
await guild.channels
.create(`${customId + "-" + ID}`, {
type: "GUILD_TEXT",
parent: PARENTID,
permissionOverwrites: [
{
id: member.id,
allow: ["SEND_MESSAGES", "VIEW_CHANNEL", "READ_MESSAGE_HISTORY"],
},
{
id: EVERYONEID,
deny: ["SEND_MESSAGES", "VIEW_CHANNEL", "READ_MESSAGE_HISTORY"],
},
],
})
.then(async (channel) => {
await DB.create({
GuildID: guild.id,
MemberID: member.id,
TicketID: ID,
ChannelID: channel.id,
Closed: false,
Locked: false,
type: customId,
});
const Embed = new MessageEmbed()
.setAuthor(
`${guild.name} | Ticket: ${ID}`,
guild.iconURL({ dynamic: true })
)
.setDescription(
"Please wait patiently for a response from the Staff team, in the mean while, describe your issue in as much detail."
)
.setFooter("The buttons below are staff only buttons.");
const Buttons = new MessageActionRow();
Buttons.addComponents(
new MessageButton()
.setCustomId("close")
.setLabel("Save and close")
.setStyle("PRIMARY")
.setEmoji("📂"),
new MessageButton()
.setCustomId("lock")
.setLabel("lock")
.setStyle("SECONDARY")
.setEmoji("'🔒"),
new MessageButton()
.setCustomId("unlock")
.setLabel("unlock")
.setStyle("SUCCESS")
.setEmoji("❤"),
);
channel.send({
embeds: [Embed],
components: [Buttons],
});
await channel
.send({ content: `${member} here is your ticket` })
.then((m) => {
setTimeout(() => {});
}, 1 * 5000);
})
interaction.reply({
content: `${member} your ticket has been created: ${channel}`,
});
},
};
```js
I'm still learning JavaScript so please bear with me if I don't get it straight away, I will try my best.
You have an extra character in your lock button. It should be .setEmoji("🔒"), not .setEmoji("'🔒"). That's what the error is telling you: "Invalid Emoji" (because '{lock} isn't an emoji)
I'm making a ban command for my discord bot and everything's working except for one thing, the embed that the bot is supposed to send to the banned user is not being sent I'm getting a Discord API problem, this problem:
DiscordAPIError: Invalid Form Body
Here is my ban.js file:
module.exports = {
name: 'ban',
description: "This command bans a member!",
async execute(message, args) {
const member = message.mentions.users.first();
if(message.member.roles.cache.has("858091311126806538")) {
if(!message.guild.me.hasPermission("BAN_MEMBERS")) {
return message.channel.send(`**${message.author.username}**, I do not have perms to ban someone`)
}
let banReason = args.join(" ").slice(22);
if (!banReason) {
banReason = "None"
}
if (member) {
const memberTarget = message.guild.members.cache.get(member.id);
const Discord = require('discord.js');
const delay = (msec) => new Promise((resolve) => setTimeout(resolve, msec));
const authoRR = message.author.tag;
const banEmbed = new Discord.MessageEmbed()
.setColor('#ff0000')
.setTitle(`You are banned from Anime Club!`)
.setAuthor(`${authoRR}`, `${message.author.displayAvatarURL()}`)
.setThumbnail(member.displayAvatarURL())
.addFields(
{ name: 'Banned User:', value: `${memberTarget}` },
{ name: 'Ban Reason:', value: `${banReason}` },
{ name: ' ', value: `You were **banned** from Anime Club,
please do not try to rejoin the server or beg the owner to unban you`}
)
.setTimestamp()
message.mentions.users.first().send(banEmbed);
await delay(100);
memberTarget.ban({
reason: banReason
})
const Author = message.author;
const BanEmbed = new Discord.MessageEmbed()
.setColor('#ff0000')
.setTitle(`User has been banned!`)
.setThumbnail(member.displayAvatarURL())
.addFields(
{ name: 'Banned User:', value: `${memberTarget}` },
{ name: 'Ban Reason:', value: `${banReason}` },
{ name: 'Banned by:', value: `${Author}` },
)
message.channel.send(BanEmbed);
} else {
return message.reply(`Please mention a member!`);
}
} else return message.reply(`You must be an administrator to unban a member`)
}
}
Can anyone help? I really don't understand this problem.
The name property of EmbedFieldData cannot be empty. Discord considers a field name empty if it consists only of whitespace characters. If you want to leave the content visibly empty, you could try something like this.
{
name: '** **',
value: `You were **banned** from Anime Club,
please do not try to rejoin the server or beg the owner to unban you`
}
Update
I have updated the code that is currently working for me, It will now create the channel and then check to see if the channel is create. It will only allow 1 user to create a channel you will not be able to create a T5 channel and a T4 channel as the same user.
Thank you and I hope you all have a great Christmas.
Client.on("message", async (message) => {
if (message.author.Client || message.channel.type === "dm") return;
let messageArray = message.content.split(" ");
let cmd = messageArray[0];
let args = message.content.substring(message.content.indexOf(" ") + 1);
if (cmd === `${prefix}battle`) {
let embed = new Discord.MessageEmbed()
.setTitle("⚔️ 1657 Battles! ⚔️")
.setDescription("React to this message to join the battle.")
.addFields(
{ name: "🥇", value: "T5" },
{ name: "🥈", value: "T4" },
{ name: "🥉", value: "T3" },
{ name: "🏅", value: "T2" },
{ name: "🎖", value: "T1" }
)
.setColor("#0099ff")
.setTimestamp()
.setFooter("Please pick the troop type you want to battle with!");
let msgEmbed = await message.channel.send(embed);
msgEmbed.react("🥇"); // T5
msgEmbed.react("🥈"); // T4
msgEmbed.react("🥉"); // T3
msgEmbed.react("🏅"); // T2
msgEmbed.react("🎖"); // T1
}
});
Client.on("messageReactionAdd", async (reaction, user, message) => {
//Add an event listener
if (reaction.message.partial) await reaction.message.fetch();
if (user.id === Client.user.id) return; //If the reaction was from the bot, return
if (!reaction.message.guild) return; //If the reaction was not in a guild
const guild = Client.guilds.cache.get("644295524404428832");
if (
guild.channels.cache.find((channel) => channel.name === "t5-battle-channel")
)
return;
if (reaction.emoji.name === "🥇") {
let guild = reaction.message.guild;
guild.channels.create("T5 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400016736780338",
allow: ["VIEW_CHANNEL"],
},
],
});
}
if (
guild.channels.cache.find((channel) => channel.name === "t4-battle-channel")
)
return;
if (reaction.emoji.name === "🥈") {
let guild = reaction.message.guild;
guild.channels.create("T4 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400619114463275",
allow: ["VIEW_CHANNEL"],
},
],
});
}
if (
guild.channels.cache.find((channel) => channel.name === "t3-battle-channel")
)
return;
if (reaction.emoji.name === "🥉") {
let guild = reaction.message.guild;
guild.channels.create("T3 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400701130670110",
allow: ["VIEW_CHANNEL"],
},
],
});
}
if (
guild.channels.cache.find((channel) => channel.name === "t2-battle-channel")
)
return;
if (reaction.emoji.name === "🏅") {
let guild = reaction.message.guild;
guild.channels.create("T2 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400738727624704",
allow: ["VIEW_CHANNEL"],
},
],
});
}
if (
guild.channels.cache.find((channel) => channel.name === "t1-battle-channel")
)
return;
if (reaction.emoji.name === "🎖") {
let guild = reaction.message.guild;
guild.channels.create("T1 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400784420372490",
allow: ["VIEW_CHANNEL"],
},
],
});
}
});
If you want to get all of the reactions on a message, you can use the reactions property on a message, if you already have the message object. This will return a ReactionManager which you can use.
You should use a reaction collector.
These work quite similarly to message collectors, except that you
apply them on a message rather than a channel. The following is an
example taken from the documentation, with slightly better variable
names for clarification. The filter will check for the 👍 emoji - in
the default skin tone specifically, so be wary of that. It will also
check that the person who reacted shares the same id as the author of
the original message that the collector was assigned to.
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
Read it's documentation here.
I would like to also know if it is possible to the randomly pair each users that have reacted to a specific role.
The collected property should be handy for this task.
As for adding a role/roles to a GuildMember, use the add method. Read about how you can add a role to a member here.