From 1a0817a89c92dcadda01d4afcae87a4d9a9764e7 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 11:54:04 -0400 Subject: [PATCH 01/14] Versioning -- v3.3.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 513ea8b..8fcfff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.3.2", + "version": "3.3.3", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From 23f081c6c1d82e597786047d8759391e4dd89e39 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 11:54:33 -0400 Subject: [PATCH 02/14] Move CommandData and checkCommand to NodBot Classes --- CustomModules/NodBot.js | 18 ++++++++++++++++++ functions.js | 33 +++------------------------------ 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index 2d5ff83..24efec3 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -1,4 +1,22 @@ module.exports = { + CommandData: class { + constructor(message) { + // Get the location of the final period in the message + this.finalPeriod = message.content.lastIndexOf('.'); + this.isCommand = finalPeriod >= 0 ? true : false; // Check if there is a period somewhere in the message to flag as a possible command + this.args = message.content.slice(0,finalPeriod).toLowerCase(); // Grab everything leading up to the final period + this.command = message.content.slice(finalPeriod + 1).toLowerCase(); // Grab everything after the final period + this.author = message.author.username; + + return this; + } + + isValid(validCommands) { + if (this.args.startsWith('http')) return false; + if (this.args.startsWith('www')) return false; + return validCommands.includes(this.command); + } + }, GifData: class { constructor() { this.id = 0; diff --git a/functions.js b/functions.js index d6b12dd..7a27238 100644 --- a/functions.js +++ b/functions.js @@ -34,6 +34,7 @@ const config = require('./config.json'); const strings = require('./strings.json'); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js')); +const { CommandData } = require('./CustomModules/NodBot.js'); // MySQL database connection const mysql = require('mysql'); @@ -172,36 +173,8 @@ const functions = { }, dot: { getCommandData(message) { - const commandData = {}; - // Split the message content at the final instance of a period - const finalPeriod = message.content.lastIndexOf('.'); - // if(isDev) console.log(message.content); - // If the final period is the last character, or doesn't exist - if (finalPeriod < 0) { - if (isDev) console.log(finalPeriod); - commandData.isCommand = false; - return commandData; - } - commandData.isCommand = true; - // Get the first part of the message, everything leading up to the final period - commandData.args = message.content.slice(0,finalPeriod).toLowerCase(); - // Get the last part of the message, everything after the final period - commandData.command = message.content.slice(finalPeriod + 1).toLowerCase(); - commandData.author = `${message.author.username}`; - return this.checkCommand(commandData); - }, - checkCommand(commandData) { - if (commandData.isCommand) { - const validCommands = require('./config.json').validCommands; - commandData.isValid = validCommands.includes(commandData.command); - // Add exceptions for messages that contain only a link - if (commandData.args.startsWith('http')) commandData.isValid = false; - } - else { - commandData.isValid = false; - console.error('Somehow a non-command made it to checkCommands()'); - } - return commandData; + const commandData = new CommandData(message); + return commandData.isValid(require('./config.json').validCommands); } }, embeds: { From 00df6074d6eb4c8ec477764ca1230873e01b19d5 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 15:30:51 -0400 Subject: [PATCH 03/14] Fixed duplication of valid commands --- CustomModules/NodBot.js | 24 +++++++++++++++++++----- functions.js | 18 ++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index 24efec3..ac29c41 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -3,18 +3,32 @@ module.exports = { constructor(message) { // Get the location of the final period in the message this.finalPeriod = message.content.lastIndexOf('.'); - this.isCommand = finalPeriod >= 0 ? true : false; // Check if there is a period somewhere in the message to flag as a possible command - this.args = message.content.slice(0,finalPeriod).toLowerCase(); // Grab everything leading up to the final period - this.command = message.content.slice(finalPeriod + 1).toLowerCase(); // Grab everything after the final period + this.isCommand = this.finalPeriod >= 0 ? true : false; // Check if there is a period somewhere in the message to flag as a possible command + this.isValid = false; + this.args = message.content.slice(0,this.finalPeriod).toLowerCase(); // Grab everything leading up to the final period + this.command = message.content.slice(this.finalPeriod + 1).toLowerCase(); // Grab everything after the final period this.author = message.author.username; return this; } - isValid(validCommands) { + validate(dotCommands) { if (this.args.startsWith('http')) return false; if (this.args.startsWith('www')) return false; - return validCommands.includes(this.command); + + for (const [key, value] of dotCommands) { + if (key === this.command) { + this.isValid = true; + return this.isValid; + } else if (value.alias && value.alias.includes(this.command)) { + this.command = key; + this.isValid = true; + return this.isValid; + } + } + + this.isValid = validCommands.includes(this.command); + return this.isValid; } }, GifData: class { diff --git a/functions.js b/functions.js index 7a27238..eeaeb3f 100644 --- a/functions.js +++ b/functions.js @@ -82,13 +82,13 @@ const functions = { for (const file of dotCommandFiles) { const dotCommand = require(`./dot-commands/${file}`); client.dotCommands.set(dotCommand.name, dotCommand); - if (Array.isArray(dotCommand.alias)) { - dotCommand.alias.forEach(element => { - client.dotCommands.set(element, dotCommand); - }); - } else if (dotCommand.alias != undefined) { - client.dotCommands.set(dotCommand.alias, dotCommand); - } + // if (Array.isArray(dotCommand.alias)) { + // dotCommand.alias.forEach(element => { + // client.dotCommands.set(element, dotCommand); + // }); + // } else if (dotCommand.alias != undefined) { + // client.dotCommands.set(dotCommand.alias, dotCommand); + // } } if (isDev) console.log('Dot Commands Collection Built'); }, @@ -174,7 +174,9 @@ const functions = { dot: { getCommandData(message) { const commandData = new CommandData(message); - return commandData.isValid(require('./config.json').validCommands); + const { validCommands } = require('./config.json'); + commandData.validate(message.client.dotCommands); + return commandData; } }, embeds: { From ecbfc2bc2aad2d01eef0b3cb68b39938c6fcb890 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 15:35:01 -0400 Subject: [PATCH 04/14] Remove unnecessary function calls now that classes exist --- CustomModules/NodBot.js | 6 +++--- functions.js | 8 -------- main.js | 4 ++-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index ac29c41..2d2ed16 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -19,16 +19,16 @@ module.exports = { for (const [key, value] of dotCommands) { if (key === this.command) { this.isValid = true; - return this.isValid; + return this; } else if (value.alias && value.alias.includes(this.command)) { this.command = key; this.isValid = true; - return this.isValid; + return this; } } this.isValid = validCommands.includes(this.command); - return this.isValid; + return this; } }, GifData: class { diff --git a/functions.js b/functions.js index eeaeb3f..608848d 100644 --- a/functions.js +++ b/functions.js @@ -171,14 +171,6 @@ const functions = { if (isDev) console.log('Medical Advice Collection Built'); } }, - dot: { - getCommandData(message) { - const commandData = new CommandData(message); - const { validCommands } = require('./config.json'); - commandData.validate(message.client.dotCommands); - return commandData; - } - }, embeds: { help(interaction) { // Construct the Help Embed diff --git a/main.js b/main.js index 55a347c..2493676 100644 --- a/main.js +++ b/main.js @@ -27,7 +27,7 @@ const { MessageActionRow, MessageButton } = require('discord.js'); const fn = require('./functions.js'); const config = require('./config.json'); const strings = require('./strings.json'); -const { GifData } = require('./CustomModules/NodBot.js'); +const { GifData, CommandData } = require('./CustomModules/NodBot.js'); const isDev = process.env.isDev; client.once('ready', async () => { @@ -232,7 +232,7 @@ client.on('messageCreate', message => { }); // Break the message down into its components and analyze it - const commandData = fn.dot.getCommandData(message); + const commandData = new CommandData(message).validate(message.client.dotCommands); console.log(commandData); if (commandData.isValid && commandData.isCommand) { From be83b9ea749e6d788cf118478766754335ce2d92 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 18:56:33 -0400 Subject: [PATCH 05/14] WIP --- CustomModules/Embeds.js | 28 ++++++++++++++++++++++++++++ slash-commands/save.js | 12 ++---------- 2 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 CustomModules/Embeds.js diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js new file mode 100644 index 0000000..6335690 --- /dev/null +++ b/CustomModules/Embeds.js @@ -0,0 +1,28 @@ +module.exports = { + gifSearchAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevGif') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const confirmButton = new MessageButton() + .setCustomId('confirmGif') + .setLabel('✅') + .setStyle('PRIMARY'); + + const nextButton = new MessageButton() + .setCustomId('nextGif') + .setLabel('➡️') + .setStyle('SECONDARY'); + + const cancelButton = new MessageButton() + .setCustomId('cancelGif') + .setLabel('❌') + .setStyle('DANGER'); + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, confirmButton, nextButton, cancelButton); + } +} \ No newline at end of file diff --git a/slash-commands/save.js b/slash-commands/save.js index b47b05d..28f7533 100644 --- a/slash-commands/save.js +++ b/slash-commands/save.js @@ -11,6 +11,7 @@ const { MessageActionRow, MessageButton } = require('discord.js'); const fn = require('../functions.js'); const strings = require('../strings.json'); const { GifData } = require('../CustomModules/NodBot.js'); +const customEmbeds = require('../CustomModules/Embeds.js'); const { emoji } = strings; module.exports = { @@ -142,16 +143,7 @@ module.exports = { // GIF Search case "gifsearch": // TODO Check on option names - // Previous GIF button - const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled(true); - // Confirm GIF Button - const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY'); - // Next GIF Button - const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY'); - // Cancel Button - const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER'); - // Put all the above into an ActionRow to be sent as a component of the reply - const actionRow = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton); + const actionRow = customEmbeds.gifSearchAR(); // Get the query const query = interaction.options.getString('query'); From 8e5931e0d49d419b8c78889753ce67b75d3fc257 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 23:22:22 -0400 Subject: [PATCH 06/14] Working on storing interaction data in the client --- CustomModules/ButtonHandlers.js | 22 ++++++++ CustomModules/Embeds.js | 81 ++++++++++++++++++++++++++++- CustomModules/Indexer.js | 31 +++++++++++ CustomModules/InteractionStorage.js | 15 ++++++ CustomModules/NodBot.js | 2 - functions.js | 22 ++++---- main.js | 12 ++++- slash-commands/gifs.js | 43 +++++++-------- 8 files changed, 188 insertions(+), 40 deletions(-) create mode 100644 CustomModules/ButtonHandlers.js create mode 100644 CustomModules/Indexer.js create mode 100644 CustomModules/InteractionStorage.js diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js new file mode 100644 index 0000000..a9cfa6c --- /dev/null +++ b/CustomModules/ButtonHandlers.js @@ -0,0 +1,22 @@ +const customEmbeds = require('../CustomModules/Embeds.js'); + +module.exports = { + baseEvent(interaction) { + console.log(interaction.component.customId); + switch (interaction.component.customId) { + // Any of the gifsPage Buttons + case 'prevGifsPage' || 'nextGifsPage' : + break; + default: + return; + } + }, + gifsPage(interaction, gifs, page) { + switch (buttonId) { + case 'prevGifsPage': + return 'previous'; + case 'nextGifsPage': + return 'next'; + } + } +} \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index 6335690..cc057da 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -1,5 +1,7 @@ +const { MessageActionRow, MessageButton } = require('discord.js'); + module.exports = { - gifSearchAR() { + gifSearchAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevGif') @@ -21,6 +23,83 @@ module.exports = { .setLabel('❌') .setStyle('DANGER'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, confirmButton, nextButton, cancelButton); + }, + gifsPageAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevGifsPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const nextButton = new MessageButton() + .setCustomId('nextGifsPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, nextButton); + }, + requestsPageAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevRequestsPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const confirmButton = new MessageButton() + .setCustomId('confirmRequestsPage') + .setLabel('✅') + .setStyle('PRIMARY'); + + const nextButton = new MessageButton() + .setCustomId('nextRequestsPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + const cancelButton = new MessageButton() + .setCustomId('cancelRequestsPage') + .setLabel('❌') + .setStyle('DANGER'); + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, confirmButton, nextButton, cancelButton); + }, + pastasPageAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevPastasPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const confirmButton = new MessageButton() + .setCustomId('confirmPastasPage') + .setLabel('✅') + .setStyle('PRIMARY'); + + const nextButton = new MessageButton() + .setCustomId('nextPastasPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + const cancelButton = new MessageButton() + .setCustomId('cancelPastasPage') + .setLabel('❌') + .setStyle('DANGER'); + // Put the buttons into an ActionRow return new MessageActionRow() .addComponents(previousButton, confirmButton, nextButton, cancelButton); diff --git a/CustomModules/Indexer.js b/CustomModules/Indexer.js new file mode 100644 index 0000000..8a3960f --- /dev/null +++ b/CustomModules/Indexer.js @@ -0,0 +1,31 @@ +module.exports = (collection, page) => { + const itemsPerPage = 10; + const index = page * itemsPerPage; + const totalPages = Math.ceil(collection.size / itemsPerPage); + let state = page === 0 ? 'first' : 'middle'; + + const thisPage = new Array(); + + // Map the Djs Collection to an Array + const collectionArray = collection.map((command) => command); + + for (let i = index; i < index + itemsPerPage; i++) { + if (collectionArray[i]) { + thisPage.push(collectionArray[i]); + } else { + state = 'last'; + break; + } + + if (i === collectionArray.size - 1) { + state = 'last'; + break; + } + } + + return { + state: state, + thisPage: thisPage, + pages: `Page ${page + 1}/${totalPages}` + }; +} \ No newline at end of file diff --git a/CustomModules/InteractionStorage.js b/CustomModules/InteractionStorage.js new file mode 100644 index 0000000..d5cf06a --- /dev/null +++ b/CustomModules/InteractionStorage.js @@ -0,0 +1,15 @@ +module.exports = class InteractionStorage { + constructor(idString, interaction) { + this.idString = idString; + + // Store in the client + interaction.client.iStorage.set(idString, this); + + // Delete this from the interactionStorage after 5 minutes + setTimeout(() => { + interaction.client.iStorage.delete(idString); + }, 300000); + + return this; + } +} \ No newline at end of file diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index 2d2ed16..d18c21b 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -26,8 +26,6 @@ module.exports = { return this; } } - - this.isValid = validCommands.includes(this.command); return this; } }, diff --git a/functions.js b/functions.js index 608848d..15a5e5a 100644 --- a/functions.js +++ b/functions.js @@ -1,7 +1,6 @@ /* eslint-disable comma-dangle */ // dotenv for handling environment variables -const dotenv = require('dotenv'); -dotenv.config(); +const dotenv = require('dotenv').config(); // Assignment of environment variables for database access const dbHost = process.env.dbHost; const dbUser = process.env.dbUser; @@ -9,7 +8,6 @@ const dbName = process.env.dbName; const dbPass = process.env.dbPass; const dbPort = process.env.dbPort; const isDev = process.env.isDev; - const ownerId = process.env.ownerId; // filesystem @@ -22,10 +20,6 @@ const Discord = require('discord.js'); // Fuzzy text matching for db lookups const FuzzySearch = require('fuzzy-search'); -// OpenAI -// const OpenAI = require("openai"); -// const openai = new OpenAI(); - // Axios for APIs const axios = require('axios'); @@ -34,7 +28,7 @@ const config = require('./config.json'); const strings = require('./strings.json'); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js')); -const { CommandData } = require('./CustomModules/NodBot.js'); +const customEmbeds = require('./CustomModules/Embeds.js'); // MySQL database connection const mysql = require('mysql'); @@ -51,6 +45,11 @@ const db = new mysql.createPool({ const functions = { // Functions for managing and creating Collections collections: { + interactionStorage(client) { + if (!client.iStorage) client.iStorage = new Discord.Collection(); + client.iStorage.clear(); + if (isDev) console.log('Interaction Storage Collection Built'); + } // Create the collection of slash commands slashCommands(client) { if (!client.slashCommands) client.slashCommands = new Discord.Collection(); @@ -268,14 +267,15 @@ const functions = { return { embeds: [pastasEmbed], ephemeral: true }; }, - gifs(commandData, gifList) { + gifs(commandData, gifsString, state) { const gifsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() .setFooter({text: commandData.author}) - .setDescription(gifList.join('\n')); + .setDescription(gifsString); - return { embeds: [gifsEmbed] }; + const gifsPageAR = customEmbeds.gifsPageAR(state); + return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true }; }, text(commandData) { return { embeds: [new Discord.MessageEmbed() diff --git a/main.js b/main.js index 2493676..304c7be 100644 --- a/main.js +++ b/main.js @@ -28,9 +28,12 @@ const fn = require('./functions.js'); const config = require('./config.json'); const strings = require('./strings.json'); const { GifData, CommandData } = require('./CustomModules/NodBot.js'); +const ButtonHandlers = require('./CustomModules/ButtonHandlers.js'); +const InteractionStorage = require('./CustomModules/InteractionStorage.js'); const isDev = process.env.isDev; client.once('ready', async () => { + fn.collections.interactionStorage(client); fn.collections.slashCommands(client); fn.collections.dotCommands(client); fn.collections.setvalidCommands(client); @@ -58,6 +61,12 @@ client.on('interactionCreate', async interaction => { } const { commandName } = interaction; + const idString = `${interaction.channelId}${interaction.member.id}`; + + if (!client.interactionStorage.has(idString)) { + new InteractionStorage(idString, interaction); + } + if (client.slashCommands.has(commandName)) { client.slashCommands.get(commandName).execute(interaction); } else { @@ -67,7 +76,7 @@ client.on('interactionCreate', async interaction => { } if (interaction.isButton()) { - if (interaction.user.id != strings.temp.gifUserId) return; + if (isDev) console.log(interaction.id); // Get some meta info from strings const index = strings.temp.gifIndex; const limit = strings.temp.gifLimit; @@ -176,6 +185,7 @@ client.on('interactionCreate', async interaction => { interaction.update({ content: 'Canceled.', components: [row] }); break; default: + ButtonHandlers.baseEvent(interaction); break; } } diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 0409968..00a30f0 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -1,36 +1,29 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { config } = require('dotenv'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() .setName('gifs') .setDescription('Get a list of currently saved GIFs.'), - async execute(interaction) { - if (!interaction.client.gifs) { - interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); - return; - } - // const gifsMap = interaction.client.gifs.map(e => {e.name, e.url}); - // const commandData = { - // gifs: [], - // command: 'gifs', - // author: interaction.user.tag, - // }; - // for (const row of gifsMap) { - // commandData.gifs.push({ - // id: row.id, - // name: row.name, - // }); - // } - let gifList = []; - interaction.client.gifs.forEach(element => { - gifList.push(`[${element.name}](${element.url})`); + execute(interaction) { + return new Promise((resolve, reject) => { + if (!interaction.client.gifs) { + interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); + resolve(); + } + let gifList = indexer(interaction.client.gifs, 0); + let gifsString = new String(); + + for (const gif of gifList.thisPage) { + gifsString += `[${gif.name}.gif](${gif.url})\n`; + } + const commandData = { + command: "/gifs", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.gifs(commandData, gifsString, gifList.state)); }); - const commandData = { - command: "/gifs", - author: interaction.member.displayName - }; - interaction.reply(fn.embeds.gifs(commandData, gifList)); }, }; \ No newline at end of file From 7aa3d5d0a1e44e3f3f8cf83b96e582b9b7b70d7e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:09:09 -0400 Subject: [PATCH 07/14] MVP for Paged /gifs Browser --- CustomModules/ButtonHandlers.js | 49 ++++++++++++++++++++++++----- CustomModules/Embeds.js | 11 ++++++- CustomModules/Indexer.js | 3 +- CustomModules/InteractionStorage.js | 1 + functions.js | 42 +++---------------------- main.js | 11 +++---- slash-commands/gifs.js | 13 +++++--- 7 files changed, 72 insertions(+), 58 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index a9cfa6c..4e9011f 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -1,22 +1,55 @@ const customEmbeds = require('../CustomModules/Embeds.js'); +const InteractionStorage = require('../CustomModules/InteractionStorage.js'); +const indexer = require('../CustomModules/Indexer.js'); +const fn = require('../functions.js'); module.exports = { baseEvent(interaction) { - console.log(interaction.component.customId); switch (interaction.component.customId) { // Any of the gifsPage Buttons - case 'prevGifsPage' || 'nextGifsPage' : + case 'prevGifsPage': + module.exports.gifsPage(interaction); + break; + case 'nextGifsPage': + module.exports.gifsPage(interaction); break; default: return; } }, - gifsPage(interaction, gifs, page) { - switch (buttonId) { - case 'prevGifsPage': - return 'previous'; - case 'nextGifsPage': - return 'next'; + gifsPage(interaction) { + let iStorage; + if (interaction.client.iStorage.has(interaction.message.interaction.id)) { + iStorage = interaction.client.iStorage.get(interaction.message.interaction.id) + } else { + iStorage = new InteractionStorage(interaction.message.interaction.id, interaction); + iStorage.page = 0; } + console.log('Beginning Page: ' + iStorage.page); + + switch (interaction.component.customId) { + case 'prevGifsPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextGifsPage': + if (iStorage.page < interaction.client.gifs.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedGifs = indexer(interaction.client.gifs, iStorage.page); + indexedGifs.gifsString = new String(); + + for (const gif of indexedGifs.thisPage) { + indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; + } + + console.log('Ending Page: ' + iStorage.page); + + interaction.update(fn.embeds.gifs({command: "/gifs", author: interaction.member.displayName}, indexedGifs)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index cc057da..bbb9bb3 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -36,7 +36,7 @@ module.exports = { return new MessageActionRow() .addComponents(previousButton, confirmButton, nextButton, cancelButton); }, - gifsPageAR() { + gifsPageAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevGifsPage') @@ -48,6 +48,15 @@ module.exports = { .setLabel('➡️') .setStyle('SECONDARY'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } + // Put the buttons into an ActionRow return new MessageActionRow() .addComponents(previousButton, nextButton); diff --git a/CustomModules/Indexer.js b/CustomModules/Indexer.js index 8a3960f..dacb3bb 100644 --- a/CustomModules/Indexer.js +++ b/CustomModules/Indexer.js @@ -26,6 +26,7 @@ module.exports = (collection, page) => { return { state: state, thisPage: thisPage, - pages: `Page ${page + 1}/${totalPages}` + totalPages: totalPages, + pagesString: `${page + 1}/${totalPages}` }; } \ No newline at end of file diff --git a/CustomModules/InteractionStorage.js b/CustomModules/InteractionStorage.js index d5cf06a..e1ace19 100644 --- a/CustomModules/InteractionStorage.js +++ b/CustomModules/InteractionStorage.js @@ -7,6 +7,7 @@ module.exports = class InteractionStorage { // Delete this from the interactionStorage after 5 minutes setTimeout(() => { + console.log(`Deleting interactionStorage with id: ${idString}`); interaction.client.iStorage.delete(idString); }, 300000); diff --git a/functions.js b/functions.js index 15a5e5a..f2e2507 100644 --- a/functions.js +++ b/functions.js @@ -49,7 +49,7 @@ const functions = { if (!client.iStorage) client.iStorage = new Discord.Collection(); client.iStorage.clear(); if (isDev) console.log('Interaction Storage Collection Built'); - } + }, // Create the collection of slash commands slashCommands(client) { if (!client.slashCommands) client.slashCommands = new Discord.Collection(); @@ -267,14 +267,14 @@ const functions = { return { embeds: [pastasEmbed], ephemeral: true }; }, - gifs(commandData, gifsString, state) { + gifs(commandData, indexedGifs) { const gifsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter({text: commandData.author}) - .setDescription(gifsString); + .setFooter({text: `Page: ${indexedGifs.pagesString}`}) + .setDescription(indexedGifs.gifsString); - const gifsPageAR = customEmbeds.gifsPageAR(state); + const gifsPageAR = customEmbeds.gifsPageAR(indexedGifs.state); return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true }; }, text(commandData) { @@ -599,38 +599,6 @@ const functions = { } } }, - openAI: { - chatPrompt(userPrompt) { - return new Promise(async (resolve, reject) => { - const response = await openai.chat.completions.create({ - messages: [{ - role: 'user', - content: userPrompt - }], - model: strings.ai.chatModel - }).catch(e => { - reject(e); - return null; - }); - resolve(response); - }); - }, - imagePrompt(userPrompt, size, userId) { - return new Promise(async (resolve, reject) => { - try { - const response = await openai.createImage({ - prompt: userPrompt, - size: size, - user: userId - }); - resolve(response.data.data[0].url); - } catch (e) { - reject(e); - return; - } - }); - } - }, search: { gifs(query, client) { const gifSearcher = new FuzzySearch(client.gifs.map(element => element.name)); diff --git a/main.js b/main.js index 304c7be..147f500 100644 --- a/main.js +++ b/main.js @@ -57,14 +57,12 @@ client.once('ready', async () => { client.on('interactionCreate', async interaction => { if (interaction.isCommand()) { if (isDev) { - console.log(interaction); + console.log('Interaction ID: ' + interaction.id); } const { commandName } = interaction; - const idString = `${interaction.channelId}${interaction.member.id}`; - - if (!client.interactionStorage.has(idString)) { - new InteractionStorage(idString, interaction); + if (!client.iStorage.has(interaction.id)) { + new InteractionStorage(interaction.id, interaction); } if (client.slashCommands.has(commandName)) { @@ -76,7 +74,8 @@ client.on('interactionCreate', async interaction => { } if (interaction.isButton()) { - if (isDev) console.log(interaction.id); + if (isDev) console.log('Origin Interaction ID: ' + interaction.message.interaction.id); + if (isDev) console.log('Button ID: ' + interaction.component.customId); // Get some meta info from strings const index = strings.temp.gifIndex; const limit = strings.temp.gifLimit; diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 00a30f0..51d1d9d 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -13,17 +13,20 @@ module.exports = { interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); resolve(); } - let gifList = indexer(interaction.client.gifs, 0); - let gifsString = new String(); + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedGifs = indexer(interaction.client.gifs, 0); + indexedGifs.gifsString = new String(); - for (const gif of gifList.thisPage) { - gifsString += `[${gif.name}.gif](${gif.url})\n`; + iStorage.page = 0; + + for (const gif of indexedGifs.thisPage) { + indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; } const commandData = { command: "/gifs", author: interaction.member.displayName }; - interaction.reply(fn.embeds.gifs(commandData, gifsString, gifList.state)); + interaction.reply(fn.embeds.gifs(commandData, indexedGifs)); }); }, }; \ No newline at end of file From 709c8cfab7037ee494e9296a2438b0aaac338563 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:27:11 -0400 Subject: [PATCH 08/14] MVP for paged /pastas --- CustomModules/ButtonHandlers.js | 51 +++++++++++++++++++++++------ CustomModules/Embeds.js | 21 ++++++------ CustomModules/InteractionStorage.js | 1 + functions.js | 16 +++------ slash-commands/gifs.js | 36 ++++++++++---------- slash-commands/pastas.js | 31 ++++++++---------- 6 files changed, 88 insertions(+), 68 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index 4e9011f..d0682b8 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -5,6 +5,14 @@ const fn = require('../functions.js'); module.exports = { baseEvent(interaction) { + let iStorage; + if (interaction.client.iStorage.has(interaction.message.interaction.id)) { + iStorage = interaction.client.iStorage.get(interaction.message.interaction.id) + } else { + iStorage = new InteractionStorage(interaction.message.interaction.id, interaction); + iStorage.page = 0; + } + if (interaction.user.id !== iStorage.userId) return; switch (interaction.component.customId) { // Any of the gifsPage Buttons case 'prevGifsPage': @@ -13,19 +21,18 @@ module.exports = { case 'nextGifsPage': module.exports.gifsPage(interaction); break; + case 'prevPastasPage': + module.exports.pastasPage(interaction); + break; + case 'nextPastasPage': + module.exports.pastasPage(interaction); + break; default: return; } }, gifsPage(interaction) { - let iStorage; - if (interaction.client.iStorage.has(interaction.message.interaction.id)) { - iStorage = interaction.client.iStorage.get(interaction.message.interaction.id) - } else { - iStorage = new InteractionStorage(interaction.message.interaction.id, interaction); - iStorage.page = 0; - } - console.log('Beginning Page: ' + iStorage.page); + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); switch (interaction.component.customId) { case 'prevGifsPage': @@ -48,8 +55,32 @@ module.exports = { indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; } - console.log('Ending Page: ' + iStorage.page); - interaction.update(fn.embeds.gifs({command: "/gifs", author: interaction.member.displayName}, indexedGifs)); + }, + pastasPage(interaction) { + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); + + switch (interaction.component.customId) { + case 'prevPastasPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextPastasPage': + if (iStorage.page < interaction.client.pastas.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedPastas = indexer(interaction.client.pastas, iStorage.page); + indexedPastas.pastasString = new String(); + + for (const pasta of indexedPastas.thisPage) { + indexedPastas.pastasString += `${pasta.name}.pasta\n`; + } + + interaction.update(fn.embeds.pastas({command: "/pastas", author: interaction.member.displayName}, indexedPastas)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index bbb9bb3..036eb9b 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -87,30 +87,29 @@ module.exports = { return new MessageActionRow() .addComponents(previousButton, confirmButton, nextButton, cancelButton); }, - pastasPageAR() { + pastasPageAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevPastasPage') .setLabel('⬅️') .setStyle('SECONDARY'); - const confirmButton = new MessageButton() - .setCustomId('confirmPastasPage') - .setLabel('✅') - .setStyle('PRIMARY'); - const nextButton = new MessageButton() .setCustomId('nextPastasPage') .setLabel('➡️') .setStyle('SECONDARY'); - const cancelButton = new MessageButton() - .setCustomId('cancelPastasPage') - .setLabel('❌') - .setStyle('DANGER'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } // Put the buttons into an ActionRow return new MessageActionRow() - .addComponents(previousButton, confirmButton, nextButton, cancelButton); + .addComponents(previousButton, nextButton); } } \ No newline at end of file diff --git a/CustomModules/InteractionStorage.js b/CustomModules/InteractionStorage.js index e1ace19..6103ecd 100644 --- a/CustomModules/InteractionStorage.js +++ b/CustomModules/InteractionStorage.js @@ -1,6 +1,7 @@ module.exports = class InteractionStorage { constructor(idString, interaction) { this.idString = idString; + this.userId = interaction.user.id; // Store in the client interaction.client.iStorage.set(idString, this); diff --git a/functions.js b/functions.js index f2e2507..7099c30 100644 --- a/functions.js +++ b/functions.js @@ -251,21 +251,15 @@ const functions = { .setTimestamp() .setFooter({text: commandData.author})]}; }, - pastas(commandData) { - const pastasArray = []; + pastas(commandData, indexedPastas) { const pastasEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter({text: commandData.author}); + .setFooter({text: `Page: ${indexedPastas.pagesString}`}) + .setDescription(indexedPastas.pastasString); - for (const row of commandData.pastas) { - pastasArray.push(`#${row.id} - ${row.name}.pasta`); - } - - const pastasString = pastasArray.join('\n'); - pastasEmbed.setDescription(pastasString); - - return { embeds: [pastasEmbed], ephemeral: true }; + const pastasPageAR = customEmbeds.pastasPageAR(indexedPastas.state); + return { embeds: [pastasEmbed], components: [pastasPageAR], ephemeral: true }; }, gifs(commandData, indexedGifs) { const gifsEmbed = new Discord.MessageEmbed() diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 51d1d9d..c372cc0 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -8,25 +8,23 @@ module.exports = { .setName('gifs') .setDescription('Get a list of currently saved GIFs.'), execute(interaction) { - return new Promise((resolve, reject) => { - if (!interaction.client.gifs) { - interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); - resolve(); - } - let iStorage = interaction.client.iStorage.get(interaction.id); - let indexedGifs = indexer(interaction.client.gifs, 0); - indexedGifs.gifsString = new String(); + if (!interaction.client.gifs) { + interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); + return; + } + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedGifs = indexer(interaction.client.gifs, 0); + indexedGifs.gifsString = new String(); - iStorage.page = 0; + iStorage.page = 0; - for (const gif of indexedGifs.thisPage) { - indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; - } - const commandData = { - command: "/gifs", - author: interaction.member.displayName - }; - interaction.reply(fn.embeds.gifs(commandData, indexedGifs)); - }); - }, + for (const gif of indexedGifs.thisPage) { + indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; + } + const commandData = { + command: "/gifs", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.gifs(commandData, indexedGifs)); + } }; \ No newline at end of file diff --git a/slash-commands/pastas.js b/slash-commands/pastas.js index baeb52d..8d43578 100644 --- a/slash-commands/pastas.js +++ b/slash-commands/pastas.js @@ -1,6 +1,7 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { config } = require('dotenv'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() @@ -11,23 +12,19 @@ module.exports = { interaction.reply({ content: 'For some reason I don\'t have access to the collection of copypastas. Sorry about that!', ephemeral: true }); return; } - const commandData = { - author: interaction.user.tag, - command: interaction.commandName, - pastas: [], - }; - const pastasMap = interaction.client.pastas.map(e => { - return { - id: e.id, - name: e.name, - }; - }); - for (const row of pastasMap) { - commandData.pastas.push({ - id: row.id, - name: row.name, - }); + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedPastas = indexer(interaction.client.pastas, 0); + indexedPastas.pastasString = new String(); + + iStorage.page = 0; + + for (const pasta of indexedPastas.thisPage) { + indexedPastas.pastasString += `${pasta.name}.pasta\n`; } - interaction.reply(fn.embeds.pastas(commandData)); + const commandData = { + command: "/pastas", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.pastas(commandData, indexedPastas)); }, }; \ No newline at end of file From c3fa30ea649440b20585ea74cb7e2614d0c1bf13 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:37:16 -0400 Subject: [PATCH 09/14] MVP for paged /requests --- CustomModules/ButtonHandlers.js | 33 +++++++++++++++++++++++ CustomModules/Embeds.js | 21 +++++++-------- functions.js | 19 ++++--------- slash-commands/requests.js | 48 ++++++++++++++------------------- 4 files changed, 68 insertions(+), 53 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index d0682b8..f28b878 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -2,6 +2,7 @@ const customEmbeds = require('../CustomModules/Embeds.js'); const InteractionStorage = require('../CustomModules/InteractionStorage.js'); const indexer = require('../CustomModules/Indexer.js'); const fn = require('../functions.js'); +const requests = require('../slash-commands/requests.js'); module.exports = { baseEvent(interaction) { @@ -27,6 +28,12 @@ module.exports = { case 'nextPastasPage': module.exports.pastasPage(interaction); break; + case 'prevRequestsPage': + module.exports.requestsPage(interaction); + break; + case 'nextRequestsPage': + module.exports.requestsPage(interaction); + break; default: return; } @@ -82,5 +89,31 @@ module.exports = { } interaction.update(fn.embeds.pastas({command: "/pastas", author: interaction.member.displayName}, indexedPastas)); + }, + requestsPage(interaction) { + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); + + switch (interaction.component.customId) { + case 'prevRequestsPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextRequestsPage': + if (iStorage.page < interaction.client.requests.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedRequests = indexer(interaction.client.requests, iStorage.page); + indexedRequests.requestsString = new String(); + + for (const request of indexedRequests.thisPage) { + indexedRequests.requestsString += `[${request.id}]: ${request.request} (submitted by ${request.author})\n`; + } + + interaction.update(fn.embeds.requests({command: "/requests", author: interaction.member.displayName}, indexedRequests)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index 036eb9b..3264174 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -61,31 +61,30 @@ module.exports = { return new MessageActionRow() .addComponents(previousButton, nextButton); }, - requestsPageAR() { + requestsPageAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevRequestsPage') .setLabel('⬅️') .setStyle('SECONDARY'); - const confirmButton = new MessageButton() - .setCustomId('confirmRequestsPage') - .setLabel('✅') - .setStyle('PRIMARY'); - const nextButton = new MessageButton() .setCustomId('nextRequestsPage') .setLabel('➡️') .setStyle('SECONDARY'); - const cancelButton = new MessageButton() - .setCustomId('cancelRequestsPage') - .setLabel('❌') - .setStyle('DANGER'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } // Put the buttons into an ActionRow return new MessageActionRow() - .addComponents(previousButton, confirmButton, nextButton, cancelButton); + .addComponents(previousButton, nextButton); }, pastasPageAR(state) { // Setup the buttons diff --git a/functions.js b/functions.js index 7099c30..15b8caa 100644 --- a/functions.js +++ b/functions.js @@ -278,24 +278,15 @@ const functions = { .setTimestamp() .setFooter({text: commandData.author})]}; }, - requests(commandData) { + requests(commandData, indexedRequests) { const requestsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter({text: commandData.author}); + .setFooter({text: `Page: ${indexedRequests.pagesString}`}) + .setDescription(indexedRequests.requestsString); - const requestsArray = []; - - for (const row of commandData.requests) { - requestsArray.push( - `**#${row.id} - ${row.author}**`, - `Request: ${row.request}` - ); - } - - requestsEmbed.setDescription(requestsArray.join('\n')); - - return { embeds: [requestsEmbed], ephemeral: true }; + const requestsPageAR = customEmbeds.requestsPageAR(indexedRequests.state); + return { embeds: [requestsEmbed], components: [requestsPageAR], ephemeral: true }; }, strain(strainInfo, interaction) { const strainEmbed = new Discord.MessageEmbed() diff --git a/slash-commands/requests.js b/slash-commands/requests.js index 039504e..fbc8b3b 100644 --- a/slash-commands/requests.js +++ b/slash-commands/requests.js @@ -1,39 +1,31 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { config } = require('dotenv'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() .setName('requests') - .setDescription('Get a list of Active requests from the database') - .addStringOption(option => - option - .setName('page') - .setDescription('Page Number') - .setRequired(true)), + .setDescription('Get a list of Active requests from the database'), async execute(interaction) { - const pageNum = interaction.options.getString('page'); - const commandData = { - author: interaction.user.tag, - command: interaction.commandName, - requests: [], - }; - const requestsMap = interaction.client.requests.map(e => { - return { - id: e.id, - author: e.author, - request: e.request, - }; - }); - for (let i = ( 10 * ( pageNum - 1 ) ); i < ( 10 * pageNum ); i++) { - if (requestsMap[i] != undefined) { - commandData.requests.push({ - id: requestsMap[i].id, - author: requestsMap[i].author, - request: requestsMap[i].request, - }); - } + if (!interaction.client.requests) { + interaction.reply('For some reason I don\'t have access to the collection of requests. Sorry about that!'); + return; } - interaction.reply(fn.embeds.requests(commandData)); + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedRequests = indexer(interaction.client.requests, 0); + indexedRequests.requestsString = new String(); + + iStorage.page = 0; + + for (const request of indexedRequests.thisPage) { + indexedRequests.requestsString += `[${request.id}]: ${request.request} (submitted by ${request.author})\n`; + } + + const commandData = { + command: "/requests", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.requests(commandData, indexedRequests)); }, }; \ No newline at end of file From d0528c36377073dbb37d1e2fa0754568bc298f2b Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:47:42 -0400 Subject: [PATCH 10/14] MVP for paged /joints --- CustomModules/ButtonHandlers.js | 32 ++++++++++++++++++++++++++++++++ CustomModules/Embeds.js | 25 +++++++++++++++++++++++++ functions.js | 10 ++++++++++ slash-commands/joints.js | 24 +++++++++++++++++++----- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index f28b878..cf3d6d9 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -34,6 +34,12 @@ module.exports = { case 'nextRequestsPage': module.exports.requestsPage(interaction); break; + case 'prevJointsPage': + module.exports.jointsPage(interaction); + break; + case 'nextJointsPage': + module.exports.jointsPage(interaction); + break; default: return; } @@ -115,5 +121,31 @@ module.exports = { } interaction.update(fn.embeds.requests({command: "/requests", author: interaction.member.displayName}, indexedRequests)); + }, + jointsPage(interaction) { + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); + + switch (interaction.component.customId) { + case 'prevJointsPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextJointsPage': + if (iStorage.page < interaction.client.joints.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedJoints = indexer(interaction.client.joints, iStorage.page); + indexedJoints.jointsString = new String(); + + for (const joint of indexedJoints.thisPage) { + indexedJoints.jointsString += `${joint.content}\n`; + } + + interaction.update(fn.embeds.joints({command: "/joints", author: interaction.member.displayName}, indexedJoints)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index 3264174..115e66a 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -107,6 +107,31 @@ module.exports = { break; } + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, nextButton); + }, + jointsPageAR(state) { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevJointsPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const nextButton = new MessageButton() + .setCustomId('nextJointsPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } + // Put the buttons into an ActionRow return new MessageActionRow() .addComponents(previousButton, nextButton); diff --git a/functions.js b/functions.js index 15b8caa..f606849 100644 --- a/functions.js +++ b/functions.js @@ -271,6 +271,16 @@ const functions = { const gifsPageAR = customEmbeds.gifsPageAR(indexedGifs.state); return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true }; }, + joints(commandData, indexedJoints) { + const jointsEmbed = new Discord.MessageEmbed() + .setAuthor({name: commandData.command}) + .setTimestamp() + .setFooter({text: `Page: ${indexedJoints.pagesString}`}) + .setDescription(indexedJoints.jointsString); + + const jointsPageAR = customEmbeds.jointsPageAR(indexedJoints.state); + return { embeds: [jointsEmbed], components: [jointsPageAR], ephemeral: true }; + }, text(commandData) { return { embeds: [new Discord.MessageEmbed() .setAuthor({name: commandData.command}) diff --git a/slash-commands/joints.js b/slash-commands/joints.js index 2ca5b6c..bca4490 100644 --- a/slash-commands/joints.js +++ b/slash-commands/joints.js @@ -1,15 +1,29 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() .setName('joints') .setDescription('Send a list of all the /joint phrases.'), async execute(interaction) { - let joints = []; - interaction.client.joints.map(e => { - joints.push(e.content); - }); - interaction.reply({ content: 'Here are all the `.joint` phrases I have saved:\n\n' + joints.join('\n'), ephemeral: true }); + if (!interaction.client.joints) { + interaction.reply('For some reason I don\'t have access to the collection of joints. Sorry about that!'); + return; + } + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedJoints = indexer(interaction.client.joints, 0); + indexedJoints.jointsString = new String(); + + iStorage.page = 0; + + for (const joint of indexedJoints.thisPage) { + indexedJoints.jointsString += `${joint.content}\n`; + } + const commandData = { + command: "/joints", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.joints(commandData, indexedJoints)); }, }; \ No newline at end of file From 4b75dfa88558d759d61b4a1d16d8a43921f901b0 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:07:20 -0400 Subject: [PATCH 11/14] v3.3.3 Documentation --- CHANGELOG.md | 23 +++++++++++++++++++++++ README.md | 33 +-------------------------------- Roadmap.md | 14 -------------- 3 files changed, 24 insertions(+), 46 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 Roadmap.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a666790 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,23 @@ +## v3.3.x +#### v3.3.3 (#20) +* Fixed content-list slash commands `/gifs`, `/pastas`, `/joints`, `/requests` (#19) +* Fixed the creation of duplicate commands properly (#18) +* Added a ton of aliases for `.gif` (`.wav`, `.mp3`, `.mp4`, `.wmv`, etc.) + +#### v3.3.2 (#17) +* Fixed the `/help` command to not crash the bot (#15) +* Filtered out duplicate commands from the `/help` list, temporary fix (#18) +* Removed instances of `MessageEmbed.addField` due to deprecation (#16) + +v3.3.1 - Polishing and bugfixing for new AvWx commands +v3.3.0 - Added `.metar`, `.atis`, and `.datis` AvWx commands + +## v3.0.x +v3.0.1 - Migrate TenorJS API Endpoint +v3.0.2 - Add medical advice commands +v3.0.3 - Fix broken `/requests` command +v3.0.4 - Add ability to use multiple aliases +v3.0.5 - Add ability to save strains +v3.0.6 - Move `.strain` to `/strain` and add Autocomplete +v3.0.7 - Add `.spongebob` replies +v3.0.8 - Add ability to open requests by pages \ No newline at end of file diff --git a/README.md b/README.md index 7b473ee..799bc87 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ # About Nodbot Nodbot is a content saving and serving Discord bot. Nodbot is able to search Tenor for GIFs, save custom copypastas, and look up marijuana strain information. Nodbot is in semi-active development by voidf1sh. It's buggy as hell and very shoddily built. Don't use it. -# Status -This should be ready to merge into `main`, let it run a couple days with testing before creating a PR. METAR and D-ATIS are implemented. TAFs will come later as they're more complicated. - # Nodbot Help Use the `/help` command to see the bot's help message. @@ -14,16 +11,6 @@ Use the `/help` command to see the bot's help message. ## Push Docker Image `docker push name/nodbot` -# Immediate To-Do - -1. ~~Sanitize inputs for SQL queries.~~ -2. ~~Move environment variables so they don't get included in the image.~~ -3. Implement error handling on all actions. -4. ~~Ephemeral responses to some/most slash commands.~~ -5. Comment the code! Document! -6. Check for and create database tables if necessary. Handle errors. -7. Readjust keyword autoresponses to be more generic instead of hard coded - # Deploy NodBot Yourself 1. Create an application at the [Discord Developer Portal](https://discord.com/developers/applications) @@ -35,13 +22,6 @@ Use the `/help` command to see the bot's help message. 6. Configure your environment variables as outlined below. 7. Fire it up with `node main.js` -# Recent Changes - -* Added METAR via AviationWeather.gov API -* Added D-ATIS via datis.clowd.io API -* Updated how keyword autoresponses are handled -* Changed `.joint` to reduce duplication and repetition by implementing an Ashtray and Roaches - ## Table Structure ``` @@ -108,15 +88,4 @@ tenorAPIKey= ownerId= statusChannelId= clientId= -``` - -## Changes - -v3.0.1 - Migrate TenorJS API Endpoint -v3.0.2 - Add medical advice commands -v3.0.3 - Fix broken `/requests` command -v3.0.4 - Add ability to use multiple aliases -v3.0.5 - Add ability to save strains -v3.0.6 - Move `.strain` to `/strain` and add Autocomplete -v3.0.7 - Add `.spongebob` replies -v3.0.8 - Add ability to open requests by pages \ No newline at end of file +``` \ No newline at end of file diff --git a/Roadmap.md b/Roadmap.md deleted file mode 100644 index 80bce7b..0000000 --- a/Roadmap.md +++ /dev/null @@ -1,14 +0,0 @@ -# v3.1.0 - -* Name checking for saving content -* .jpg, .wav -* Audio/Video attachments for saved content. -* Pass The Joint -* Voting system for Super Adventure Club - -# v4.0.0 -* Scalability: modify the code to allow the bot to be used in multiple servers - * including saved content, saved commands, preferences, etc. - -# v3.?.? -= Joke generator for Hallihan \ No newline at end of file From 09901b5e58ba146e47868ca040b5c56f0692645e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:07:26 -0400 Subject: [PATCH 12/14] Add aliases --- dot-commands/gif.js | 1 + 1 file changed, 1 insertion(+) diff --git a/dot-commands/gif.js b/dot-commands/gif.js index b9f746a..dc2ff98 100644 --- a/dot-commands/gif.js +++ b/dot-commands/gif.js @@ -9,6 +9,7 @@ const dotenv = require('dotenv').config(); module.exports = { name: 'gif', description: 'Send a GIF', + alias: ['jpg', 'png', 'gifv', 'webm', 'mp4', 'wav', 'wmv', 'webp', 'mp3', 'flac', 'ogg', 'avi', 'mov', 'mpg', 'mpeg', 'mkv', 'flv', 'bmp', 'tiff', 'tif', 'svg', 'ico'], usage: '.gif', async execute(message, commandData) { // if (message.deletable) message.delete(); From 8148890574a17a3c0e24da855e6d650b3f6cd04c Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:22:16 -0400 Subject: [PATCH 13/14] Add listing of aliases to /help --- functions.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/functions.js b/functions.js index f606849..7d8a1b2 100644 --- a/functions.js +++ b/functions.js @@ -185,10 +185,11 @@ const functions = { const slashCommandsMap = interaction.client.slashCommands.map(e => { if (!slashSeenNames.includes(e.data.name)) { slashSeenNames.push(e.data.name); - return { + const command = { name: e.data.name, description: e.data.description }; + return command; } else { return null; } @@ -204,18 +205,29 @@ const functions = { const dotCommandsMap = interaction.client.dotCommands.map(e => { if (!dotSeenNames.includes(e.name)) { dotSeenNames.push(e.name); - return { + let command = { name: e.name, description: e.description, usage: e.usage }; + command.aliasString = new String(); + if (e.alias != undefined && typeof e.alias === 'object') { + for (const a of e.alias) { + command.aliasString += `\`.${a}\`, `; + } + } else if (e.alias != undefined && typeof e.alias === 'string') { + command.aliasString += `\`.${e.alias}\``; + } else { + command.aliasString = 'None'; + } + return command; } else { return null; } }); for (const e of dotCommandsMap) { if (e != null) { - dotCommandsFields.push(`- \`.${e.name}\` - ${e.description} - ${e.usage}`); + dotCommandsFields.push(`- \`.${e.name}\` - ${e.description}\n\tUsage: ${e.usage}\n\tAliases: ${e.aliasString}`); } } console.log(dotCommandsFields); From 3a35b829adac6f7d22c7a6cb24abc70a3cb81d3f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:23:25 -0400 Subject: [PATCH 14/14] Documentation update, final for v.3.3.3 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a666790..4b83906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Fixed content-list slash commands `/gifs`, `/pastas`, `/joints`, `/requests` (#19) * Fixed the creation of duplicate commands properly (#18) * Added a ton of aliases for `.gif` (`.wav`, `.mp3`, `.mp4`, `.wmv`, etc.) +* Added alias lists in `/help` #### v3.3.2 (#17) * Fixed the `/help` command to not crash the bot (#15)