restructure commands to be in seperate dirs, add mod commands and plenty others

This commit is contained in:
Ayden Jahola 2024-09-05 03:50:51 +01:00
parent a44310b00f
commit 2ec7c73709
No known key found for this signature in database
GPG key ID: 71DD90AE4AE92742
12 changed files with 635 additions and 16 deletions

View file

@ -0,0 +1,57 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("botinfo")
.setDescription("Displays information about the bot"),
async execute(interaction, client) {
try {
const uptime = client.uptime; // Uptime in milliseconds
const days = Math.floor(uptime / (24 * 60 * 60 * 1000));
const hours = Math.floor(
(uptime % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000)
);
const minutes = Math.floor((uptime % (60 * 60 * 1000)) / (60 * 1000));
const seconds = Math.floor((uptime % (60 * 1000)) / 1000);
const botInfoEmbed = new EmbedBuilder()
.setColor("#0099ff")
.setTitle("Bot Information")
.addFields(
{ name: "Bot Name", value: client.user.tag, inline: true },
{
name: "Uptime",
value: `${days} days, ${hours} hours, ${minutes} minutes, ${seconds} seconds`,
inline: true,
},
{
name: "Server Count",
value: `${client.guilds.cache.size}`,
inline: true,
},
{
name: "User Count",
value: `${client.users.cache.size}`,
inline: true,
}
)
.setThumbnail(client.user.displayAvatarURL())
.setTimestamp()
.setFooter({
text: `Requested by ${interaction.user.tag}`,
iconURL: interaction.user.displayAvatarURL(),
});
await interaction.reply({
embeds: [botInfoEmbed],
});
} catch (error) {
console.error("Error executing botinfo command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

View file

@ -0,0 +1,55 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("serverinfo")
.setDescription("Displays information about the server"),
async execute(interaction) {
try {
const guild = interaction.guild;
const serverInfoEmbed = new EmbedBuilder()
.setColor("#0099ff")
.setTitle("Server Information")
.addFields(
{ name: "Server Name", value: guild.name, inline: true },
{
name: "Total Members",
value: `${guild.memberCount}`,
inline: true,
},
{
name: "Created On",
value: guild.createdAt.toDateString(),
inline: true,
},
{
name: "Region",
value: guild.preferredLocale || "Unknown",
inline: true,
}, // Fallback to "Unknown"
{
name: "Verification Level",
value: guild.verificationLevel.toString(),
inline: true,
} // Convert enum to string
)
.setThumbnail(guild.iconURL())
.setTimestamp()
.setFooter({
text: `Requested by ${interaction.user.tag}`,
iconURL: interaction.user.displayAvatarURL(),
});
await interaction.reply({
embeds: [serverInfoEmbed],
});
} catch (error) {
console.error("Error executing serverinfo command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

View file

@ -0,0 +1,140 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("purge")
.setDescription("Deletes messages from the channel")
.addStringOption((option) =>
option
.setName("type")
.setDescription("Type of purge operation")
.setRequired(true)
.addChoices(
{ name: "Purge Specific Number", value: "specific" },
{ name: "Purge All", value: "all" }
)
)
.addIntegerOption((option) =>
option
.setName("amount")
.setDescription("The number of messages to delete (1-100)")
.setRequired(false)
.setMinValue(1)
.setMaxValue(100)
),
isModOnly: true,
async execute(interaction) {
try {
const requiredRoleId = process.env.MOD_ROLE_ID;
if (!interaction.member.roles.cache.has(requiredRoleId)) {
await interaction.reply({
content: "You do not have the required role to use this command!",
ephemeral: true,
});
return;
}
const type = interaction.options.getString("type");
let amount = interaction.options.getInteger("amount");
const logChannelId = process.env.LOG_CHANNEL_ID;
const logChannel = interaction.guild.channels.cache.get(logChannelId);
if (type === "specific") {
// Ensure the number of messages to delete is between 1 and 100
if (amount < 1 || amount > 100) {
await interaction.reply({
content: "Please specify a number between 1 and 100.",
ephemeral: true,
});
return;
}
// Delete a specific number of messages
const fetchedMessages = await interaction.channel.messages.fetch({
limit: amount,
});
await interaction.channel.bulkDelete(fetchedMessages);
const purgeEmbed = new EmbedBuilder()
.setColor("#ff0000")
.setTitle("Messages Purged")
.setDescription(`Successfully deleted ${amount} messages.`)
.setTimestamp()
.setFooter({
text: `Requested by ${interaction.user.tag}`,
iconURL: interaction.user.displayAvatarURL(),
});
// Send confirmation as ephemeral message
await interaction.reply({
embeds: [purgeEmbed],
ephemeral: true,
});
// Send log to the logs channel
if (logChannel) {
const logEmbed = new EmbedBuilder()
.setColor("#ff0000")
.setTitle("Purge Operation")
.setDescription(
`User ${interaction.user.tag} purged ${amount} messages from ${interaction.channel.name}.`
)
.setTimestamp();
await logChannel.send({ embeds: [logEmbed] });
}
} else if (type === "all") {
// Purge all messages (up to 100 messages at a time)
let messages;
let deletedMessagesCount = 0;
do {
messages = await interaction.channel.messages.fetch({ limit: 100 });
if (messages.size === 0) break;
deletedMessagesCount += messages.size;
await interaction.channel.bulkDelete(messages);
} while (messages.size >= 2); // Keep fetching and deleting until no more messages are left
const purgeEmbed = new EmbedBuilder()
.setColor("#ff0000")
.setTitle("All Messages Purged")
.setDescription("Successfully deleted all messages in the channel.")
.setTimestamp()
.setFooter({
text: `Requested by ${interaction.user.tag}`,
iconURL: interaction.user.displayAvatarURL(),
});
// Send confirmation as ephemeral message
await interaction.reply({
embeds: [purgeEmbed],
ephemeral: true,
});
// Send log to the logs channel
if (logChannel) {
const logEmbed = new EmbedBuilder()
.setColor("#ff0000")
.setTitle("Purge Operation")
.setDescription(
`User ${interaction.user.tag} purged all messages from ${interaction.channel.name}. Total messages deleted: ${deletedMessagesCount}.`
)
.setTimestamp();
await logChannel.send({ embeds: [logEmbed] });
}
}
} catch (error) {
console.error("Error executing purge command:", error);
try {
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
} catch (replyError) {
console.error("Error replying to interaction:", replyError);
}
}
},
};

View file

@ -0,0 +1,71 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("userinfo")
.setDescription("Displays information about a user")
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user to get information about")
.setRequired(false)
),
isModOnly: true,
async execute(interaction) {
try {
const requiredRoleId = process.env.MOD_ROLE_ID;
if (!interaction.member.roles.cache.has(requiredRoleId)) {
await interaction.reply({
content: "You do not have the required role to use this command!",
ephemeral: true,
});
return;
}
const user = interaction.options.getUser("user") || interaction.user;
const member = interaction.guild.members.cache.get(user.id);
// Create the embed for user information
const userInfoEmbed = new EmbedBuilder()
.setColor("#0099ff")
.setTitle("User Information")
.addFields(
{ name: "Username", value: user.tag, inline: true },
{
name: "Joined Server On",
value: member ? member.joinedAt.toDateString() : "N/A",
inline: true,
},
{
name: "Account Created On",
value: user.createdAt.toDateString(),
inline: true,
},
{
name: "Roles",
value: member
? member.roles.cache.map((role) => role.name).join(", ")
: "N/A",
inline: false,
}
)
.setThumbnail(user.displayAvatarURL())
.setTimestamp()
.setFooter({
text: `Requested by ${interaction.user.tag}`,
iconURL: interaction.user.displayAvatarURL(),
});
await interaction.reply({
embeds: [userInfoEmbed],
});
} catch (error) {
console.error("Error executing userinfo command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

117
commands/moderation/warn.js Normal file
View file

@ -0,0 +1,117 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
const Warning = require("../../models/warning");
module.exports = {
data: new SlashCommandBuilder()
.setName("warn")
.setDescription("Issue a warning to a user")
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user to warn")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("reason")
.setDescription("The reason for the warning")
.setRequired(true)
),
isModOnly: true,
async execute(interaction) {
try {
const requiredRoleId = process.env.MOD_ROLE_ID;
if (!interaction.member.roles.cache.has(requiredRoleId)) {
await interaction.reply({
content: "You do not have the required role to use this command!",
ephemeral: true,
});
return;
}
const user = interaction.options.getUser("user");
const reason = interaction.options.getString("reason");
const member = interaction.guild.members.cache.get(user.id);
// Save the warning to the database
const warning = new Warning({
userId: user.id,
guildId: interaction.guild.id,
reason: reason,
});
await warning.save();
const logChannelId = process.env.LOG_CHANNEL_ID;
const logChannel = interaction.guild.channels.cache.get(logChannelId);
if (!logChannel) {
await interaction.reply({
content: "Log channel not found!",
ephemeral: true,
});
return;
}
// Create and send the warning log to the log channel
const warnEmbed = new EmbedBuilder()
.setColor("#ffcc00")
.setTitle("User Warned")
.addFields(
{ name: "User", value: `${user.tag} (${user.id})`, inline: true },
{ name: "Reason", value: reason, inline: true },
{ name: "Issued By", value: interaction.user.tag, inline: true },
{ name: "Date", value: new Date().toLocaleString(), inline: true }
)
.setTimestamp()
.setFooter({
text: `Warned in ${interaction.guild.name}`,
iconURL: interaction.guild.iconURL(),
});
await logChannel.send({ embeds: [warnEmbed] });
// Send a DM to the user
try {
const dmEmbed = new EmbedBuilder()
.setColor("#ffcc00")
.setTitle("Warning Notice")
.setDescription(
`You have been warned in **${interaction.guild.name}**.`
)
.addFields(
{ name: "Reason", value: reason, inline: false },
{ name: "Issued By", value: interaction.user.tag, inline: false },
{ name: "Date", value: new Date().toLocaleString(), inline: false }
)
.setFooter({
text: `Please follow the rules of ${interaction.guild.name}`,
iconURL: interaction.guild.iconURL(),
})
.setTimestamp();
await user.send({ embeds: [dmEmbed] });
} catch (dmError) {
console.error("Error sending DM to user:", dmError);
await interaction.reply({
content: `Failed to send a DM to ${user.tag}.`,
ephemeral: true,
});
return;
}
// Notify the mod who issued the warning
await interaction.reply({
content: `Successfully warned ${user.tag} for: ${reason}`,
ephemeral: true,
});
} catch (error) {
console.error("Error executing warn command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

60
commands/utility/help.js Normal file
View file

@ -0,0 +1,60 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("help")
.setDescription("Lists all available commands"),
async execute(interaction, client) {
try {
const modRoleId = process.env.MOD_ROLE_ID;
const isMod = interaction.member.roles.cache.has(modRoleId);
const serverName = interaction.guild.name;
const helpEmbed = new EmbedBuilder()
.setColor("#0099ff")
.setTitle("Available Commands")
.setDescription("Here are all the available commands:")
.setTimestamp()
.setFooter({
text: `${serverName}`,
iconURL: client.user.displayAvatarURL(),
});
// Add general commands
client.commands.forEach((command) => {
if (!command.isModOnly) {
helpEmbed.addFields({
name: `/${command.data.name}`,
value: command.data.description,
inline: false,
});
}
});
// Add mod-only commands if the user is a mod
if (isMod) {
client.commands.forEach((command) => {
if (command.isModOnly) {
helpEmbed.addFields({
name: `/${command.data.name}`,
value: command.data.description + " (Mods only)",
inline: false,
});
}
});
}
await interaction.reply({
embeds: [helpEmbed],
});
} catch (error) {
console.error("Error executing the help command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

44
commands/utility/ping.js Normal file
View file

@ -0,0 +1,44 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("ping")
.setDescription("Replies with Pong! and bot latency"),
async execute(interaction, client) {
try {
const sent = await interaction.reply({
content: "Pinging...",
fetchReply: true,
});
const latency = sent.createdTimestamp - interaction.createdTimestamp;
const apiLatency = Math.round(client.ws.ping);
const serverName = interaction.guild.name;
const pingEmbed = new EmbedBuilder()
.setColor("#0099ff")
.setTitle("Pong! 🏓")
.setDescription("Bot latency information:")
.addFields(
{ name: "Latency", value: `${latency} ms`, inline: true },
{ name: "API Latency", value: `${apiLatency} ms`, inline: true }
)
.setTimestamp()
.setFooter({
text: `${serverName}`,
iconURL: client.user.displayAvatarURL(),
});
await interaction.editReply({
embeds: [pingEmbed],
});
} catch (error) {
console.error("Error executing the ping command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

View file

@ -0,0 +1,46 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("uptime")
.setDescription("Shows how long the bot has been running"),
async execute(interaction, client) {
try {
const uptime = client.uptime;
const days = Math.floor(uptime / (24 * 60 * 60 * 1000));
const hours = Math.floor(
(uptime % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000)
);
const minutes = Math.floor((uptime % (60 * 60 * 1000)) / (60 * 1000));
const seconds = Math.floor((uptime % (60 * 1000)) / 1000);
const serverName = interaction.guild.name;
const uptimeEmbed = new EmbedBuilder()
.setColor("#0099ff")
.setTitle("Bot Uptime")
.setDescription(`The bot has been online for:`)
.addFields(
{ name: "Days", value: `${days}`, inline: true },
{ name: "Hours", value: `${hours}`, inline: true },
{ name: "Minutes", value: `${minutes}`, inline: true },
{ name: "Seconds", value: `${seconds}`, inline: true }
)
.setTimestamp()
.setFooter({
text: `${serverName}`,
iconURL: client.user.displayAvatarURL(),
});
await interaction.reply({
embeds: [uptimeEmbed],
});
} catch (error) {
console.error("Error executing the uptime command:", error);
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
},
};

View file

@ -1,5 +1,5 @@
const { SlashCommandBuilder } = require("discord.js");
const VerificationCode = require("../models/VerificationCode");
const VerificationCode = require("../../models/VerificationCode");
module.exports = {
data: new SlashCommandBuilder()
@ -89,7 +89,7 @@ module.exports = {
// Get the admin log channel
const adminLogChannel = client.channels.cache.get(
process.env.ADMIN_LOG_CHANNEL_ID
process.env.LOG_CHANNEL_ID
);
if (adminLogChannel) {

View file

@ -1,6 +1,6 @@
const { SlashCommandBuilder } = require("discord.js");
const nodemailer = require("nodemailer");
const VerificationCode = require("../models/VerificationCode");
const VerificationCode = require("../../models/VerificationCode");
const transporter = nodemailer.createTransport({
service: "Gmail",

View file

@ -18,19 +18,31 @@ const client = new Client({
],
});
const GUIlD_ID = process.env.GUILD_ID;
const GUILD_ID = process.env.GUILD_ID;
client.commands = new Collection();
const commandFiles = fs
.readdirSync(path.join(__dirname, "commands"))
.filter((file) => file.endsWith(".js"));
// Function to recursively read commands from subdirectories
function loadCommands(dir) {
const files = fs.readdirSync(dir);
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
for (const file of files) {
const filePath = path.join(dir, file);
if (fs.statSync(filePath).isDirectory()) {
// If it's a directory, recurse into it
loadCommands(filePath);
} else if (file.endsWith(".js")) {
// If it's a JavaScript file, load the command
const command = require(filePath);
client.commands.set(command.data.name, command);
}
}
}
// Load all commands from the commands directory and its subdirectories
loadCommands(path.join(__dirname, "commands"));
client.once("ready", async () => {
console.log(`\n==============================`);
console.log(`🤖 Logged in as ${client.user.tag}`);
@ -52,7 +64,7 @@ client.once("ready", async () => {
const rest = new REST({ version: "10" }).setToken(process.env.BOT_TOKEN);
try {
await rest.put(Routes.applicationGuildCommands(client.user.id, GUIlD_ID), {
await rest.put(Routes.applicationGuildCommands(client.user.id, GUILD_ID), {
body: commands,
});
console.log("Successfully registered all application commands.");
@ -77,12 +89,19 @@ client.on("interactionCreate", async (interaction) => {
try {
await command.execute(interaction, client);
} catch (err) {
console.error(err);
console.error("Error executing command:", err);
if (interaction.deferred || interaction.ephemeral) {
await interaction.followUp({
content: "There was an error while executing this command!",
ephemeral: true,
});
} else {
await interaction.reply({
content: "There was an error while executing this command!",
ephemeral: true,
});
}
}
});
client.on("Error", (err) => {

10
models/warning.js Normal file
View file

@ -0,0 +1,10 @@
const mongoose = require("mongoose");
const warningSchema = new mongoose.Schema({
userId: { type: String, required: true },
guildId: { type: String, required: true },
reason: { type: String, required: true },
date: { type: Date, default: Date.now },
});
module.exports = mongoose.model("Warning", warningSchema);