From e5c5e8b8b28110a3338f51319f25b1cc9b8f118d Mon Sep 17 00:00:00 2001 From: ethanf Date: Wed, 27 Mar 2024 01:00:11 -0500 Subject: [PATCH] refactor: remove unused autocaptain --- config.json | 3 +- index.js | 790 +--------------------------------------------------- 2 files changed, 6 insertions(+), 787 deletions(-) diff --git a/config.json b/config.json index 1593190..12fad82 100644 --- a/config.json +++ b/config.json @@ -10,6 +10,5 @@ "VOICE_ID_PICKING": "1175649967935856680", "VOICE_ID_BLU": "1175649793943552010", "VOICE_ID_RED": "1175649777648680971", - "VOICE_ID_FK": "1176396207183106078", - "RANKING_WHITELIST": "233036215610245120" + "VOICE_ID_FK": "1176396207183106078" } diff --git a/index.js b/index.js index cb5e89f..e9056fa 100644 --- a/index.js +++ b/index.js @@ -1,19 +1,13 @@ import fs from "fs"; import path from "path"; import { Client, Collection, GatewayIntentBits, Partials } from "discord.js"; -import { getApplicableName, findPlayer } from "./utils.js"; + const { TOKEN, - GUILD_ID, USER_ID_DEBUG, TEXT_ID_COMMAND, - VOICE_ID_PICKING, - VOICE_ID_BLU, - VOICE_ID_RED, } = require("./config.json"); -let whitelistStr = require("./config.json").RANKING_WHITELIST; - export const client = new Client({ intents: [ GatewayIntentBits.Guilds, @@ -45,132 +39,6 @@ for (const file of commandFiles) { } } -const backticks = "```"; -const rankingsPath = path.join(__dirname, "rankings.json"); - - -const avgDiff = (arr) => { - // average absolute difference between all pairs of rank properties in a given array - let sum = 0; - for (let i = 0; i < arr.length; i++) { - for (let j = 0; j < arr.length; j++) { - if (isNaN(arr[i].rank) || isNaN(arr[j].rank)) { - console.error(`Invalid array passed to avgDiff ${arr}`); - return; - } - sum += Math.abs(arr[i].rank - arr[j].rank); - } - } - return sum / (arr.length * (arr.length - 1)) / 2; -}; - -// values used for balancing, modifiable -// FUN value: Fluctuating Unfairness Normalization value -// PASSION: Player Ability/Skill Separation Index Offset Number -let funInput = 4; // 1-10 -let passionInput = 1; // 1-5 - -// balance attempt counter, not modifiable -let attempts = 0; - -const balanceArrays = (a1, a2) => { - // check to make sure arrays are not empty and that rank properties exist - if (a1.length === 0 || a2.length === 0) { - console.error(`Empty array(s) passed to balanceArrays ${a1} ${a2}`); - return [a1, a2]; - } - if (!a1[0].rank || !a2[0].rank) { - console.error(`Rank property missing ${a1} ${a2}`); - return [a1, a2]; - } - - let modArr1 = [...a1]; - let modArr2 = [...a2]; - let sum1 = modArr1.reduce((acc, player) => acc + player.rank, 0); - let sum2 = modArr2.reduce((acc, player) => acc + player.rank, 0); - - let funValue = funInput * 0.01 + 0.025; - let passion = passionInput * 0.1; - let unequalAllowance = Math.floor((sum1 + sum2) * funValue); - - // rebalance until teams fall within constraints - attempts = 0; - while ( - Math.abs(avgDiff(modArr1) - avgDiff(modArr2)) > passion || - (Math.abs(sum1 - sum2) > unequalAllowance && attempts < 1000) - ) { - attempts++; - if (attempts > 1000) { - console.log( - `Too many attempts to balance teams - ${attempts} ${unequalAllowance} ${passion} - ${avgDiff(modArr1)} ${avgDiff(modArr2)}` - ); - return [modArr1, modArr2]; - } else if (attempts > 600) { - unequalAllowance = (sum1 + sum2) * funValue + 2; - } else if (attempts > 300) { - unequalAllowance = (sum1 + sum2) * funValue + 1; - } - - let rerolls = 0; - let ran1 = Math.floor(Math.random() * modArr1.length); - let ran2 = Math.floor(Math.random() * modArr2.length); - // swap randomly if teams seem even - if (Math.abs(sum1 - sum2) < unequalAllowance) { - while (modArr1[ran1].rank === modArr2[ran2].rank && rerolls < 100) { - rerolls++; - ran1 = Math.floor(Math.random() * modArr1.length); - ran2 = Math.floor(Math.random() * modArr2.length); - } - } - // else swap players to minimize difference - else if (sum1 > sum2) { - while (modArr1[ran1].rank <= modArr2[ran2].rank && rerolls < 100) { - rerolls++; - ran1 = Math.floor(Math.random() * modArr1.length); - ran2 = Math.floor(Math.random() * modArr2.length); - } - } else if (sum1 < sum2) { - while (modArr1[ran1].rank >= modArr2[ran2].rank && rerolls < 100) { - rerolls++; - ran1 = Math.floor(Math.random() * modArr1.length); - ran2 = Math.floor(Math.random() * modArr2.length); - } - } - - // make the swap - let temp = modArr1[ran1]; - modArr1[ran1] = modArr2[ran2]; - modArr2[ran2] = temp; - sum1 = modArr1.reduce((acc, player) => acc + player.rank, 0); - sum2 = modArr2.reduce((acc, player) => acc + player.rank, 0); - - // if array lengths are uneven, act as if the shorter array is padded with the average of all values - // a length difference of more than 1 between the two arrays should be disallowed elsewhere - if (modArr1.length > modArr2.length) { - let avg = sum2 / modArr2.length; - sum2 += avg; - } else if (modArr1.length < modArr2.length) { - let avg = sum1 / modArr1.length; - sum1 += avg; - } - } - modArr1.sort((a, b) => b.rank - a.rank); - modArr2.sort((a, b) => b.rank - a.rank); - console.log( - `${ - attempts > 999 ? "forced" : "successful" - } sort after ${attempts} attempts: - ${modArr1.map((i) => i.rank)} - ${modArr2.map((i) => i.rank)} - ${sum1} ${sum2} (${unequalAllowance}) - ${avgDiff(modArr1)} ${avgDiff(modArr2)} (${passion})` - ); - - return [modArr1, modArr2]; -}; - client.on("ready", () => { console.log(`Logged in as ${client.user.tag}!`); console.log( @@ -211,7 +79,10 @@ client.on("interactionCreate", async (interaction) => { if (fileCommand.permissions) { const member = interaction.member; for (const permission of fileCommand.permissions) { - if (!member.roles.cache.has(permission) && member.id !== USER_ID_DEBUG) { + if ( + !member.roles.cache.has(permission) && + member.id !== USER_ID_DEBUG + ) { await interaction.reply({ content: "You lack the required permissions", ephemeral: true, @@ -228,657 +99,6 @@ client.on("interactionCreate", async (interaction) => { ephemeral: true, }); } - } else if (interaction.channelId !== TEXT_ID_COMMAND) { - //let isRunner = await interaction.member.roles.cache.has(ROLE_ID_RUNNER); - //if (!isRunner) { - await interaction.reply({ - content: "Wrong channel, or you lack the required permissions", - ephemeral: true, - }); - return; - } - - if (command === "pick" || command === "autocaptain") { - await interaction.reply("Picking teams..."); - - // get voice channels - const picking = interaction.guild.channels.cache.find( - (channel) => channel.name === "picking" || channel.id === VOICE_ID_PICKING - ); - if (!picking) return console.error("Can't find channel 'picking'!"); - const blu = interaction.guild.channels.cache.find( - (channel) => channel.name === "blu" || channel.id === VOICE_ID_BLU - ); - if (!blu) return console.error("Can't find channel 'blu'!"); - const red = interaction.guild.channels.cache.find( - (channel) => channel.name === "red" || channel.id === VOICE_ID_RED - ); - if (!red) return console.error("Can't find channel 'red'!"); - - // get players in voice channel - const players = picking.members; - if (players.size !== 18) { - return await interaction.followUp( - `Found ${players.size} players in picking, expected 18` - ); - } - - // get rankings - let rankings = {}; - try { - console.log(`Getting rankings at ${rankingsPath}...`); - if (!fs.existsSync(rankingsPath)) { - fs.writeFileSync(rankingsPath, "{}"); - } - rankings = JSON.parse(fs.readFileSync(rankingsPath)); - } catch (error) { - console.error(error); - return await message.reply("Error sorting teams"); - } - - // distribute unranked players evenly, then randomly assign ranked players - let rankedPlayers = [], - bluPlayers = [], - redPlayers = [], - rng = 0; - - for (const [playerId, player] of players) { - if (!rankings[playerId]) { - rng = Math.random(); - // if teams are even, randomly assign - if (bluPlayers.length === redPlayers.length) { - if (rng < 0.5) { - bluPlayers.push({ player, rank: 0 }); - } else { - redPlayers.push({ player, rank: 0 }); - } - } - // otherwise, equalize teams - else if (bluPlayers.length < redPlayers.length) { - bluPlayers.push({ player, rank: 0 }); - } else { - redPlayers.push({ player, rank: 0 }); - } - } - // prepare ranked players for random assignment - else { - rankedPlayers.push(player); - } - } - - // slots for ranked players are limited by unranked players, who are sorted differently - let bluRankedPlayers = [], - redRankedPlayers = [], - bluRankSlots = 9 - bluPlayers.length, - redRankSlots = 9 - redPlayers.length; - - // create array with players and their ranks - for (const player of rankedPlayers) { - rng = Math.random(); - if (rng < 0.5) { - if (bluRankedPlayers.length < bluRankSlots) { - bluRankedPlayers.push({ player, rank: rankings[player.id] }); - } else { - redRankedPlayers.push({ player, rank: rankings[player.id] }); - } - } else { - if (redRankedPlayers.length < redRankSlots) { - redRankedPlayers.push({ player, rank: rankings[player.id] }); - } else { - bluRankedPlayers.push({ player, rank: rankings[player.id] }); - } - } - } - - if ( - bluPlayers.length + bluRankedPlayers.length !== 9 || - redPlayers.length + redRankedPlayers.length !== 9 - ) { - console.error( - `Invalid number of players: ${bluPlayers.length} ${bluRankedPlayers.length} ${redPlayers.length} ${redRankedPlayers.length}` - ); - return await message.reply("Error sorting teams"); - } - - // bring teams to reasonable balance - let [bluBalanced, redBalanced] = balanceArrays( - bluRankedPlayers, - redRankedPlayers - ); - bluPlayers = bluPlayers.concat(bluBalanced); - redPlayers = redPlayers.concat(redBalanced); - - // sort alphebetically then build string - bluPlayers.sort((a, b) => - a.player.displayName.localeCompare(b.player.displayName) - ); - redPlayers.sort((a, b) => - a.player.displayName.localeCompare(b.player.displayName) - ); - - try { - let teamStr = `${backticks}BLU:`; - for (const player of bluPlayers) { - teamStr += `\n${player.player.displayName}`; - } - teamStr += `\n\nRED:`; - for (const player of redPlayers) { - teamStr += `\n${player.player.displayName}`; - } - teamStr += backticks; - - await interaction.followUp(teamStr); - } catch (error) { - console.error(error); - await interaction.followUp("Couldn't print teams before moving players"); - } - - let moveErr = 0; - - // move to team voice channels - while (bluPlayers.length > 0) { - const idx = Math.floor(Math.random() * bluPlayers.length); - const player = bluPlayers.splice(idx, 1)[0]; - try { - await player.player.voice.setChannel(blu); - } catch (error) { - console.error(error); - moveErr++; - } - } - - while (redPlayers.length > 0) { - const idx = Math.floor(Math.random() * redPlayers.length); - const player = redPlayers.splice(idx, 1)[0]; - try { - await player.player.voice.setChannel(red); - } catch (error) { - console.error(error); - moveErr++; - } - } - - interaction.followUp( - `Players moved into teams${ - moveErr > 0 ? ` (error moving ${moveErr} members)` : "" - }` - ); - } -}); - -/* - * DM commands - * - setrank: saves a player's rank - * - getrank: prints a player's rank - * - rankings: prints all players' ranks - * - fun: prints or sets the FUN value - * - passion: prints or sets the PASSION value - * - simulateteams: simulates autocaptain results - * - whitelist: adds an admin to the whitelist to use DM commands - * - getwhitelist: prints the whitelist - * - clearwhitelist: clears the whitelist completely, security measure - */ -client.on("messageCreate", async (message) => { - if (message.author.bot || message.guild) return; - - // check if user is whitelisted - if (!whitelistStr.includes(message.author.id)) { - return; - } - - if (message.content.toLowerCase().includes("hello penguin")) { - await message.reply(`Hello ${message.author.username}`); - return; - } - - const pickupGuild = client.guilds.cache.get(GUILD_ID); - if (!pickupGuild) { - await message.reply("Could not find guild"); - return; - } - - const args = message.content.toLowerCase().split(" "); - - if (args[0] === "setrank") { - if (args.length < 3) { - await message.reply( - "Invalid number of arguments. usage: `setrank `" - ); - return; - } - - const player = findPlayer(pickupGuild, args[1]); - if (!player) { - await message.reply( - `Could not find player ${args[1]}. If this issue persists, try copy/pasting the player's Discord handle or user ID` - ); - return; - } - - const playerId = player.id; - const applicableName = getApplicableName(player); - - const rank = parseInt(args[2]); - if (isNaN(rank) || rank < 0 || rank > 5) { - await message.reply( - `Invalid rank ${args[2]}. Supply an integer between 0 and 5` - ); - return; - } - - // create rankings.json if it doesn't exist - const rankingsPath = path.join(__dirname, "rankings.json"); - if (!fs.existsSync(rankingsPath)) { - fs.writeFileSync(rankingsPath, "{}"); - } - - // rankings.json is a map of player's id to rank - const rankings = JSON.parse(fs.readFileSync(rankingsPath)); - rankings[playerId] = rank; - - console.log( - `Setting rank of ${applicableName}, ${playerId} to ${rank} at ${rankingsPath}...` - ); - new Promise((resolve, reject) => { - fs.writeFile(rankingsPath, JSON.stringify(rankings), (err) => { - if (err) reject(err); - else resolve(); - }); - }).then((res, err) => { - if (err) { - console.error(err); - message.reply(`Error setting rank: ${err.message}`); - } else { - message.reply(`Set rank of ${applicableName} to ${rank}`); - } - }); - } - - if (args[0] === "getrank") { - if (args.length < 2) { - await message.reply( - "Invalid number of arguments. Usage: `getrank `" - ); - return; - } - - const player = findPlayer(pickupGuild, args[1]); - if (!player) { - await message.reply( - `Could not find player ${args[1]}. If this issue persists, try copy/pasting the player's Discord handle or user ID` - ); - return; - } - - const playerId = player.id; - const applicableName = getApplicableName(player); - - try { - console.log( - `Getting rank of ${applicableName}, ${playerId} at ${rankingsPath}...` - ); - if (!fs.existsSync(rankingsPath)) { - fs.writeFileSync(rankingsPath, "{}"); - } - const rankings = JSON.parse(fs.readFileSync(rankingsPath)); - await message.reply( - `${backticks}${applicableName} - ${"*".repeat( - rankings[playerId] - )}${backticks}` - ); - } catch (error) { - console.error(error); - await message.reply(`Error getting rank: ${error.message}`); - } - } - - if (args[0] === "rankings") { - await message.reply("Getting rankings..."); - try { - console.log(`Getting rankings at ${rankingsPath}...`); - if (!fs.existsSync(rankingsPath)) { - fs.writeFileSync(rankingsPath, "{}"); - } - const rankings = JSON.parse(fs.readFileSync(rankingsPath)); - let players = []; - for (const [playerId, rank] of Object.entries(rankings)) { - if (rank > 0) { - const player = await pickupGuild.members.fetch(playerId); - if (!player) { - console.error(`Could not find player ${playerId}`); - continue; - } - const applicableName = getApplicableName(player); - players.push({ name: applicableName, rank }); - } - } - - // sort by rank, then name - players.sort((a, b) => { - if (a.rank === b.rank) { - return a.name.localeCompare(b.name); - } - return b.rank - a.rank; - }); - - // build string - let str = ""; - const maxNameLength = Math.max(...players.map((p) => p.name.length)); - for (const { name, rank } of players) { - str += `${name.padEnd(maxNameLength, " ")} - ${"*".repeat(rank)}\n`; - } - if (str === "") str = "No rankings found"; - if (str.length > 2000) { - let chunks = str.match(/[\s\S]{1,1990}/g); - for (let chunk of chunks) { - await message.reply(`${backticks}${chunk}${backticks}`); - } - } else { - await message.reply(`${backticks}${str}${backticks}`); - } - } catch (error) { - console.error(error); - await message.reply(`Error getting rankings: ${error.message}`); - } - } - - if (args[0] === "fun") { - if ( - args.length < 2 || - isNaN(args[1]) || - parseInt(args[1]) < 1 || - parseInt(args[1]) > 10 - ) - return await message.reply( - `Current FUN value: ${funInput}\nUsage: \`fun <1-10>\`` - ); - funInput = parseInt(args[1]); - return await message.reply(`FUN value set to ${funInput}`); - } - - if (args[0] === "passion") { - if ( - args.length < 2 || - isNaN(args[1]) || - parseInt(args[1]) < 1 || - parseInt(args[1]) > 5 - ) - return await message.reply( - `Current PASSION: ${passionInput}\nUsage: \`passion <1-5>\`` - ); - passionInput = parseInt(args[1]); - return await message.reply(`PASSION set to ${passionInput}`); - } - - if (args[0] === "simulateteams") { - await message.reply("Simulating teams..."); - - // get players in voice channel - // const players = picking.members; - // if (players.size !== 18) { - // return await message.reply( - // `Found ${players.size} players in picking, expected 18` - // ); - // } - - // simulate input is 18 player display names separated by commas - const playerInputs = args[1].split(","); - if (playerInputs.length !== 18) { - return await message.reply( - `Found ${playerInputs.length} players in input, expected 18 - \nUsage: \`simulateteams ,,...,\`` - ); - } - - // get players from input - let players = new Map(); - for (const input of playerInputs) { - const player = findPlayer(pickupGuild, input); - if (!player) { - await message.reply(`Could not find player ${input}`); - return; - } - players.set(player.id, player); - } - - // get rankings - let rankings = {}; - try { - console.log(`Getting rankings at ${rankingsPath}...`); - if (!fs.existsSync(rankingsPath)) { - fs.writeFileSync(rankingsPath, "{}"); - } - rankings = JSON.parse(fs.readFileSync(rankingsPath)); - } catch (error) { - console.error(error); - return await message.reply("Error sorting teams"); - } - - // distribute unranked players evenly, then randomly assign ranked players - let rankedPlayers = [], - bluPlayers = [], - redPlayers = [], - rng = 0; - - for (const [playerId, player] of players) { - if (!rankings[playerId]) { - rng = Math.random(); - // if teams are even, randomly assign - if (bluPlayers.length === redPlayers.length) { - if (rng < 0.5) { - bluPlayers.push({ player, rank: 0 }); - } else { - redPlayers.push({ player, rank: 0 }); - } - } - // otherwise, equalize teams - else if (bluPlayers.length < redPlayers.length) { - bluPlayers.push({ player, rank: 0 }); - } else { - redPlayers.push({ player, rank: 0 }); - } - } - // prepare ranked players for random assignment - else { - rankedPlayers.push(player); - } - } - console.log( - `bluUnranked: ${bluPlayers.length} redUnranked: ${redPlayers.length}` - ); - - // slots for ranked players are limited by unranked players, who are sorted differently - let bluRankedPlayers = [], - redRankedPlayers = [], - bluRankSlots = 9 - bluPlayers.length, - redRankSlots = 9 - redPlayers.length; - - console.log(`bluRankSlots: ${bluRankSlots} redRankSlots: ${redRankSlots}`); - - // create array with players and their ranks - for (const player of rankedPlayers) { - rng = Math.random(); - console.log( - `rng: ${rng}, bluRankedPlayers: ${bluRankedPlayers.length}, redRankedPlayers: ${redRankedPlayers.length}` - ); - if (rng < 0.5) { - if (bluRankedPlayers.length < bluRankSlots) { - bluRankedPlayers.push({ player, rank: rankings[player.id] }); - } else { - redRankedPlayers.push({ player, rank: rankings[player.id] }); - } - } else { - if (redRankedPlayers.length < redRankSlots) { - redRankedPlayers.push({ player, rank: rankings[player.id] }); - } else { - bluRankedPlayers.push({ player, rank: rankings[player.id] }); - } - } - } - - if ( - bluPlayers.length + bluRankedPlayers.length !== 9 || - redPlayers.length + redRankedPlayers.length !== 9 - ) { - console.error( - `Invalid number of players: ${bluPlayers.length} ${bluRankedPlayers.length} ${redPlayers.length} ${redRankedPlayers.length}` - ); - return await message.reply("Error sorting teams"); - } - - // bring teams to reasonable balance - let [bluBalanced, redBalanced] = balanceArrays( - bluRankedPlayers, - redRankedPlayers - ); - bluPlayers = bluPlayers.concat(bluBalanced); - redPlayers = redPlayers.concat(redBalanced); - - let moveErr = 0; - - // for sim, print teams after sorting by rank then name - bluPlayers.sort((a, b) => { - if (a.rank === b.rank) { - return a.player.displayName.localeCompare(b.player.displayName); - } - return b.rank - a.rank; - }); - redPlayers.sort((a, b) => { - if (a.rank === b.rank) { - return a.player.displayName.localeCompare(b.player.displayName); - } - return b.rank - a.rank; - }); - let simString = `${backticks}BLU:`; - - // move to team voice channels - while (bluPlayers.length > 0) { - //let idx = Math.floor(Math.random() * bluPlayers.length); - //if (idx === bluPlayers.length) idx--; - let idx = 0; - const player = bluPlayers.splice(idx, 1)[0]; - try { - //await player.voice.setChannel(blu); - simString += `\n${getApplicableName(player.player)} - ${"*".repeat( - player.rank - )}`; - } catch (error) { - console.error(error); - moveErr++; - } - } - - simString += `\n\nRED:`; - while (redPlayers.length > 0) { - //let idx = Math.floor(Math.random() * redPlayers.length); - //if (idx === redPlayers.length) idx--; - let idx = 0; - const player = redPlayers.splice(idx, 1)[0]; - try { - //await player.voice.setChannel(red); - simString += `\n${getApplicableName(player.player)} - ${"*".repeat( - player.rank - )}`; - } catch (error) { - console.error(error); - moveErr++; - } - } - - message.reply( - `Simulated teams:\n${simString}${backticks}${ - moveErr > 0 ? ` (error moving ${moveErr} members)` : "" - }${attempts > 999 ? "(forced)" : ""}` - ); - } - - if (args[0] === "whitelist") { - // add user to config.json whitelist - if (args.length < 2) { - await message.reply( - "Invalid number of arguments. Usage: `whitelist `" - ); - return; - } - - const name = args[1]; - const player = findPlayer(pickupGuild, name); - if (!player) { - await message.reply( - `Could not find player ${name}. If this issue persists, try copy/pasting the player's Discord handle or user ID` - ); - return; - } - - const playerId = player.id; - const applicableName = getApplicableName(player); - - if (whitelistStr.includes(playerId)) { - await message.reply( - `User ${applicableName} (${playerId}) is already whitelisted` - ); - return; - } - - const configPath = path.join(__dirname, "config.json"); - const config = JSON.parse(fs.readFileSync(configPath)); - whitelistStr += `,${playerId}`; - config.RANKING_WHITELIST = whitelistStr; - new Promise((resolve, reject) => { - fs.writeFile(configPath, JSON.stringify(config), (err) => { - if (err) reject(err); - else resolve(); - }); - }).then((res, err) => { - if (err) { - console.error(err); - message.reply(`Error whitelisting user: ${err.message}`); - } else { - message.reply( - `Whitelisted user ${applicableName} (${playerId}). If this was done in error, please contact an admin` - ); - } - }); - } - - if (args[0] === "getwhitelist") { - let str = `${backticks}${whitelistStr}${backticks}${backticks}`; - const whitelistIds = whitelistStr.split(","); - for (const id of whitelistIds) { - const player = findPlayer(pickupGuild, id); - if (player) { - str += `\n${getApplicableName(player)}`; - } - } - str += `${backticks}`; - await message.reply(str); - } - - if (args[0] === "clearwhitelist") { - if (args[1] !== "confirm") { - await message.reply( - "This command will clear the whitelist and prevent further DM commands. This will require manual intervention to undo. To confirm, use `clearwhitelist confirm`" - ); - return; - } else { - const configPath = path.join(__dirname, "config.json"); - const config = JSON.parse(fs.readFileSync(configPath)); - whitelistStr = ""; - config.RANKING_WHITELIST = whitelistStr; - new Promise((resolve, reject) => { - fs.writeFile(configPath, JSON.stringify(config), (err) => { - if (err) reject(err); - else resolve(); - }); - }).then((res, err) => { - if (err) { - console.error(err); - message.reply(`Error clearing whitelist: ${err.message}`); - } else { - message.reply("Whitelist cleared, please alert an admin"); - } - }); - } } });