From 9c4a2c1e4c87aa40eb8c1b7e9e8ce6449827c583 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 12 Feb 2023 23:51:17 -0500 Subject: [PATCH] Upgrades for a more solid base --- .env | 3 +- data/strings.json | 17 +++++-- main.js | 31 ++++++------- modules/_clear-commands.js | 17 +++---- modules/_deploy-global.js | 17 ++++--- modules/_sanitizeInput.js | 18 ++++++++ modules/functions.js | 94 +++++++++++++++++++------------------- modules/input.txt | 0 package.json | 7 +++ slash-commands/commands.js | 37 +++++++++++++++ slash-commands/help.js | 30 ++++++++++++ slash-commands/template | 26 +++++++++-- 12 files changed, 207 insertions(+), 90 deletions(-) create mode 100644 modules/_sanitizeInput.js create mode 100644 modules/input.txt create mode 100644 package.json create mode 100644 slash-commands/commands.js create mode 100644 slash-commands/help.js diff --git a/.env b/.env index b74db4f..265c551 100644 --- a/.env +++ b/.env @@ -1,3 +1,4 @@ TOKEN= DEBUG=true -CLIENTID= \ No newline at end of file +BOTID= +STATUSCHANNELID= \ No newline at end of file diff --git a/data/strings.json b/data/strings.json index a345d5f..05757af 100644 --- a/data/strings.json +++ b/data/strings.json @@ -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." } } \ No newline at end of file diff --git a/main.js b/main.js index bbdaae2..929b536 100644 --- a/main.js +++ b/main.js @@ -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); \ No newline at end of file diff --git a/modules/_clear-commands.js b/modules/_clear-commands.js index 57b7d64..34ee25d 100644 --- a/modules/_clear-commands.js +++ b/modules/_clear-commands.js @@ -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); diff --git a/modules/_deploy-global.js b/modules/_deploy-global.js index d8e703f..f3c7c92 100644 --- a/modules/_deploy-global.js +++ b/modules/_deploy-global.js @@ -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); diff --git a/modules/_sanitizeInput.js b/modules/_sanitizeInput.js new file mode 100644 index 0000000..1a25698 --- /dev/null +++ b/modules/_sanitizeInput.js @@ -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); \ No newline at end of file diff --git a/modules/functions.js b/modules/functions.js index 4951a0f..2e0ab4d 100644 --- a/modules/functions.js +++ b/modules/functions.js @@ -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 }; + } } } }; diff --git a/modules/input.txt b/modules/input.txt new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json new file mode 100644 index 0000000..1e6381b --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "discord.js": "^14.7.1", + "dotenv": "^16.0.3", + "string.prototype.replaceall": "^1.0.7" + } +} diff --git a/slash-commands/commands.js b/slash-commands/commands.js new file mode 100644 index 0000000..cf5d9f1 --- /dev/null +++ b/slash-commands/commands.js @@ -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.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)); + } + }, +}; \ No newline at end of file diff --git a/slash-commands/help.js b/slash-commands/help.js new file mode 100644 index 0000000..9324c2e --- /dev/null +++ b/slash-commands/help.js @@ -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)); + } + }, +}; \ No newline at end of file diff --git a/slash-commands/template b/slash-commands/template index 774cf03..ceb2de6 100644 --- a/slash-commands/template +++ b/slash-commands/template @@ -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)); + } }, }; \ No newline at end of file