mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-05-25 18:25:03 +00:00
Merge 3acb089f47
into 801cd2630b
This commit is contained in:
commit
18a2eea263
7 changed files with 216 additions and 3 deletions
|
@ -29,6 +29,7 @@ import {
|
||||||
RunAutomodOnThreadDelete,
|
RunAutomodOnThreadDelete,
|
||||||
RunAutomodOnThreadUpdate,
|
RunAutomodOnThreadUpdate,
|
||||||
} from "./events/runAutomodOnThreadEvents";
|
} from "./events/runAutomodOnThreadEvents";
|
||||||
|
import { RunAutomodOnVoiceStateUpdate } from "./events/runAutomodOnVoiceStateUpdate";
|
||||||
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
|
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
|
||||||
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
||||||
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
||||||
|
@ -207,14 +208,14 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
events: [
|
events: [
|
||||||
RunAutomodOnJoinEvt,
|
RunAutomodOnJoinEvt,
|
||||||
RunAutomodOnMemberUpdate,
|
RunAutomodOnMemberUpdate,
|
||||||
RunAutomodOnLeaveEvt,
|
RunAutomodOnLeaveEvt,
|
||||||
RunAutomodOnThreadCreate,
|
RunAutomodOnThreadCreate,
|
||||||
RunAutomodOnThreadDelete,
|
RunAutomodOnThreadDelete,
|
||||||
RunAutomodOnThreadUpdate
|
RunAutomodOnThreadUpdate,
|
||||||
|
RunAutomodOnVoiceStateUpdate,
|
||||||
// Messages use message events from SavedMessages, see onLoad below
|
// Messages use message events from SavedMessages, see onLoad below
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { typedGuildEventListener } from "knub";
|
||||||
|
import { AutomodContext, AutomodPluginType } from "../types";
|
||||||
|
import { runAutomod } from "../functions/runAutomod";
|
||||||
|
import { noop } from "../../../utils";
|
||||||
|
|
||||||
|
export const RunAutomodOnVoiceStateUpdate = typedGuildEventListener<AutomodPluginType>()({
|
||||||
|
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;
|
||||||
|
|
||||||
|
const context: AutomodContext = {
|
||||||
|
member,
|
||||||
|
timestamp,
|
||||||
|
voiceChannel: {
|
||||||
|
joined: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
user: member.user,
|
||||||
|
};
|
||||||
|
let addToQueue = false;
|
||||||
|
|
||||||
|
if (!oldChannel && newChannel) {
|
||||||
|
context.voiceChannel!.joined = newChannel;
|
||||||
|
addToQueue = true;
|
||||||
|
} else if (oldChannel && !newChannel) {
|
||||||
|
context.voiceChannel!.left = oldChannel;
|
||||||
|
addToQueue = true;
|
||||||
|
} else if (oldChannel?.id && newChannel?.id && oldChannel.id === newChannel.id) {
|
||||||
|
context.voiceChannel!.left = oldChannel;
|
||||||
|
context.voiceChannel!.joined = newChannel;
|
||||||
|
addToQueue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addToQueue) {
|
||||||
|
pluginData.state.queue.add(() => {
|
||||||
|
runAutomod(pluginData, context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
|
@ -7,7 +7,9 @@ import { BanTrigger } from "./ban";
|
||||||
import { CharacterSpamTrigger } from "./characterSpam";
|
import { CharacterSpamTrigger } from "./characterSpam";
|
||||||
import { CounterTrigger } from "./counterTrigger";
|
import { CounterTrigger } from "./counterTrigger";
|
||||||
import { EmojiSpamTrigger } from "./emojiSpam";
|
import { EmojiSpamTrigger } from "./emojiSpam";
|
||||||
|
import { JoinVoiceChannelTrigger } from "./joinVoiceChannel";
|
||||||
import { KickTrigger } from "./kick";
|
import { KickTrigger } from "./kick";
|
||||||
|
import { LeaveVoiceChannelTrigger } from "./leaveVoiceChannel";
|
||||||
import { LineSpamTrigger } from "./lineSpam";
|
import { LineSpamTrigger } from "./lineSpam";
|
||||||
import { LinkSpamTrigger } from "./linkSpam";
|
import { LinkSpamTrigger } from "./linkSpam";
|
||||||
import { MatchAttachmentTypeTrigger } from "./matchAttachmentType";
|
import { MatchAttachmentTypeTrigger } from "./matchAttachmentType";
|
||||||
|
@ -21,6 +23,7 @@ import { MemberJoinSpamTrigger } from "./memberJoinSpam";
|
||||||
import { MemberLeaveTrigger } from "./memberLeave";
|
import { MemberLeaveTrigger } from "./memberLeave";
|
||||||
import { MentionSpamTrigger } from "./mentionSpam";
|
import { MentionSpamTrigger } from "./mentionSpam";
|
||||||
import { MessageSpamTrigger } from "./messageSpam";
|
import { MessageSpamTrigger } from "./messageSpam";
|
||||||
|
import { MoveVoiceChannelTrigger } from "./moveVoiceChannel";
|
||||||
import { MuteTrigger } from "./mute";
|
import { MuteTrigger } from "./mute";
|
||||||
import { NoteTrigger } from "./note";
|
import { NoteTrigger } from "./note";
|
||||||
import { RoleAddedTrigger } from "./roleAdded";
|
import { RoleAddedTrigger } from "./roleAdded";
|
||||||
|
@ -69,6 +72,10 @@ export const availableTriggers: Record<string, AutomodTriggerBlueprint<any, any>
|
||||||
ban: BanTrigger,
|
ban: BanTrigger,
|
||||||
unban: UnbanTrigger,
|
unban: UnbanTrigger,
|
||||||
|
|
||||||
|
join_voice_channel: JoinVoiceChannelTrigger,
|
||||||
|
leave_voice_channel: LeaveVoiceChannelTrigger,
|
||||||
|
move_voice_channel: MoveVoiceChannelTrigger,
|
||||||
|
|
||||||
antiraid_level: AntiraidLevelTrigger,
|
antiraid_level: AntiraidLevelTrigger,
|
||||||
|
|
||||||
thread_create: ThreadCreateTrigger,
|
thread_create: ThreadCreateTrigger,
|
||||||
|
@ -112,6 +119,10 @@ export const AvailableTriggers = t.type({
|
||||||
ban: BanTrigger.configType,
|
ban: BanTrigger.configType,
|
||||||
unban: UnbanTrigger.configType,
|
unban: UnbanTrigger.configType,
|
||||||
|
|
||||||
|
join_voice_channel: JoinVoiceChannelTrigger.configType,
|
||||||
|
leave_voice_channel: LeaveVoiceChannelTrigger.configType,
|
||||||
|
move_voice_channel: MoveVoiceChannelTrigger.configType,
|
||||||
|
|
||||||
antiraid_level: AntiraidLevelTrigger.configType,
|
antiraid_level: AntiraidLevelTrigger.configType,
|
||||||
|
|
||||||
thread_create: ThreadCreateTrigger.configType,
|
thread_create: ThreadCreateTrigger.configType,
|
||||||
|
|
43
backend/src/plugins/Automod/triggers/joinVoiceChannel.ts
Normal file
43
backend/src/plugins/Automod/triggers/joinVoiceChannel.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import * as t from "io-ts";
|
||||||
|
import { ChannelTypeStrings } from "../../../types";
|
||||||
|
import { tNullable } from "../../../utils";
|
||||||
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
|
interface JoinVoiceChannelResult {
|
||||||
|
matchedChannelId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const JoinVoiceChannelTrigger = automodTrigger<JoinVoiceChannelResult>()({
|
||||||
|
configType: t.type({
|
||||||
|
include_moves: tNullable(t.boolean),
|
||||||
|
}),
|
||||||
|
|
||||||
|
defaultConfig: {
|
||||||
|
include_moves: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
async match({ triggerConfig, context }) {
|
||||||
|
const matchedChannelId = context.voiceChannel?.joined?.id;
|
||||||
|
const includeMoves =
|
||||||
|
typeof triggerConfig === "object" && !Array.isArray(triggerConfig) && triggerConfig.include_moves;
|
||||||
|
|
||||||
|
if (!context.member || !matchedChannelId || (context.voiceChannel?.left && !includeMoves)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
extra: {
|
||||||
|
matchedChannelId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
renderMatchInformation({ matchResult, pluginData, contexts }) {
|
||||||
|
const channel = pluginData.guild.channels.resolve(matchResult.extra.matchedChannelId);
|
||||||
|
const channelName = channel?.name ?? "Unknown";
|
||||||
|
const member = contexts[0].member!;
|
||||||
|
const memberName = `**${member.user.username}#${member.user.discriminator}** (\`${member.id}\`)`;
|
||||||
|
const voiceOrStage = channel?.type === ChannelTypeStrings.STAGE ? "stage" : "voice";
|
||||||
|
return `${memberName} has joined the ${channelName} (\`${matchResult.extra.matchedChannelId}\`) ${voiceOrStage} channel`;
|
||||||
|
},
|
||||||
|
});
|
43
backend/src/plugins/Automod/triggers/leaveVoiceChannel.ts
Normal file
43
backend/src/plugins/Automod/triggers/leaveVoiceChannel.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import * as t from "io-ts";
|
||||||
|
import { ChannelTypeStrings } from "../../../types";
|
||||||
|
import { tNullable } from "../../../utils";
|
||||||
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
|
interface LeaveVoiceChannelResult {
|
||||||
|
matchedChannelId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LeaveVoiceChannelTrigger = automodTrigger<LeaveVoiceChannelResult>()({
|
||||||
|
configType: t.type({
|
||||||
|
include_moves: tNullable(t.boolean),
|
||||||
|
}),
|
||||||
|
|
||||||
|
defaultConfig: {
|
||||||
|
include_moves: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
async match({ triggerConfig, context }) {
|
||||||
|
const matchedChannelId = context.voiceChannel?.left?.id;
|
||||||
|
const includeMoves =
|
||||||
|
typeof triggerConfig === "object" && !Array.isArray(triggerConfig) && triggerConfig.include_moves;
|
||||||
|
|
||||||
|
if (!context.member || !matchedChannelId || (context.voiceChannel?.joined && !includeMoves)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
extra: {
|
||||||
|
matchedChannelId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
renderMatchInformation({ matchResult, pluginData, contexts }) {
|
||||||
|
const channel = pluginData.guild.channels.resolve(matchResult.extra.matchedChannelId);
|
||||||
|
const channelName = channel?.name ?? "Unknown";
|
||||||
|
const member = contexts[0].member!;
|
||||||
|
const memberName = `**${member.user.username}#${member.user.discriminator}** (\`${member.id}\`)`;
|
||||||
|
const voiceOrStage = channel?.type === ChannelTypeStrings.STAGE ? "stage" : "voice";
|
||||||
|
return `${memberName} has left the ${channelName} (\`${matchResult.extra.matchedChannelId}\`) ${voiceOrStage} channel`;
|
||||||
|
},
|
||||||
|
});
|
58
backend/src/plugins/Automod/triggers/moveVoiceChannel.ts
Normal file
58
backend/src/plugins/Automod/triggers/moveVoiceChannel.ts
Normal file
|
@ -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<MoveVoiceChannelResult>()({
|
||||||
|
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`;
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,4 +1,12 @@
|
||||||
import { GuildMember, PartialGuildMember, TextChannel, ThreadChannel, User } from "discord.js";
|
import {
|
||||||
|
GuildMember,
|
||||||
|
PartialGuildMember,
|
||||||
|
StageChannel,
|
||||||
|
TextChannel,
|
||||||
|
ThreadChannel,
|
||||||
|
User,
|
||||||
|
VoiceChannel,
|
||||||
|
} from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, CooldownManager } from "knub";
|
import { BasePluginType, CooldownManager } from "knub";
|
||||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||||
|
@ -140,6 +148,10 @@ export interface AutomodContext {
|
||||||
unlocked?: ThreadChannel;
|
unlocked?: ThreadChannel;
|
||||||
};
|
};
|
||||||
channel?: TextChannel | ThreadChannel;
|
channel?: TextChannel | ThreadChannel;
|
||||||
|
voiceChannel?: {
|
||||||
|
joined?: VoiceChannel | StageChannel | null;
|
||||||
|
left?: VoiceChannel | StageChannel | null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RecentAction {
|
export interface RecentAction {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue