From c7400f9fcdefe2ba4e290438d08cad1ac39e3758 Mon Sep 17 00:00:00 2001 From: Marius Begby Date: Tue, 18 Jul 2023 14:53:07 +0200 Subject: [PATCH] feat: Added common logic for validating command execution --- src/commands/player/filters.js | 32 ++++++---------- src/commands/player/leave.js | 13 ++----- src/commands/player/loop.js | 26 +++---------- src/commands/player/nowplaying.js | 38 ++++--------------- src/commands/player/pause.js | 38 ++++--------------- src/commands/player/play.js | 13 ++----- src/commands/player/queue.js | 15 ++------ src/commands/player/remove.js | 26 +++---------- src/commands/player/seek.js | 38 ++++--------------- src/commands/player/skip.js | 30 +++++---------- src/commands/player/volume.js | 26 +++---------- src/commands/system/guilds.js | 15 ++------ src/commands/system/status.js | 15 ++------ src/utils/validation/queueValidation.js | 36 ++++++++++++++++++ .../validation/systemCommandValidation.js | 19 ++++++++++ .../validation/voiceChannelValidation.js | 19 ++++++++++ 16 files changed, 155 insertions(+), 244 deletions(-) create mode 100644 src/utils/validation/queueValidation.js create mode 100644 src/utils/validation/systemCommandValidation.js create mode 100644 src/utils/validation/voiceChannelValidation.js diff --git a/src/commands/player/filters.js b/src/commands/player/filters.js index a7e3d71d..3f2b9aba 100644 --- a/src/commands/player/filters.js +++ b/src/commands/player/filters.js @@ -1,4 +1,6 @@ const { embedOptions, ffmpegFilterOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist, queueNoCurrentTrack } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder, @@ -15,30 +17,18 @@ module.exports = { .setDescription('Toggle various audio filters during playback.') .setDMPermission(false), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } - const queue = await useQueue(interaction.guild.id); + const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; + } + + if (await queueNoCurrentTrack(interaction, queue)) { + return; } let filterOptions = []; diff --git a/src/commands/player/leave.js b/src/commands/player/leave.js index 9b994a41..16766b28 100644 --- a/src/commands/player/leave.js +++ b/src/commands/player/leave.js @@ -1,4 +1,5 @@ const { embedOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -10,16 +11,8 @@ module.exports = { // todo, allow command to be executed if bot is only member in voice channel execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); diff --git a/src/commands/player/loop.js b/src/commands/player/loop.js index 2566c8d6..0b69e15f 100644 --- a/src/commands/player/loop.js +++ b/src/commands/player/loop.js @@ -1,4 +1,6 @@ const { embedOptions, botOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -20,30 +22,14 @@ module.exports = { ) ), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; } const loopModesFormatted = new Map([ diff --git a/src/commands/player/nowplaying.js b/src/commands/player/nowplaying.js index 991cdc3f..1787d67a 100644 --- a/src/commands/player/nowplaying.js +++ b/src/commands/player/nowplaying.js @@ -1,4 +1,6 @@ const { embedOptions, playerOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist, queueNoCurrentTrack } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -8,42 +10,18 @@ module.exports = { .setDescription('Show information about the track currently playing.') .setDMPermission(false), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; } - if (!queue.currentTrack) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere is nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueNoCurrentTrack(interaction, queue)) { + return; } const sourceStringsFormatted = new Map([ diff --git a/src/commands/player/pause.js b/src/commands/player/pause.js index 787f1c6f..5620aa58 100644 --- a/src/commands/player/pause.js +++ b/src/commands/player/pause.js @@ -1,4 +1,6 @@ const { embedOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist, queueNoCurrentTrack } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -8,42 +10,18 @@ module.exports = { .setDescription('Pause or resume the current track.') .setDMPermission(false), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; } - if (!queue.currentTrack) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere is nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueNoCurrentTrack(interaction, queue)) { + return; } let durationFormat = diff --git a/src/commands/player/play.js b/src/commands/player/play.js index a66db106..d7ec9562 100644 --- a/src/commands/player/play.js +++ b/src/commands/player/play.js @@ -1,4 +1,5 @@ const { embedOptions, playerOptions, botOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useMainPlayer, useQueue } = require('discord-player'); @@ -9,16 +10,8 @@ module.exports = { .setDMPermission(false) .addStringOption((option) => option.setName('query').setDescription('Search query or URL.').setRequired(true)), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const player = useMainPlayer(); diff --git a/src/commands/player/queue.js b/src/commands/player/queue.js index c7875f12..82a0ddc8 100644 --- a/src/commands/player/queue.js +++ b/src/commands/player/queue.js @@ -1,4 +1,5 @@ const { embedOptions, playerOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -9,20 +10,12 @@ module.exports = { .setDMPermission(false) .addNumberOption((option) => option.setName('page').setDescription('Page number of the queue').setMinValue(1)), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } - const pageIndex = (interaction.options.getNumber('page') || 1) - 1; const queue = useQueue(interaction.guild.id); + const pageIndex = (interaction.options.getNumber('page') || 1) - 1; let queueString = ''; if (!queue) { diff --git a/src/commands/player/remove.js b/src/commands/player/remove.js index 6ea818fa..a17e5068 100644 --- a/src/commands/player/remove.js +++ b/src/commands/player/remove.js @@ -1,4 +1,6 @@ const { embedOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -15,30 +17,14 @@ module.exports = { .setRequired(true) ), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; } const removeTrackNumber = interaction.options.getNumber('tracknumber'); diff --git a/src/commands/player/seek.js b/src/commands/player/seek.js index 13a21199..c749dd9d 100644 --- a/src/commands/player/seek.js +++ b/src/commands/player/seek.js @@ -1,4 +1,6 @@ const { embedOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist, queueNoCurrentTrack } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -14,42 +16,18 @@ module.exports = { .setRequired(true) ), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; } - if (!queue.currentTrack) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere is nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueNoCurrentTrack(interaction, queue)) { + return; } const durationInput = interaction.options.getString('duration'); diff --git a/src/commands/player/skip.js b/src/commands/player/skip.js index 6ba871dc..f0159bf8 100644 --- a/src/commands/player/skip.js +++ b/src/commands/player/skip.js @@ -1,4 +1,6 @@ const { embedOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist, queueNoCurrentTrack } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -11,30 +13,18 @@ module.exports = { option.setName('tracknumber').setDescription('Track number to skip to in the queue.').setMinValue(1) ), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; + } + + if (await queueNoCurrentTrack(interaction, queue)) { + return; } const skipToTrack = interaction.options.getNumber('tracknumber'); diff --git a/src/commands/player/volume.js b/src/commands/player/volume.js index 28ba2260..f8fc56a5 100644 --- a/src/commands/player/volume.js +++ b/src/commands/player/volume.js @@ -1,4 +1,6 @@ const { embedOptions } = require('../../config'); +const { notInVoiceChannel } = require('../../utils/validation/voiceChannelValidation'); +const { queueDoesNotExist } = require('../../utils/validation/queueValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); @@ -15,30 +17,14 @@ module.exports = { .setMaxValue(100) ), execute: async ({ interaction }) => { - if (!interaction.member.voice.channel) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notInVoiceChannel(interaction)) { + return; } const queue = useQueue(interaction.guild.id); - if (!queue) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await queueDoesNotExist(interaction, queue)) { + return; } const volume = interaction.options.getNumber('percentage'); diff --git a/src/commands/system/guilds.js b/src/commands/system/guilds.js index 7bac5127..dbcd7f16 100644 --- a/src/commands/system/guilds.js +++ b/src/commands/system/guilds.js @@ -1,4 +1,5 @@ -const { embedOptions, systemOptions } = require('../../config'); +const { embedOptions } = require('../../config'); +const { notValidGuildId } = require('../../utils/validation/systemCommandValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); module.exports = { @@ -8,16 +9,8 @@ module.exports = { .setDescription('Show list of guilds where bot is added.') .setDMPermission(false), execute: async ({ interaction, client }) => { - if (!systemOptions.systemGuildIds.includes(interaction.guildId)) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nNo permission to execute this command.\n\nThe command \`${interaction.commandName}\` cannot be executed in this server.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notValidGuildId(interaction)) { + return; } let guildsList = client.guilds.cache diff --git a/src/commands/system/status.js b/src/commands/system/status.js index 09dec62b..a9ff47f9 100644 --- a/src/commands/system/status.js +++ b/src/commands/system/status.js @@ -1,4 +1,5 @@ -const { embedOptions, systemOptions } = require('../../config'); +const { embedOptions } = require('../../config'); +const { notValidGuildId } = require('../../utils/validation/systemCommandValidation'); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { useQueue } = require('discord-player'); const osu = require('node-os-utils'); @@ -8,16 +9,8 @@ module.exports = { isSystemCommand: true, data: new SlashCommandBuilder().setName('status').setDescription('Show bot status.').setDMPermission(false), execute: async ({ interaction, client }) => { - if (!systemOptions.systemGuildIds.includes(interaction.guildId)) { - return await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setDescription( - `**${embedOptions.icons.warning} Oops!**\nNo permission to execute this command.\n\nThe command \`${interaction.commandName}\` cannot be executed in this server.` - ) - .setColor(embedOptions.colors.warning) - ] - }); + if (await notValidGuildId(interaction)) { + return; } const interactionLatency = Date.now() - interaction.createdTimestamp; diff --git a/src/utils/validation/queueValidation.js b/src/utils/validation/queueValidation.js new file mode 100644 index 00000000..7f533ea9 --- /dev/null +++ b/src/utils/validation/queueValidation.js @@ -0,0 +1,36 @@ +const { embedOptions } = require('../../config'); +const { EmbedBuilder } = require('discord.js'); + +exports.queueDoesNotExist = async (interaction, queue) => { + if (!queue) { + await interaction.editReply({ + embeds: [ + new EmbedBuilder() + .setDescription( + `**${embedOptions.icons.warning} Oops!**\nThere are no tracks in the queue and nothing currently playing. First add some tracks with **\`/play\`**!` + ) + .setColor(embedOptions.colors.warning) + ] + }); + return true; + } + + return false; +}; + +exports.queueNoCurrentTrack = async (interaction, queue) => { + if (!queue.currentTrack) { + await interaction.editReply({ + embeds: [ + new EmbedBuilder() + .setDescription( + `**${embedOptions.icons.warning} Oops!**\nThere is nothing currently playing. First add some tracks with **\`/play\`**!` + ) + .setColor(embedOptions.colors.warning) + ] + }); + return true; + } + + return false; +}; diff --git a/src/utils/validation/systemCommandValidation.js b/src/utils/validation/systemCommandValidation.js new file mode 100644 index 00000000..6f4639f5 --- /dev/null +++ b/src/utils/validation/systemCommandValidation.js @@ -0,0 +1,19 @@ +const { embedOptions, systemOptions } = require('../../config'); +const { EmbedBuilder } = require('discord.js'); + +exports.notValidGuildId = async (interaction) => { + if (!systemOptions.systemGuildIds.includes(interaction.guildId)) { + await interaction.editReply({ + embeds: [ + new EmbedBuilder() + .setDescription( + `**${embedOptions.icons.warning} Oops!**\nNo permission to execute this command.\n\nThe command \`${interaction.commandName}\` cannot be executed in this server.` + ) + .setColor(embedOptions.colors.warning) + ] + }); + return true; + } + + return false; +}; diff --git a/src/utils/validation/voiceChannelValidation.js b/src/utils/validation/voiceChannelValidation.js new file mode 100644 index 00000000..d86f8946 --- /dev/null +++ b/src/utils/validation/voiceChannelValidation.js @@ -0,0 +1,19 @@ +const { embedOptions } = require('../../config'); +const { EmbedBuilder } = require('discord.js'); + +exports.notInVoiceChannel = async (interaction) => { + if (!interaction.member.voice.channel) { + await interaction.editReply({ + embeds: [ + new EmbedBuilder() + .setDescription( + `**${embedOptions.icons.warning} Oops!**\nYou need to be in a voice channel to use this command.` + ) + .setColor(embedOptions.colors.warning) + ] + }); + return true; + } + + return false; +};