Upgrades for a more solid base

This commit is contained in:
Skylar Grant 2023-02-12 23:51:17 -05:00
parent a17a4da93d
commit 9c4a2c1e4c
12 changed files with 207 additions and 90 deletions

3
.env
View File

@ -1,3 +1,4 @@
TOKEN=
DEBUG=true
CLIENTID=
BOTID=
STATUSCHANNELID=

View File

@ -1,17 +1,24 @@
{
"help": {
"info": "",
"setup": "",
"permissions": ""
"title": "Title",
"content": "Some help content",
"footer": "Witty Text Here"
},
"embeds": {
"footer": "",
"color": "0x55FF55"
"footer": "github/voidf1sh/discord-bot-template",
"color": "0x55FF55",
"errorTitle": "Error",
"errorColor": "0xFF0000",
"infoTitle": "Information",
"infoColor": "0x8888FF"
},
"emoji": {
"next": "⏭️",
"previous": "⏮️",
"confirm": "☑️",
"cancel": "❌"
},
"errors": {
"generalCommand": "Sorry, there was an error running that command."
}
}

31
main.js
View File

@ -6,32 +6,25 @@ dotenv.config();
const token = process.env.TOKEN;;
// Discord.JS
const { Client, GatewayIntentBits, Partials } = require('discord.js');
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.MessageContent
],
partials: [
Partials.Channel,
Partials.Message
],
GatewayIntentBits.Guilds
]
});
// Various imports
const fn = require('./modules/functions.js');
const strings = require('./data/strings.json');
const isDev = process.env.DEBUG;
const debugMode = process.env.DEBUG;
const statusChannelId = process.env.STATUSCHANNELID
client.once('ready', () => {
fn.collections.slashCommands(client);
fn.collectionBuilders.slashCommands(client);
console.log('Ready!');
client.channels.fetch(statusChannelId).then(channel => {
channel.send(`${new Date().toISOString()} -- Ready`);
});
// client.channels.fetch(statusChannelId).then(channel => {
// channel.send(`${new Date().toISOString()} -- Ready`).catch(e => console.error(e));
// });
});
// slash-commands
@ -40,12 +33,16 @@ client.on('interactionCreate', async interaction => {
const { commandName } = interaction;
if (client.slashCommands.has(commandName)) {
client.slashCommands.get(commandName).execute(interaction);
client.slashCommands.get(commandName).execute(interaction).catch(e => console.error(e));
} else {
interaction.reply('Sorry, I don\'t have access to that command.');
interaction.reply('Sorry, I don\'t have access to that command.').catch(e => console.error(e));
console.error('Slash command attempted to run but not found: /' + commandName);
}
}
});
process.on('uncaughtException', err => {
console.error(err);
});
client.login(token);

View File

@ -2,24 +2,25 @@
const dotenv = require('dotenv');
dotenv.config();
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const clientId = process.env.clientId;
const { guildId } = require('../data/config.json');
const { REST, Routes } = require('discord.js');
const botId = process.env.BOTID;
const token = process.env.TOKEN;
const fs = require('fs');
const rest = new REST({ version: '9' }).setToken(token);
console.log(`Token: ...${token.slice(-5)} | Bot ID: ${botId}`);
const rest = new REST({ version: '10' }).setToken(token);
(async () => {
try {
console.log('Started refreshing application (/) commands.');
console.log('Started clearing global application (/) commands.');
await rest.put(
Routes.applicationGuildCommands(clientId, guildId),
Routes.applicationCommands(botId),
{ body: '' },
);
console.log('Successfully reloaded application (/) commands.');
console.log('Successfully cleared global application (/) commands.');
process.exit();
} catch (error) {
console.error(error);

View File

@ -2,9 +2,8 @@
const dotenv = require('dotenv');
dotenv.config();
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const clientId = process.env.CLIENTID;
const { REST, Routes } = require('discord.js');
const botId = process.env.BOTID;
const token = process.env.TOKEN;
const fs = require('fs');
@ -12,26 +11,26 @@ const commands = [];
const commandFiles = fs.readdirSync('./slash-commands').filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const command = require(`./slash-commands/${file}`);
const command = require(`../slash-commands/${file}`);
if (command.data != undefined) {
commands.push(command.data.toJSON());
}
}
// console.log(commands);
console.log(`Token: ...${token.slice(-5)} | Bot ID: ${botId}`);
const rest = new REST({ version: '9' }).setToken(token);
const rest = new REST({ version: '10' }).setToken(token);
(async () => {
try {
console.log('Started refreshing application (/) commands.');
console.log('Started refreshing global application (/) commands.');
await rest.put(
Routes.applicationCommands(clientId),
Routes.applicationCommands(botId),
{ body: commands },
);
console.log('Successfully reloaded application (/) commands.');
console.log('Successfully reloaded global application (/) commands.');
process.exit();
} catch (error) {
console.error(error);

18
modules/_sanitizeInput.js Normal file
View File

@ -0,0 +1,18 @@
const replaceAll = require('string.prototype.replaceall');
const fs = require('fs');
const path = "./input.txt";
const input = fs.readFileSync(path);
let output = "";
console.log(input);
if (input.includes("\r\n")) {
output = replaceAll(input, "\r\n", "\\n");
} else {
output = replaceAll(input, "\n", "\\n");
}
output = replaceAll(output, "`", "``");
console.log(output);
fs.writeFileSync(path, output);

View File

@ -1,24 +1,22 @@
/* eslint-disable comma-dangle */
// dotenv for handling environment variables
// dotenv for importing environment variables
const dotenv = require('dotenv');
dotenv.config();
const isDev = process.env.DEBUG;
// filesystem
const fs = require('fs');
// Configure Environment Variables
dotenv.config();
// Discord.js
const Discord = require('discord.js');
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord;
// Various imports from other files
const debugMode = process.env.DEBUG;
const config = require('../data/config.json');
const strings = require('../data/strings.json');
const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js'));
const functions = {
// Functions for managing and creating Collections
collections: {
collectionBuilders: {
// Create the collection of slash commands
slashCommands(client) {
if (!client.slashCommands) client.slashCommands = new Discord.Collection();
@ -29,50 +27,52 @@ const functions = {
client.slashCommands.set(slashCommand.data.name, slashCommand);
}
}
if (isDev) console.log('Slash Commands Collection Built');
if (debugMode) console.log('Slash Commands Collection Built');
}
},
builders: {
refreshAction() {
// Create the button to go in the Action Row
const refreshButton = new ButtonBuilder()
.setCustomId('refresh')
.setLabel('Refresh')
.setStyle(ButtonStyle.Primary);
// Create the Action Row with the Button in it, to be sent with the Embed
const refreshActionRow = new ActionRowBuilder()
.addComponents(
refreshButton
);
return refreshActionRow;
actionRows: {
example() {
// Create the button to go in the Action Row
const exampleButton = this.buttons.exampleButton();
// Create the Action Row with the Button in it, to be sent with the Embed
return new ActionRowBuilder()
.addComponents(exampleButton);
},
buttons: {
exampleButton() {
return new ButtonBuilder()
.setCustomId('id')
.setLabel('Label')
.setStyle(ButtonStyle.Primary);
}
}
},
helpEmbed(content, private) {
const embed = new EmbedBuilder()
.setColor(strings.embeds.color)
.setTitle('Grow A Tree Analyzer Help')
.setDescription(content)
.setFooter({ text: strings.embeds.footer });
const privateBool = private == 'true';
const messageContents = { embeds: [embed], ephemeral: privateBool };
return messageContents;
},
errorEmbed(content) {
const embed = new EmbedBuilder()
.setColor(0xFF0000)
.setTitle('Error!')
.setDescription(content)
.setFooter({ text: strings.embeds.footer });
const messageContents = { embeds: [embed], ephemeral: true };
return messageContents;
},
embed(content) {
const embed = new EmbedBuilder()
.setColor(0x8888FF)
.setTitle('Information')
.setDescription(content)
.setFooter({ text: strings.embeds.footer });
const messageContents = { embeds: [embed], ephemeral: true };
return messageContents;
embeds: {
help(private) {
const embed = new EmbedBuilder()
.setColor(strings.embeds.color)
.setTitle(strings.help.title)
.setDescription(strings.help.content)
.setFooter({ text: strings.help.footer });
return { embeds: [embed] };
},
error(content) {
const embed = new EmbedBuilder()
.setColor(strings.error.color)
.setTitle(strings.error.title)
.setDescription(content)
.setFooter({ text: strings.embeds.footer });
return { embeds: [embed], ephemeral: true };
},
info(content) {
const embed = new EmbedBuilder()
.setColor(strings.embeds.infoColor)
.setTitle(strings.embeds.infoTitle)
.setDescription(content)
.setFooter({ text: strings.embeds.footer });
return { embeds: [embed], ephemeral: true };
}
}
}
};

0
modules/input.txt Normal file
View File

7
package.json Normal file
View File

@ -0,0 +1,7 @@
{
"dependencies": {
"discord.js": "^14.7.1",
"dotenv": "^16.0.3",
"string.prototype.replaceall": "^1.0.7"
}
}

View File

@ -0,0 +1,37 @@
const { SlashCommandBuilder } = require('discord.js');
const fn = require('../modules/functions.js');
const strings = require('../data/strings.json');
module.exports = {
data: new SlashCommandBuilder()
.setName("commands")
.setDescription("View all of the bot's commands")
.addBooleanOption(o =>
o.setName("private")
.setDescription("Should the reply be visible only to you?")
.setRequired(false)
),
id: "", // The command ID, used to generate clickable commands
about: "[meta] View all of the bot's commands", // A description of the command to be used with /commands
async execute(interaction) {
let private = interaction.options.getBoolean('private');
if (private == undefined) {
private = true;
}
// Defer the reply so we have time to do things
await interaction.deferReply({ ephemeral: private }).catch(e => console.error(e));
try {
// Code here...
let commandsParts = ["These are all of the bot's commands, and some information about them:"];
interaction.client.slashCommands.forEach(slashCommand => {
commandsParts.push(`</${slashCommand.data.name}:${(slashCommand.id == "" ? "0" : slashCommand.id)}> - ${slashCommand.about}`);
});
let commandsString = commandsParts.join("\n");
await interaction.editReply(fn.builders.embeds.info(commandsString)).catch(e => console.error(e));
} catch(err) {
// In case of error, log it and let the user know something went wrong
console.error(err);
await interaction.editReply(strings.errors.generalCommand).catch(e => console.error(e));
}
},
};

30
slash-commands/help.js Normal file
View File

@ -0,0 +1,30 @@
const { SlashCommandBuilder } = require('discord.js');
const fn = require('../modules/functions.js');
const strings = require('../data/strings.json');
module.exports = {
data: new SlashCommandBuilder()
.setName("help")
.setDescription("Get some help using the bot")
.addBooleanOption(o =>
o.setName("private")
.setDescription("Should the reply be visible only to you?")
.setRequired(false)
),
id: "", // The command ID, used to generate clickable commands
about: "Get some help using the bot", // A description of the command to be used with /commands
async execute(interaction) {
let private = interaction.options.getBoolean('private');
if (private == undefined) {
private = true;
}
await interaction.deferReply({ ephemeral: private }).catch(e => console.error(e));
try {
await interaction.editReply(fn.builders.embeds.help()).catch(e => console.error(e));
} catch(err) {
// In case of error, log it and let the user know something went wrong
console.error(err);
await interaction.editReply(strings.errors.generalCommand).catch(e => console.error(e));
}
},
};

View File

@ -1,11 +1,31 @@
const { SlashCommandBuilder } = require('discord.js');
const fn = require('../modules/functions.js');
const strings = require('../data/strings.json');
module.exports = {
data: new SlashCommandBuilder()
.setName('')
.setDescription(''),
.setName("")
.setDescription("")
.addBooleanOption(o =>
o.setName("private")
.setDescription("Should the reply be visible only to you?")
.setRequired(false)
),
id: "", // The command ID, used to generate clickable commands
about: "", // A description of the command to be used with /commands
async execute(interaction) {
await
let private = interaction.options.getBoolean('private');
if (private == undefined) {
private = true;
}
// Defer the reply so we have time to do things
await interaction.deferReply({ ephemeral: private }).catch(e => console.error(e));
try {
// Code here...
} catch(err) {
// In case of error, log it and let the user know something went wrong
console.error(err);
await interaction.editReply(strings.errors.generalCommand).catch(e => console.error(e));
}
},
};