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= TOKEN=
DEBUG=true DEBUG=true
CLIENTID= BOTID=
STATUSCHANNELID=

View File

@ -1,17 +1,24 @@
{ {
"help": { "help": {
"info": "", "title": "Title",
"setup": "", "content": "Some help content",
"permissions": "" "footer": "Witty Text Here"
}, },
"embeds": { "embeds": {
"footer": "", "footer": "github/voidf1sh/discord-bot-template",
"color": "0x55FF55" "color": "0x55FF55",
"errorTitle": "Error",
"errorColor": "0xFF0000",
"infoTitle": "Information",
"infoColor": "0x8888FF"
}, },
"emoji": { "emoji": {
"next": "⏭️", "next": "⏭️",
"previous": "⏮️", "previous": "⏮️",
"confirm": "☑️", "confirm": "☑️",
"cancel": "❌" "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;; const token = process.env.TOKEN;;
// Discord.JS // Discord.JS
const { Client, GatewayIntentBits, Partials } = require('discord.js'); const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({ const client = new Client({
intents: [ intents: [
GatewayIntentBits.Guilds, GatewayIntentBits.Guilds
GatewayIntentBits.GuildMessages, ]
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.MessageContent
],
partials: [
Partials.Channel,
Partials.Message
],
}); });
// Various imports // Various imports
const fn = require('./modules/functions.js'); const fn = require('./modules/functions.js');
const strings = require('./data/strings.json'); const strings = require('./data/strings.json');
const isDev = process.env.DEBUG; const debugMode = process.env.DEBUG;
const statusChannelId = process.env.STATUSCHANNELID const statusChannelId = process.env.STATUSCHANNELID
client.once('ready', () => { client.once('ready', () => {
fn.collections.slashCommands(client); fn.collectionBuilders.slashCommands(client);
console.log('Ready!'); console.log('Ready!');
client.channels.fetch(statusChannelId).then(channel => { // client.channels.fetch(statusChannelId).then(channel => {
channel.send(`${new Date().toISOString()} -- Ready`); // channel.send(`${new Date().toISOString()} -- Ready`).catch(e => console.error(e));
}); // });
}); });
// slash-commands // slash-commands
@ -40,12 +33,16 @@ client.on('interactionCreate', async interaction => {
const { commandName } = interaction; const { commandName } = interaction;
if (client.slashCommands.has(commandName)) { if (client.slashCommands.has(commandName)) {
client.slashCommands.get(commandName).execute(interaction); client.slashCommands.get(commandName).execute(interaction).catch(e => console.error(e));
} else { } 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); console.error('Slash command attempted to run but not found: /' + commandName);
} }
} }
}); });
process.on('uncaughtException', err => {
console.error(err);
});
client.login(token); client.login(token);

View File

@ -2,24 +2,25 @@
const dotenv = require('dotenv'); const dotenv = require('dotenv');
dotenv.config(); dotenv.config();
const { REST } = require('@discordjs/rest'); const { REST, Routes } = require('discord.js');
const { Routes } = require('discord-api-types/v9'); const botId = process.env.BOTID;
const clientId = process.env.clientId;
const { guildId } = require('../data/config.json');
const token = process.env.TOKEN; 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 () => { (async () => {
try { try {
console.log('Started refreshing application (/) commands.'); console.log('Started clearing global application (/) commands.');
await rest.put( await rest.put(
Routes.applicationGuildCommands(clientId, guildId), Routes.applicationCommands(botId),
{ body: '' }, { body: '' },
); );
console.log('Successfully reloaded application (/) commands.'); console.log('Successfully cleared global application (/) commands.');
process.exit(); process.exit();
} catch (error) { } catch (error) {
console.error(error); console.error(error);

View File

@ -2,9 +2,8 @@
const dotenv = require('dotenv'); const dotenv = require('dotenv');
dotenv.config(); dotenv.config();
const { REST } = require('@discordjs/rest'); const { REST, Routes } = require('discord.js');
const { Routes } = require('discord-api-types/v9'); const botId = process.env.BOTID;
const clientId = process.env.CLIENTID;
const token = process.env.TOKEN; const token = process.env.TOKEN;
const fs = require('fs'); const fs = require('fs');
@ -12,26 +11,26 @@ const commands = [];
const commandFiles = fs.readdirSync('./slash-commands').filter(file => file.endsWith('.js')); const commandFiles = fs.readdirSync('./slash-commands').filter(file => file.endsWith('.js'));
for (const file of commandFiles) { for (const file of commandFiles) {
const command = require(`./slash-commands/${file}`); const command = require(`../slash-commands/${file}`);
if (command.data != undefined) { if (command.data != undefined) {
commands.push(command.data.toJSON()); 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 () => { (async () => {
try { try {
console.log('Started refreshing application (/) commands.'); console.log('Started refreshing global application (/) commands.');
await rest.put( await rest.put(
Routes.applicationCommands(clientId), Routes.applicationCommands(botId),
{ body: commands }, { body: commands },
); );
console.log('Successfully reloaded application (/) commands.'); console.log('Successfully reloaded global application (/) commands.');
process.exit(); process.exit();
} catch (error) { } catch (error) {
console.error(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 importing environment variables
// dotenv for handling environment variables
const dotenv = require('dotenv'); const dotenv = require('dotenv');
dotenv.config();
const isDev = process.env.DEBUG;
// filesystem
const fs = require('fs'); const fs = require('fs');
// Configure Environment Variables
dotenv.config();
// Discord.js // Discord.js
const Discord = require('discord.js'); const Discord = require('discord.js');
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord;
// Various imports from other files // Various imports from other files
const debugMode = process.env.DEBUG;
const config = require('../data/config.json'); const config = require('../data/config.json');
const strings = require('../data/strings.json'); const strings = require('../data/strings.json');
const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js'));
const functions = { const functions = {
// Functions for managing and creating Collections // Functions for managing and creating Collections
collections: { collectionBuilders: {
// Create the collection of slash commands // Create the collection of slash commands
slashCommands(client) { slashCommands(client) {
if (!client.slashCommands) client.slashCommands = new Discord.Collection(); if (!client.slashCommands) client.slashCommands = new Discord.Collection();
@ -29,50 +27,52 @@ const functions = {
client.slashCommands.set(slashCommand.data.name, slashCommand); client.slashCommands.set(slashCommand.data.name, slashCommand);
} }
} }
if (isDev) console.log('Slash Commands Collection Built'); if (debugMode) console.log('Slash Commands Collection Built');
} }
}, },
builders: { builders: {
refreshAction() { actionRows: {
example() {
// Create the button to go in the Action Row // Create the button to go in the Action Row
const refreshButton = new ButtonBuilder() const exampleButton = this.buttons.exampleButton();
.setCustomId('refresh')
.setLabel('Refresh')
.setStyle(ButtonStyle.Primary);
// Create the Action Row with the Button in it, to be sent with the Embed // Create the Action Row with the Button in it, to be sent with the Embed
const refreshActionRow = new ActionRowBuilder() return new ActionRowBuilder()
.addComponents( .addComponents(exampleButton);
refreshButton
);
return refreshActionRow;
}, },
helpEmbed(content, private) { buttons: {
exampleButton() {
return new ButtonBuilder()
.setCustomId('id')
.setLabel('Label')
.setStyle(ButtonStyle.Primary);
}
}
},
embeds: {
help(private) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setColor(strings.embeds.color) .setColor(strings.embeds.color)
.setTitle('Grow A Tree Analyzer Help') .setTitle(strings.help.title)
.setDescription(content) .setDescription(strings.help.content)
.setFooter({ text: strings.embeds.footer }); .setFooter({ text: strings.help.footer });
const privateBool = private == 'true'; return { embeds: [embed] };
const messageContents = { embeds: [embed], ephemeral: privateBool };
return messageContents;
}, },
errorEmbed(content) { error(content) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setColor(0xFF0000) .setColor(strings.error.color)
.setTitle('Error!') .setTitle(strings.error.title)
.setDescription(content) .setDescription(content)
.setFooter({ text: strings.embeds.footer }); .setFooter({ text: strings.embeds.footer });
const messageContents = { embeds: [embed], ephemeral: true }; return { embeds: [embed], ephemeral: true };
return messageContents;
}, },
embed(content) { info(content) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setColor(0x8888FF) .setColor(strings.embeds.infoColor)
.setTitle('Information') .setTitle(strings.embeds.infoTitle)
.setDescription(content) .setDescription(content)
.setFooter({ text: strings.embeds.footer }); .setFooter({ text: strings.embeds.footer });
const messageContents = { embeds: [embed], ephemeral: true }; return { embeds: [embed], ephemeral: true };
return messageContents; }
} }
} }
}; };

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 { SlashCommandBuilder } = require('discord.js');
const fn = require('../modules/functions.js'); const fn = require('../modules/functions.js');
const strings = require('../data/strings.json');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('') .setName("")
.setDescription(''), .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) { 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));
}
}, },
}; };