diff --git a/backend/src/plugins/Utility/UtilityPlugin.ts b/backend/src/plugins/Utility/UtilityPlugin.ts index 2f09cdc7..bfc08657 100644 --- a/backend/src/plugins/Utility/UtilityPlugin.ts +++ b/backend/src/plugins/Utility/UtilityPlugin.ts @@ -16,7 +16,7 @@ import { NicknameCmd } from "./commands/NicknameCmd"; import { PingCmd } from "./commands/PingCmd"; import { SourceCmd } from "./commands/SourceCmd"; import { ContextCmd } from "./commands/ContextCmd"; -import { VcmoveCmd } from "./commands/VcmoveCmd"; +import { VcmoveAllCmd, VcmoveCmd } from "./commands/VcmoveCmd"; import { HelpCmd } from "./commands/HelpCmd"; import { AboutCmd } from "./commands/AboutCmd"; import { PluginOptions } from "knub"; @@ -120,6 +120,7 @@ export const UtilityPlugin = zeppelinGuildPlugin()("utility", SourceCmd, ContextCmd, VcmoveCmd, + VcmoveAllCmd, HelpCmd, AboutCmd, ReloadGuildCmd, diff --git a/backend/src/plugins/Utility/commands/VcmoveCmd.ts b/backend/src/plugins/Utility/commands/VcmoveCmd.ts index af18c41d..b80ad810 100644 --- a/backend/src/plugins/Utility/commands/VcmoveCmd.ts +++ b/backend/src/plugins/Utility/commands/VcmoveCmd.ts @@ -4,11 +4,12 @@ import { channelMentionRegex, errorMessage, isSnowflake, + resolveMember, simpleClosestStringMatch, stripObjectToScalars, } from "../../../utils"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { VoiceChannel } from "eris"; +import { Member, VoiceChannel } from "eris"; import { LogType } from "../../../data/LogType"; export const VcmoveCmd = utilityCmd({ @@ -95,3 +96,99 @@ export const VcmoveCmd = utilityCmd({ ); }, }); + +export const VcmoveAllCmd = utilityCmd({ + trigger: "vcmoveall", + description: "Move all members of a voice channel to another voice channel", + usage: "!vcmoveall 551767166395875334 767497573560352798", + permission: "can_vcmove", + + signature: { + oldChannel: ct.voiceChannel(), + channel: ct.string({ catchAll: true }), + }, + + async run({ message: msg, args, pluginData }) { + let channel: VoiceChannel; + + if (isSnowflake(args.channel)) { + // Snowflake -> resolve channel directly + const potentialChannel = pluginData.guild.channels.get(args.channel); + if (!potentialChannel || !(potentialChannel instanceof VoiceChannel)) { + sendErrorMessage(pluginData, msg.channel, "Unknown or non-voice channel"); + return; + } + + channel = potentialChannel; + } else if (channelMentionRegex.test(args.channel)) { + // Channel mention -> parse channel id and resolve channel from that + const channelId = args.channel.match(channelMentionRegex)![1]; + const potentialChannel = pluginData.guild.channels.get(channelId); + if (!potentialChannel || !(potentialChannel instanceof VoiceChannel)) { + sendErrorMessage(pluginData, msg.channel, "Unknown or non-voice channel"); + return; + } + + channel = potentialChannel; + } else { + // Search string -> find closest matching voice channel name + const voiceChannels = pluginData.guild.channels.filter(theChannel => { + return theChannel instanceof VoiceChannel; + }) as VoiceChannel[]; + const closestMatch = simpleClosestStringMatch(args.channel, voiceChannels, ch => ch.name); + if (!closestMatch) { + sendErrorMessage(pluginData, msg.channel, "No matching voice channels"); + return; + } + + channel = closestMatch; + } + + if (args.oldChannel.voiceMembers.size === 0) { + sendErrorMessage(pluginData, msg.channel, "Voice channel is empty"); + return; + } + + if (args.oldChannel.id === channel.id) { + sendErrorMessage(pluginData, msg.channel, "Cant move from and to the same channel!"); + return; + } + + // Cant leave null, otherwise we get an assignment error in the catch + let currMember = msg.member; + const moveAmt = args.oldChannel.voiceMembers.size; + try { + for (const memberWithId of args.oldChannel.voiceMembers) { + currMember = memberWithId[1]; + + currMember.edit({ + channelID: channel.id, + }); + + pluginData.state.logs.log(LogType.VOICE_CHANNEL_FORCE_MOVE, { + mod: stripObjectToScalars(msg.author), + member: stripObjectToScalars(currMember, ["user", "roles"]), + oldChannel: stripObjectToScalars(args.oldChannel), + newChannel: stripObjectToScalars(channel), + }); + } + } catch (e) { + if (msg.member.id === currMember.id) { + sendErrorMessage(pluginData, msg.channel, "Unknown error when trying to move members"); + return; + } + sendErrorMessage( + pluginData, + msg.channel, + `Failed to move ${currMember.username}#${currMember.discriminator} (${currMember.id})`, + ); + return; + } + + sendSuccessMessage( + pluginData, + msg.channel, + `All ${moveAmt} members from **${args.oldChannel.name}** moved to **${channel.name}**`, + ); + }, +});