From 03ead92c19809637a0db7920d27781cffd8e5a55 Mon Sep 17 00:00:00 2001 From: Almeida Date: Fri, 7 May 2021 20:06:31 +0100 Subject: [PATCH] added join and leave voice channel triggers --- backend/src/plugins/Automod/AutomodPlugin.ts | 3 +- .../events/runAutomodOnVoiceStateUpdate.ts | 58 +++++++++++++++++++ .../Automod/triggers/availableTriggers.ts | 11 ++++ .../Automod/triggers/joinVoiceChannel.ts | 37 ++++++++++++ .../Automod/triggers/leaveVoiceChannel.ts | 37 ++++++++++++ .../Automod/triggers/moveVoiceChannel.ts | 58 +++++++++++++++++++ backend/src/plugins/Automod/types.ts | 4 ++ 7 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 backend/src/plugins/Automod/events/runAutomodOnVoiceStateUpdate.ts create mode 100644 backend/src/plugins/Automod/triggers/joinVoiceChannel.ts create mode 100644 backend/src/plugins/Automod/triggers/leaveVoiceChannel.ts create mode 100644 backend/src/plugins/Automod/triggers/moveVoiceChannel.ts diff --git a/backend/src/plugins/Automod/AutomodPlugin.ts b/backend/src/plugins/Automod/AutomodPlugin.ts index 72cb7aa5..48a0afbf 100644 --- a/backend/src/plugins/Automod/AutomodPlugin.ts +++ b/backend/src/plugins/Automod/AutomodPlugin.ts @@ -29,6 +29,7 @@ import { RunAutomodOnThreadDelete, RunAutomodOnThreadUpdate, } from "./events/runAutomodOnThreadEvents"; +import { RunAutomodOnVoiceStateUpdate } from "./events/runAutomodOnVoiceStateUpdate"; import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges"; import { clearOldRecentActions } from "./functions/clearOldRecentActions"; import { clearOldRecentSpam } from "./functions/clearOldRecentSpam"; @@ -207,7 +208,6 @@ export const AutomodPlugin = zeppelinGuildPlugin()({ }, }, - // prettier-ignore events: [ RunAutomodOnJoinEvt, RunAutomodOnMemberUpdate, @@ -215,6 +215,7 @@ export const AutomodPlugin = zeppelinGuildPlugin()({ RunAutomodOnThreadCreate, RunAutomodOnThreadDelete, RunAutomodOnThreadUpdate + RunAutomodOnVoiceStateUpdate, // Messages use message events from SavedMessages, see onLoad below ], diff --git a/backend/src/plugins/Automod/events/runAutomodOnVoiceStateUpdate.ts b/backend/src/plugins/Automod/events/runAutomodOnVoiceStateUpdate.ts new file mode 100644 index 00000000..1726f35c --- /dev/null +++ b/backend/src/plugins/Automod/events/runAutomodOnVoiceStateUpdate.ts @@ -0,0 +1,58 @@ +import { typedGuildEventListener } from "knub"; +import { AutomodContext, AutomodPluginType } from "../types"; +import { runAutomod } from "../functions/runAutomod"; +import { noop } from "../../../utils"; + +export const RunAutomodOnVoiceStateUpdate = typedGuildEventListener()({ + event: "voiceStateUpdate", + async listener({ pluginData, args: { newState, oldState } }) { + const oldChannel = newState.channel; + const { channel: newChannel, guild } = newState; + const timestamp = Date.now(); + + const member = newState.member ?? oldState.member ?? (await guild.members.fetch(newState.id).catch(noop)); + if (!member) return; + + if (!oldChannel && newChannel) { + const context: AutomodContext = { + member, + timestamp, + voiceChannel: { + joined: newChannel, + }, + user: member.user, + }; + + pluginData.state.queue.add(() => { + runAutomod(pluginData, context); + }); + } else if (oldChannel && !newChannel) { + const context: AutomodContext = { + member, + timestamp, + voiceChannel: { + left: oldChannel, + }, + user: member.user, + }; + + pluginData.state.queue.add(() => { + runAutomod(pluginData, context); + }); + } else if (oldChannel?.id && newChannel?.id && oldChannel.id === newChannel.id) { + const context: AutomodContext = { + member, + timestamp, + voiceChannel: { + left: oldChannel, + joined: newChannel, + }, + user: member.user, + }; + + pluginData.state.queue.add(() => { + runAutomod(pluginData, context); + }); + } + }, +}); diff --git a/backend/src/plugins/Automod/triggers/availableTriggers.ts b/backend/src/plugins/Automod/triggers/availableTriggers.ts index ea8b6f04..bd2e79a8 100644 --- a/backend/src/plugins/Automod/triggers/availableTriggers.ts +++ b/backend/src/plugins/Automod/triggers/availableTriggers.ts @@ -7,7 +7,9 @@ import { BanTrigger } from "./ban"; import { CharacterSpamTrigger } from "./characterSpam"; import { CounterTrigger } from "./counterTrigger"; import { EmojiSpamTrigger } from "./emojiSpam"; +import { JoinVoiceChannelTrigger } from "./joinVoiceChannel"; import { KickTrigger } from "./kick"; +import { LeaveVoiceChannelTrigger } from "./leaveVoiceChannel"; import { LineSpamTrigger } from "./lineSpam"; import { LinkSpamTrigger } from "./linkSpam"; import { MatchAttachmentTypeTrigger } from "./matchAttachmentType"; @@ -21,6 +23,7 @@ import { MemberJoinSpamTrigger } from "./memberJoinSpam"; import { MemberLeaveTrigger } from "./memberLeave"; import { MentionSpamTrigger } from "./mentionSpam"; import { MessageSpamTrigger } from "./messageSpam"; +import { MoveVoiceChannelTrigger } from "./moveVoiceChannel"; import { MuteTrigger } from "./mute"; import { NoteTrigger } from "./note"; import { RoleAddedTrigger } from "./roleAdded"; @@ -69,6 +72,10 @@ export const availableTriggers: Record ban: BanTrigger, unban: UnbanTrigger, + join_voice_channel: JoinVoiceChannelTrigger, + leave_voice_channel: LeaveVoiceChannelTrigger, + move_voice_channel: MoveVoiceChannelTrigger, + antiraid_level: AntiraidLevelTrigger, thread_create: ThreadCreateTrigger, @@ -112,6 +119,10 @@ export const AvailableTriggers = t.type({ ban: BanTrigger.configType, unban: UnbanTrigger.configType, + join_voice_channel: JoinVoiceChannelTrigger.configType, + leave_voice_channel: LeaveVoiceChannelTrigger.configType, + move_voice_channel: MoveVoiceChannelTrigger.configType, + antiraid_level: AntiraidLevelTrigger.configType, thread_create: ThreadCreateTrigger.configType, diff --git a/backend/src/plugins/Automod/triggers/joinVoiceChannel.ts b/backend/src/plugins/Automod/triggers/joinVoiceChannel.ts new file mode 100644 index 00000000..ecd34e3e --- /dev/null +++ b/backend/src/plugins/Automod/triggers/joinVoiceChannel.ts @@ -0,0 +1,37 @@ +import * as t from "io-ts"; +import { automodTrigger } from "../helpers"; + +interface JoinVoiceChannelResult { + matchedChannelId: string; +} + +export const JoinVoiceChannelTrigger = automodTrigger()({ + configType: t.union([t.string, t.array(t.string)]), + + defaultConfig: "", + + async match({ triggerConfig, context }) { + if (!context.member || !context.voiceChannel) { + return; + } + + const triggerChannels = Array.isArray(triggerConfig) ? triggerConfig : [triggerConfig]; + if (!triggerChannels.includes(context.voiceChannel.id)) { + return; + } + + return { + extra: { + matchedChannelId: context.voiceChannel.id, + }, + }; + }, + + renderMatchInformation({ matchResult, pluginData, contexts }) { + const channel = pluginData.guild.channels.get(matchResult.extra.matchedChannelId); + const channelName = channel?.name || "Unknown"; + const member = contexts[0].member!; + const memberName = `**${member.user.username}#${member.user.discriminator}** (\`${member.id}\`)`; + return `${memberName} has joined the ${channelName} (\`${matchResult.extra.matchedChannelId}\`) voice channel`; + }, +}); diff --git a/backend/src/plugins/Automod/triggers/leaveVoiceChannel.ts b/backend/src/plugins/Automod/triggers/leaveVoiceChannel.ts new file mode 100644 index 00000000..51b6467e --- /dev/null +++ b/backend/src/plugins/Automod/triggers/leaveVoiceChannel.ts @@ -0,0 +1,37 @@ +import * as t from "io-ts"; +import { automodTrigger } from "../helpers"; + +interface LeaveVoiceChannelResult { + matchedChannelId: string; +} + +export const LeaveVoiceChannelTrigger = automodTrigger()({ + configType: t.union([t.string, t.array(t.string)]), + + defaultConfig: "", + + async match({ triggerConfig, context }) { + if (!context.member || !context.voiceChannel) { + return; + } + + const triggerChannels = Array.isArray(triggerConfig) ? triggerConfig : [triggerConfig]; + if (!triggerChannels.includes(context.voiceChannel.id)) { + return; + } + + return { + extra: { + matchedChannelId: context.voiceChannel.id, + }, + }; + }, + + renderMatchInformation({ matchResult, pluginData, contexts }) { + const channel = pluginData.guild.channels.get(matchResult.extra.matchedChannelId); + const channelName = channel?.name || "Unknown"; + const member = contexts[0].member!; + const memberName = `**${member.user.username}#${member.user.discriminator}** (\`${member.id}\`)`; + return `${memberName} has left the ${channelName} (\`${matchResult.extra.matchedChannelId}\`) voice channel`; + }, +}); diff --git a/backend/src/plugins/Automod/triggers/moveVoiceChannel.ts b/backend/src/plugins/Automod/triggers/moveVoiceChannel.ts new file mode 100644 index 00000000..b31ea256 --- /dev/null +++ b/backend/src/plugins/Automod/triggers/moveVoiceChannel.ts @@ -0,0 +1,58 @@ +import * as t from "io-ts"; +import { ChannelTypeStrings } from "../../../types"; +import { automodTrigger } from "../helpers"; + +interface MoveVoiceChannelResult { + oldChannelId: string; + newChannelId: string; +} + +export const MoveVoiceChannelTrigger = automodTrigger()({ + configType: t.type({ + old_channel: t.union([t.string, t.array(t.string)]), + new_channel: t.union([t.string, t.array(t.string)]), + }), + + defaultConfig: {}, + + async match({ triggerConfig, context }) { + const oldChannelId = context.voiceChannel?.left?.id; + const newChannelId = context.voiceChannel?.joined?.id; + + if (!context.member || !oldChannelId || !newChannelId) { + return; + } + + const triggerOldChannels = Array.isArray(triggerConfig.old_channel) + ? triggerConfig.old_channel + : [triggerConfig.old_channel]; + + const triggerNewChannels = Array.isArray(triggerConfig.new_channel) + ? triggerConfig.new_channel + : [triggerConfig.new_channel]; + + if (!triggerOldChannels.includes(oldChannelId) || !triggerNewChannels.includes(newChannelId)) { + return; + } + + return { + extra: { + oldChannelId, + newChannelId, + }, + }; + }, + + renderMatchInformation({ matchResult, pluginData, contexts }) { + const { newChannelId, oldChannelId } = matchResult.extra; + const oldChannel = pluginData.guild.channels.resolve(oldChannelId); + const newChannel = pluginData.guild.channels.resolve(newChannelId); + const member = contexts[0].member!; + const memberName = `**${member.user.username}#${member.user.discriminator}** (\`${member.id}\`)`; + const oldChannelName = oldChannel?.name ?? "Unknown"; + const newChannelName = newChannel?.name ?? "Unknown"; + const oldChannelVoiceOrStage = oldChannel?.type === ChannelTypeStrings.STAGE ? "stage" : "voice"; + const newChannelVoiceOrStage = newChannel?.type === ChannelTypeStrings.STAGE ? "stage" : "voice"; + return `${memberName} has moved from the the ${oldChannelName} (\`${oldChannelId}\`) ${oldChannelVoiceOrStage} channel to the ${newChannelName} (\`${newChannelId}\`) ${newChannelVoiceOrStage} channel`; + }, +}); diff --git a/backend/src/plugins/Automod/types.ts b/backend/src/plugins/Automod/types.ts index ed7cf56e..c85c2d51 100644 --- a/backend/src/plugins/Automod/types.ts +++ b/backend/src/plugins/Automod/types.ts @@ -140,6 +140,10 @@ export interface AutomodContext { unlocked?: ThreadChannel; }; channel?: TextChannel | ThreadChannel; + voiceChannel?: { + joined?: VoiceChannel | StageChannel; + left?: VoiceChannel | StageChannel; + }; } export interface RecentAction {