Repository (code): https://github.com/JavascriptLearner815/spelta-discord-bot/tree/development
I am creating a Discord bot with Discord.js. I wanted to add three DM commands for the bot:
dm, reply, and followup.
In order to reply to the last DM, I needed to use SQLITE. I made and required a database.js file to do that, using the discord.js guide for SQLite. But when I run the command dm, the table isn't even created!
My code editor does in fact show the files database.js and database.sqlite.
I have also tried using node database.js.
In Discord, I get the messages from my alt and my main account, but it replies to my interaction with "Error! Either you or the recipient have disabled DMs!" This is actually my message that gets sent with a catch.
What could be the problem here?
P.S. If you prefer viewing the code right here on StackOverflow, here it is:
commands/dm.js:
const { SlashCommandBuilder } = require("#discordjs/builders")
const { DirectMessages } = require("../database")
module.exports = {
data: new SlashCommandBuilder()
.setName("dm")
.setDescription("Directly messages a user!")
.addUserOption(option =>
option
.setRequired(true)
.setName("user")
.setDescription("The user to message"))
.addStringOption(option =>
option
.setRequired(true)
.setName("message")
.setDescription("The message to send")),
async execute(interaction) {
const user = interaction.options.getUser("user")
const message = interaction.options.getString("message")
try {
await user.send(`**${interaction.user.tag} sent a message:** ${message}`)
await interaction.user.send(`**Sent ${user.tag} a message:** ${message}`)
await DirectMessages.create({
message,
from: interaction.user.id,
to: user.id,
})
interaction.reply({ content: "Successfully sent your message!", ephemeral: true })
}
catch (error) {
console.error(error)
interaction.reply({ content: "Error! Either the recipient or yourself has disabled DMs!", ephemeral: true })
}
},
}
database.js:
const Sequelize = require("sequelize")
const sequelize = new Sequelize("database", "user", "password", {
host: "localhost",
dialect: "sqlite",
logging: false,
// SQLite only
storage: "database.sqlite",
})
const DirectMessages = sequelize.define("dms", {
message: Sequelize.TEXT,
from: Sequelize.STRING,
to: Sequelize.STRING,
})
module.exports = {
sequelize,
DirectMessages,
}
await sequelize.sync({ force: true });
console.log("All models were synchronized successfully.");
you should check Sequelize Synchronizing all model
Related
I have this code to unban someone using id (btw if you know how to unban by "ping" a user that is ban I will like to know how to do that). I have an issue with the id that could be a letter and my code was crashing so I try to fix it but know the problem is that the option are undefined.
Here is my code :
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const { SnowflakeUtil } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('unban')
.setDescription('Send an id of a discord member and unban them.')
.addStringOption(option =>
option
.setName('target')
.setDescription('The id of the member to unban')
.setRequired(true))
.addStringOption(option =>
option
.setName('reason')
.setDescription('The reason for unbanning'))
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)
.setDMPermission(false),
async execute(client, interaction) {
const target = interaction.options.get('target');
if (!target) return interaction.reply({ content: "The 'target' option is missing.", ephemeral: true });
if (!SnowflakeUtil.deconstruct(target).valid) {
return interaction.reply({ content: "The target id is not a valid id.", ephemeral: true });
}
const reason = interaction.options.get('reason') || 'No reason provided';
const user = await client.users.fetch(target);
if (!user) return interaction.reply({ content: "I could not find this user.", ephemeral: true });
await interaction.reply(`Unbanning ${user.tag} for reason: ${reason}`);
await interaction.guild.members.unban(user.id);
},
};
The error is :
TypeError: Cannot read properties of undefined (reading 'options')
It is suppose to unban a user of the discord server.
Parameters is probably execute(interaction, client).
This means you need to change parameters in your command to async execute(interaction, client)
or you can leave it as it is and write interaction where you write client and client where you write interaction. The most appropriate solution would be the first thing I said.
I'm creating my Discord bot, and I saw that with the hosting provider I bought came with a mySQL database, so I'm using it. I connected to it with the mySQL NPM package:
export const con = mysql.createConnection({
host: process.env.MYSQL_HOST,
port: process.env.MYSQL_PORT,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DB,
});
and it works fine. I created a table in the database, with 3 parameters:
id: Discord user id
bananas: My toy currency
deposit: The currency deposit
I set it up that on the interactionCreate event, whenever a user uses an interaction, it checks the database, if there is a profile, it does nothing, else, it creates the profile in the database. Code:
async checkDB(int: CommandInteraction | MessageComponentInteraction) {
await con.query(
`SELECT * FROM profileSchema WHERE id = '${int.user.id}'`,
async (e: Error, rows: any) => {
if (e) throw e;
if (!rows[0]) {
await con.query(
`INSERT INTO profileSchema (id, bananas, deposit) VALUES ('${int.user.id}', 100, 0)`
);
}
}
);
},
this code works fine, the problem is that if a user does not have a profile in the database, and they use a currency related command, like the one that shows their balance, the bot crashes because their credits in the database result nonexistent, even though the profile gets created and the second time they use the command it works properly! How can I code so that if the user is not in the database and uses a command, it creates and displays at the same time? Here's the code that checks the currency balance:
await con.query(
`SELECT * FROM profileSchema WHERE id = ${interaction.user.id}`,
async (e: Error, rows: any[]) => {
if (e) throw e;
let wallet: {
bananas: number;
deposit: number;
};
try {
wallet = {
bananas: rows[0].bananas,
deposit: rows[0].deposit,
};
} catch (e) {
throw e
return;
}
)
So unless it is really needed, you don 't need the async/await components in this but the simple answer you are looking for is to change if (!rows[0]) to if (!rows.length) but that works when you set up your query like such:
con.query(`SELECT * FROM profileSchema WHERE id = '${int.user.id}'`, (err, rows) => {
if (err) throw err;
if (!rows.length) {
con.query(`INSERT INTO profileSchema (id, bananas, deposit) VALUES ('${int.user.id}', 100, 0)`, (err) => {
if (err) throw err;
});
} else {
let wallet = {
bananas: rows[0].bananas,
deposit: rows[0].deposit,
}
}
});
Hey Stack Overflow Community,
I have another question in regard to discord.js.I want to send a message and add an emoji to it, from which I later want to get the list of users who have reacted. In order to do so I have 2 questions:
-How can I add an emoji? Do I need a separate event listener for a message or can I do it within my interactionCreate event? I have tried pannel.react("👍") which gives me the error: 'TypeError: pannel.react is not a function'. Does anyone know how to let this work?
-My other question is if there is a way to access the message id from the send message, in order to check who has participated later on in another command?
I have an index file with my command and event handlers. The script is from my "setup.js" command in the "commands" folder:
const { SlashCommandBuilder } = require("#discordjs/builders");
const Discord = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("setup")
.setDescription("Setup Tweet to be rewarded")
.addChannelOption(option =>
option
.setName('destination')
.setDescription('Select a channel for the reward pannel')
.setRequired(true)
)
.addStringOption(option =>
option
.setName("twitterlink")
.setDescription("Enter the Twitter Link")
.setRequired(false)
),
async execute(interaction) {
interaction.reply({
content: "Pannel send",
ephemeral: true
}).then( function () {
const channel = interaction.options.getChannel("destination");
const channelid = channel.id;
const twitterlink = interaction.options.getString("twitterlink");
const pannel = interaction.guild.channels.cache.get(channelid).send(twitterlink);
});
}
};
Thank you very much for your assistance in advance.
Cleaned it up a bit and this should work for you
const {
SlashCommandBuilder,
} = require("#discordjs/builders");
const Discord = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("setup")
.setDescription("Setup Tweet to be rewarded")
.addChannelOption(option =>
option
.setName('destination')
.setDescription('Select a channel for the reward pannel')
.setRequired(true),
)
.addStringOption(option =>
option
.setName("twitterlink")
.setDescription("Enter the Twitter Link")
.setRequired(false),
),
async execute(interaction) { // Fixed below here and simplified it
const channel = interaction.guild.channels.cache.get(interaction.options.getChannel("destination").id);
const twitterlink = interaction.options.getString("twitterlink");
channel.send(twitterlink).then(msg => {
msg.react('🍎'),
});
return interaction.reply({
content: "Pannel send",
ephemeral: true,
});
},
};
Okay with the help from #Gh0st I was able to find a solution:
The problem in order to send a message is that the .get() function need the channel id. I have accessd it to interaction.options.getChannel("destination").id);.
I couldnt add a reaction because my .send command was not await: const pannel = await channel.send(twitterlink).
The message id is easiy to find by using .id on the variable of the message:
const pannelid = pannel.id.
The resulting code can be found below:
const { SlashCommandBuilder } = require("#discordjs/builders");
const Discord = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("setup")
.setDescription("Setup Tweet to be rewarded")
.addChannelOption(option =>
option
.setName('destination')
.setDescription('Select a channel for the reward pannel')
.setRequired(true)
)
.addStringOption(option =>
option
.setName("twitterlink")
.setDescription("Enter the Twitter Link")
.setRequired(false)
),
async execute(interaction) { // Fixed below here and simplified it
const channel = interaction.guild.channels.cache.get(interaction.options.getChannel("destination").id);
const twitterlink = interaction.options.getString("twitterlink");
const pannel = await channel.send(twitterlink)
pannel.react('🍎');
const pannelid = pannel.id
return interaction.reply({
content: "Pannel send",
ephemeral: true,
});
},
};
Meaning: there is some content and a button in the response to the slash command. The task of the button is to delete the message. What we managed to do was to force the button to delete the message, but the problem is that not only the message in which the button is deleted, but also other messages.
const {
MessageEmbed,
MessageActionRow,
MessageButton
} = require('discord.js')
const {
SlashCommandBuilder
} = require('#discordjs/builders')
const Color = 'RANDOM'
module.exports = {
name: 'Name',
data: new SlashCommandBuilder()
.setName('Name')
.setDescription('Description')
.addStringOption(option => option.setName('choice')
.setDescription('Description')
.setRequired(true)
.addChoice('choice1', 'choice1')
.addChoice('choice2', 'choice2')
.addChoice('choice3', 'choice3')
async run(interaction) {
const Embed = new MessageEmbed()
.setColor(Color)
.setTimestamp()
.setImage(url)
const Btns = new MessageActionRow()
.addComponents(new MessageButton()
.setCustomId('DeleteMsg')
.setStyle('DANGER')
.setLabel('Удалить сообщение (Только автор или администратор)'))
interaction.reply({
embeds: [Embed],
components: [Btns]
})
try {
const collector = interaction.channel.createMessageComponentCollector({
time: 60000
})
collector.on('collect', async i => {
interaction.deleteReply()
})
} catch (error) {
console.log(error)
}
}
}
Ok first of all, you should always add a filter to your component collector.
(How many items to collect, check if correct users used your component, ...)
You should also have a real custom ID (like an UUID or something like that) because if there's multiple calls of your command in the same channel then, your custom ID wouldn't be custom anymore and could be collected by every collector running in the channel.
So I've just completed writing a ping.js, echo.js, guildMemberAdd.js, and guildMemberRemove.js and I'm moving on to writing a ban.js and kick.js and currently all slash commands work except the latest commands which is kick and ban. I keep getting the error that "The reply to this interaction has not been sent or deferred." and I have no idea how to find a solution to it. I originally had it written "return interaction.followUp" and I switched them all to "await interaction.followUp" hoping it'd be the solution the problem, but it seems like that wasn't it. I originally also had it written "run: async (interaction) => {" but then I get the error that "command.execute" is not a function so I switched it to "async execute (intereaction) {" I've also tried a couple of other things, but still can't seem to find a fix, does anyone have any idea on this? I'll leave my interactionCreate.js and kick.js below
interactionCreate.js
module.exports = {
name: "interactionCreate",
async execute(interaction) {
if (!interaction.isCommand()) return;
const command = interaction.client.commands.get(interaction.commandName);
if (!command) return;
try {
await command.execute(interaction);
} catch (err) {
if (err) console.error(err);
await interaction.reply({
content: "An error occured while executing that command.",
ephemeral: true
});
}
}
}
kick.js
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageEmbed } = require("discord.js")
module.exports = {
data: new SlashCommandBuilder()
.setName("kick")
.setDescription("Allows the admin or owner to kick the member.")
.addUserOption((option) => option.setName('user').setDescription('The person who you want to kick').setRequired(true))
.addStringOption(option => option.setName('reason').setDescription('Reason to kick member').setRequired(true)),
async execute (interaction) {
if(!interaction.member.permissions.has("KICK_MEMBERS")) return interaction.followUp({ content: "You do not have the power to kick that member.", ephemeral: true })
const user = interaction.options.getUser('user')
const member = interaction.guild.members.cache.get(user.id) || await interaction.guild.members.fetch(user.id).catch(err => {})
if(!member) return interaction.followUp({ content: "😅 | Well this is awkward... I'm unable to get details related to given member.", ephemeral: true });
const reason = interaction.options.getString('reason')
if(!member.kickable || member.user.id === member.user.id)
await interaction.followUp({ content: "😡 | I am unable to kick this member", ephemeral: true });
if(interaction.member.roles.highest.position <= member.roles.highest.position)
await interaction.followUp({ content: 'This member has equal or higher power as you so I cannot kick them.', ephemeral: true })
const embed = new MessageEmbed()
.setDescription(`**${member.user.tag}** is kicked out from the cookout for \`${reason}\``)
.setColor("#5104DB")
.setFooter({ text: "Kick Member" })
.setTimestamp()
await interaction.reply(`You are kicked from **\`${interaction.guild.name}\`** for \`${reason}\``).catch(err => {})
member.kick();
await interaction.followUp({ embeds: [ embed ]})
}
}
The error comes from line 19 and 22
await interaction.followUp({ content: "😡 | I am unable to kick this member", ephemeral: true });
await interaction.followUp({ content: 'This member has equal or higher power as you so I cannot kick them.', ephemeral: true })
You attempt to followUp to an interaction, with no reply as the error message suggests. You can change this to reply as you do further down in the code, which will work.
Note: you will likely receive unexpected errors if you don't return or stop the code when the conditions above are met