From 2bed3c07e943a0edb9f752c347e69a43b6f873c9 Mon Sep 17 00:00:00 2001 From: ethanf Date: Tue, 26 Mar 2024 23:38:49 -0500 Subject: [PATCH] refactor: break relevant commands into files --- commands/clear.js | 25 +++++ commands/end.js | 71 ++++++++++++++ commands/fklist.js | 66 +++++++++++++ commands/hello.js | 14 +++ index.js | 238 ++------------------------------------------- register.js | 91 ++--------------- utils.js | 43 ++++++++ 7 files changed, 239 insertions(+), 309 deletions(-) create mode 100644 commands/clear.js create mode 100644 commands/end.js create mode 100644 commands/fklist.js create mode 100644 commands/hello.js create mode 100644 utils.js diff --git a/commands/clear.js b/commands/clear.js new file mode 100644 index 0000000..1af4a78 --- /dev/null +++ b/commands/clear.js @@ -0,0 +1,25 @@ +import { SlashCommandBuilder } from "discord.js"; +import { client } from ".."; +import { RUNNER_ROLE_ID } from "../config.json"; + +const data = new SlashCommandBuilder() + .setName("clear") + .setDescription("Clears bot messages in this channel"); + +const permissions = [RUNNER_ROLE_ID]; + +const execute = async (interaction) => { + await interaction.reply("Clearing messages..."); + interaction.channel.messages + .fetch({ limit: 250 }) + .then((messages) => { + messages.forEach((message) => { + if (message.author.id === client.user.id) { + message.delete(); + } + }); + }) + .catch(console.error); +}; + +export { data, permissions, execute }; \ No newline at end of file diff --git a/commands/end.js b/commands/end.js new file mode 100644 index 0000000..fcdae32 --- /dev/null +++ b/commands/end.js @@ -0,0 +1,71 @@ +import { SlashCommandBuilder } from "discord.js"; +import { findChannelfromCache } from "../utils.js"; +import { RUNNER_ROLE_ID, PICKING_ID, BLU_ID, RED_ID } from "../config.json"; + +const data = new SlashCommandBuilder() + .setName("end") + .setDescription("Moves the team channel members back to the picking channel"); + +const permissions = [RUNNER_ROLE_ID]; + +const execute = async (interaction) => { + await interaction.reply("Moving members..."); + + // get voice channels + const picking = findChannelfromCache( + interaction.guild.channels.cache, + "picking", + PICKING_ID + ); + const blu = findChannelfromCache( + interaction.guild.channels.cache, + "blu", + BLU_ID + ); + const red = findChannelfromCache( + interaction.guild.channels.cache, + "red", + RED_ID + ); + if (!picking || !blu || !red) { + return console.error("Could not find all channels for /end"); + } + + // get members in voice channel + let members = blu.members.concat(red.members); + if (members.size === 0) { + return await interaction.followUp("Found no members in blu or red"); + } + + let eCount = 0; + + // move members to picking + const moveToPicking = async (member) => { + try { + await member.voice.setChannel(picking); + } catch (error) { + console.error(error); + eCount++; + } + }; + + const moveAllToPicking = async () => { + return Promise.all( + Array.from(members, async ([memberId, member]) => { + await moveToPicking(member); + }) + ); + }; + + moveAllToPicking().then(() => + interaction.followUp( + `Moved members in blu and red${ + eCount > 0 ? ` (error moving ${eCount} members)` : "" + }` + ) + ); +}; + +const synonyms = ["resetteams"]; + +export { data, permissions, execute, synonyms }; diff --git a/commands/fklist.js b/commands/fklist.js new file mode 100644 index 0000000..a65404d --- /dev/null +++ b/commands/fklist.js @@ -0,0 +1,66 @@ +import { SlashCommandBuilder } from "discord.js"; +import { findChannelfromCache, findPlayer, getApplicableName } from "../utils"; +import { RUNNER_ROLE_ID, PICKING_ID, FK_ID } from "../config.json"; + +// not really used since fks are now determined randomly +const data = new SlashCommandBuilder() + .setName("fklist") + .setDescription("Pulls addup channel members into fk channel and lists them"); + +const permissions = [RUNNER_ROLE_ID]; + +const synonyms = ["listfk"]; + +const execute = async (interaction) => { + await interaction.reply("Moving fatkids..."); + + // get voice channels + const picking = findChannelfromCache( + interaction.guild.channels.cache, + "picking", + PICKING_ID + ); + const fk = findChannelfromCache( + interaction.guild.channels.cache, + "fatkid", + FK_ID + ); + if (!picking || !fk) { + return console.error("Could not find all channels for /fklist"); + } + + // get members in voice channel + const members = picking.members; + if (members.size === 0) { + return await interaction.followUp("Found no members in picking"); + } + + let names = [], + eCount = 0; + + const logFk = async (member) => { + try { + await member.voice.setChannel(fk); + names.push(getApplicableName(member)); + } catch (error) { + console.error(error); + eCount++; + } + }; + + const logAllFks = async () => { + return Promise.all( + Array.from(members, async ([memberId, member]) => { + await logFk(member); + }) + ); + }; + + logAllFks().then(() => + interaction.followUp( + `Fatkids: ${names.join(', ')}${eCount > 0 ? ` (error moving ${eCount} members)` : ""}` + ) + ); +}; + +export { data, permissions, execute, synonyms }; diff --git a/commands/hello.js b/commands/hello.js new file mode 100644 index 0000000..3123211 --- /dev/null +++ b/commands/hello.js @@ -0,0 +1,14 @@ +import { SlashCommandBuilder } from "discord.js"; +import { RUNNER_ROLE_ID } from "../config.json"; + +const data = new SlashCommandBuilder() + .setName("hello") + .setDescription("Replies 'world'"); + +const permissions = [RUNNER_ROLE_ID]; + +const execute = async (interaction) => { + await interaction.reply("world"); +} + +export { data, permissions, execute }; \ No newline at end of file diff --git a/index.js b/index.js index e8b37c2..c08dd8d 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ import fs from "fs"; -import path, { parse } from "path"; +import path from "path"; import { Client, Collection, GatewayIntentBits, Partials } from "discord.js"; +import { getApplicableName, findPlayer } from "./utils.js"; const { TOKEN, GUILD_ID, @@ -15,7 +16,7 @@ const { let whitelistStr = require("./config.json").RANKING_WHITELIST; -const client = new Client({ +export const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, @@ -36,6 +37,11 @@ for (const file of commandFiles) { const command = require(`./commands/${file}`); if ("data" in command && "execute" in command) { client.fileCommands.set(command.data.name, command); + if (command.synonyms) { + for (const synonym of command.synonyms) { + client.fileCommands.set(synonym, command); + } + } } else { console.error(`${__filename}: Invalid command file: ${file}`); } @@ -44,43 +50,6 @@ for (const file of commandFiles) { const backticks = "```"; const rankingsPath = path.join(__dirname, "rankings.json"); -const matchString = (str, search) => { - if (!str || !search) return false; - return str.toLowerCase().includes(search.toLowerCase()); -}; - -const findPlayer = (guild, searchName) => { - // search display name - let player = guild.members.cache.find((member) => - matchString(member.displayName, searchName) - ); - if (!player) { - // search global name - player = guild.members.cache.find((member) => - matchString(member.user.globalName, searchName) - ); - } - if (!player) { - // search username - player = guild.members.cache.find((member) => - matchString(member.user.username, searchName) - ); - } - if (!player) { - // match id - player = guild.members.cache.find((member) => member.id === searchName); - } - return player; -}; - -const getApplicableName = (player) => { - return ( - player.displayName || - player.user.globalName || - player.user.username || - player.id - ); -}; const avgDiff = (arr) => { // average absolute difference between all pairs of rank properties in a given array @@ -230,7 +199,7 @@ client.on("error", (error) => { if (!channel) return console.error("Can't find command channel"); client.channels.cache .get(COMMAND_CHANNEL_ID) - .send("Internal error") + .send(`Internal error: ${error.message}`) .catch(console.error); }); @@ -244,7 +213,7 @@ client.on("interactionCreate", async (interaction) => { if (fileCommand.permissions) { const member = interaction.member; for (const permission of fileCommand.permissions) { - if (!member.roles.cache.has(permission)) { + if (!member.roles.cache.has(permission) && member.id !== DEBUG_ADMIN_ID) { await interaction.reply({ content: "You lack the required permissions", ephemeral: true, @@ -271,177 +240,6 @@ client.on("interactionCreate", async (interaction) => { return; } - if ( - command === "scout" || - command === "soldier" || - command === "pyro" || - command === "demoman" || - command === "demo" || - command === "heavy" || - command === "engineer" || - command === "engi" || - command === "medic" || - command === "sniper" || - command === "spy" - ) { - // get voice channels - const picking = interaction.guild.channels.cache.find( - (channel) => channel.name === "picking" || channel.id === PICKING_ID - ); - if (!picking) return console.error("Can't find channel 'picking'!"); - const captain = interaction.guild.channels.cache.find( - (channel) => channel.name === "captains" || channel.id === CAPTAIN_ID - ); - if (!captain) return console.error("Can't find channel 'captains'!"); - - // make sure user is in picking or captain channel - if ( - !picking.members.has(interaction.user.id) && - !captain.members.has(interaction.user.id) - ) { - await interaction.reply({ - content: "Must be in picking or captains channel to use this command", - ephemeral: true, - }); - return; - } else { - await interaction.reply({ - content: "Checking picking channel...", - ephemeral: true, - }); - - // set role name - let roleName = command; - if (command === "demoman") roleName = "demo"; - if (command === "engi") roleName = "engineer"; - - // check each member in picking channel for role - let str = `In picking (${roleName}):`; - for (const member of picking.members.values()) { - if (member.roles.cache.find((role) => role.name === roleName)) { - if (str !== `In picking (${roleName}):`) str += ","; - str += " " + getApplicableName(member); - } - } - if (str === `In picking (${roleName}):`) - str = `None found ¯\\_(ツ)_/¯ (${roleName})`; - - // respond - return await interaction.followUp(str); - } - } - - if (command === "hello") { - await interaction.reply("world"); - } - - if ( - command === "topicking" || - command === "end" || - command === "resetteams" - ) { - await interaction.reply("Moving members..."); - - // get voice channels - const blu = interaction.guild.channels.cache.find( - (channel) => channel.name === "blu" || channel.id === BLU_ID - ); - if (!blu) return console.error("Can't find channel 'blu'!"); - const red = interaction.guild.channels.cache.find( - (channel) => channel.name === "red" || channel.id === RED_ID - ); - if (!red) return console.error("Can't find channel 'red'!"); - const picking = interaction.guild.channels.cache.find( - (channel) => channel.name === "picking" || channel.id === PICKING_ID - ); - if (!picking) return console.error("Can't find channel 'picking'!"); - - // get members in voice channel - let members = blu.members.concat(red.members); - if (members.size === 0) { - return await interaction.followUp("Found no members in blu or red"); - } - - let eCount = 0; - - // move members to picking - const moveToPicking = async (member) => { - try { - await member.voice.setChannel(picking); - } catch (error) { - console.error(error); - eCount++; - } - }; - - const moveAllToPicking = async () => { - return Promise.all( - Array.from(members, async ([memberId, member]) => { - await moveToPicking(member); - }) - ); - }; - - moveAllToPicking().then(() => - interaction.followUp( - `Moved members in blu and red${ - eCount > 0 ? ` (error moving ${eCount} members)` : "" - }` - ) - ); - } - - if (command === "fklist" || command === "listfk") { - // moves players in picking to fatkid channel, for use in captain pugs - await interaction.reply("Moving fatkids..."); - - // get voice channels - const picking = interaction.guild.channels.cache.find( - (channel) => channel.name === "picking" || channel.id === PICKING_ID - ); - if (!picking) return console.error("Can't find channel 'add-up'!"); - const fk = interaction.guild.channels.cache.find( - (channel) => channel.name === "fatkid" || channel.id === FK_ID - ); - if (!fk) return console.error("Can't find channel 'fatkid'!"); - - // get members in voice channel - const members = picking.members; - if (members.size === 0) { - return await interaction.followUp("Found no members in picking"); - } - - let str = "", - eCount = 0; - - const logFk = async (member) => { - try { - await member.voice.setChannel(fk); - if (str.length > 0) str += ", "; - str += getApplicableName(member); - } catch (error) { - console.error(error); - eCount++; - } - }; - - const logAllFks = async () => { - return Promise.all( - Array.from(members, async ([memberId, member]) => { - await logFk(member); - }) - ); - }; - - logAllFks().then(() => - interaction.followUp( - `Fatkids: ${str}${ - eCount > 0 ? ` (error moving ${eCount} members)` : "" - }` - ) - ); - } - if (command === "pick" || command === "autocaptain") { await interaction.reply("Picking teams..."); @@ -608,22 +406,6 @@ client.on("interactionCreate", async (interaction) => { }` ); } - - if (command === "clear" || command === "bclear") { - await interaction.reply("Clearing messages..."); - let channel = client.channels.cache.get(COMMAND_CHANNEL_ID); - if (!channel) return console.error("Can't find command channel"); - channel.messages - .fetch({ limit: 100 }) - .then((messages) => { - messages.forEach((message) => { - if (message.author.id === client.user.id) { - message.delete(); - } - }); - }) - .catch(console.error); - } }); /* diff --git a/register.js b/register.js index fe69366..87b8b54 100644 --- a/register.js +++ b/register.js @@ -5,86 +5,6 @@ const path = require("path"); // set static commands const commands = [ - { - name: "hello", - description: "Replies 'world'", - }, - { - name: "topicking", - description: "Pulls team and addup channel members into picking channel", - }, - { - name: "end", - description: "Pulls team and addup channel members into picking channel", - }, - { - name: "resetteams", - description: "Pulls team channel members into picking channel", - }, - /*{ - name: "testfk", - description: "debug fk", - },*/ - { - name: "fklist", - description: "Pulls addup channel members into fk channel and lists them", - }, - { - name: "listfk", - description: "Pulls addup channel members into fk channel and lists them", - }, - { - name: "clear", - description: "Clears bot messages in command channel", - }, - { - name: "bclear", - description: "Clears bot messages in command channel", - }, - { - name: "scout", - description: "Lists picking channel members with scout role", - }, - { - name: "soldier", - description: "Lists picking channel members with soldier role", - }, - { - name: "pyro", - description: "Lists picking channel members with pyro role", - }, - { - name: "demo", - description: "Lists picking channel members with demo role", - }, - { - name: "demoman", - description: "Alias of /demo", - }, - { - name: "heavy", - description: "Lists picking channel members with heavy role", - }, - { - name: "engineer", - description: "Lists picking channel members with engineer role", - }, - { - name: "engi", - description: "Alias of /engineer", - }, - { - name: "medic", - description: "Lists picking channel members with medic role", - }, - { - name: "sniper", - description: "Lists picking channel members with sniper role", - }, - { - name: "spy", - description: "Lists picking channel members with spy role", - }, { name: "pick", description: "Automatically picks teams", @@ -102,7 +22,16 @@ const commandFiles = fs.readdirSync(commandsPath); for (const file of commandFiles) { const command = require(`./commands/${file}`); if ("data" in command && "execute" in command) { - commands.push(command.data.toJSON()); + let commandData = command.data; + commands.push(commandData); + if (command.synonyms) { + for (const synonym of command.synonyms) { + commands.push({ + ...commandData, + name: synonym, + }); + } + } } else { console.error(`${__filename}: Invalid command file: ${file}`); } diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..39e5cd7 --- /dev/null +++ b/utils.js @@ -0,0 +1,43 @@ +export const findChannelfromCache = (channelCache, name, id) => { + return channelCache.find( + (channel) => channel.name === name || channel.id === id + ); +} + +export const matchString = (str, search) => { + if (!str || !search) return false; + return str.toLowerCase().includes(search.toLowerCase()); +}; + +export const findPlayer = (guild, searchName) => { + // search display name + let player = guild.members.cache.find((member) => + matchString(member.displayName, searchName) + ); + if (!player) { + // search global name + player = guild.members.cache.find((member) => + matchString(member.user.globalName, searchName) + ); + } + if (!player) { + // search username + player = guild.members.cache.find((member) => + matchString(member.user.username, searchName) + ); + } + if (!player) { + // match id + player = guild.members.cache.find((member) => member.id === searchName); + } + return player; +}; + +export const getApplicableName = (player) => { + return ( + player.displayName || + player.user.globalName || + player.user.username || + player.id + ); +}; \ No newline at end of file