From 18b0948e6b030244098bda44e56028cf94fddcd3 Mon Sep 17 00:00:00 2001 From: almeidx Date: Tue, 15 Mar 2022 12:06:37 +0000 Subject: [PATCH] add match_mentions automod trigger --- backend/src/data/GuildSavedMessages.ts | 10 ++++ backend/src/data/entities/SavedMessage.ts | 9 +++ .../Automod/triggers/availableTriggers.ts | 3 + .../plugins/Automod/triggers/matchMentions.ts | 60 +++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 backend/src/plugins/Automod/triggers/matchMentions.ts diff --git a/backend/src/data/GuildSavedMessages.ts b/backend/src/data/GuildSavedMessages.ts index e6c51e919..3e3f69e66 100644 --- a/backend/src/data/GuildSavedMessages.ts +++ b/backend/src/data/GuildSavedMessages.ts @@ -120,6 +120,16 @@ export class GuildSavedMessages extends BaseGuildRepository { })); } + if (msg.mentions) { + data.mentions = { + channels: Array.from(msg.mentions.channels.keys()), + everyone: msg.mentions.everyone, + roles: Array.from(msg.mentions.roles.keys()), + repliedUser: msg.mentions.repliedUser?.id ?? null, + users: Array.from(msg.mentions.users.keys()), + }; + } + return data; } diff --git a/backend/src/data/entities/SavedMessage.ts b/backend/src/data/entities/SavedMessage.ts index 5456970be..bf77705e4 100644 --- a/backend/src/data/entities/SavedMessage.ts +++ b/backend/src/data/entities/SavedMessage.ts @@ -64,6 +64,14 @@ export interface ISavedMessageStickerData { type: string | null; } +export interface ISavedMessageMentionsData { + channels: Snowflake[]; + everyone: boolean; + roles: Snowflake[]; + users: Snowflake[]; + repliedUser: Snowflake | null; +} + export interface ISavedMessageData { attachments?: ISavedMessageAttachmentData[]; author: { @@ -74,6 +82,7 @@ export interface ISavedMessageData { embeds?: ISavedMessageEmbedData[]; stickers?: ISavedMessageStickerData[]; timestamp: number; + mentions?: ISavedMessageMentionsData; } @Entity("messages") diff --git a/backend/src/plugins/Automod/triggers/availableTriggers.ts b/backend/src/plugins/Automod/triggers/availableTriggers.ts index ea8b6f044..f1040cc87 100644 --- a/backend/src/plugins/Automod/triggers/availableTriggers.ts +++ b/backend/src/plugins/Automod/triggers/availableTriggers.ts @@ -34,6 +34,7 @@ import { UnmuteTrigger } from "./unmute"; import { WarnTrigger } from "./warn"; import { ThreadArchiveTrigger } from "./threadArchive"; import { ThreadUnarchiveTrigger } from "./threadUnarchive"; +import { MatchMentionsTrigger } from "./matchMentions"; export const availableTriggers: Record> = { any_message: AnyMessageTrigger, @@ -44,6 +45,7 @@ export const availableTriggers: Record match_links: MatchLinksTrigger, match_attachment_type: MatchAttachmentTypeTrigger, match_mime_type: MatchMimeTypeTrigger, + match_mentions: MatchMentionsTrigger, member_join: MemberJoinTrigger, role_added: RoleAddedTrigger, role_removed: RoleRemovedTrigger, @@ -86,6 +88,7 @@ export const AvailableTriggers = t.type({ match_links: MatchLinksTrigger.configType, match_attachment_type: MatchAttachmentTypeTrigger.configType, match_mime_type: MatchMimeTypeTrigger.configType, + match_mentions: MatchMentionsTrigger.configType, member_join: MemberJoinTrigger.configType, member_leave: MemberLeaveTrigger.configType, role_added: RoleAddedTrigger.configType, diff --git a/backend/src/plugins/Automod/triggers/matchMentions.ts b/backend/src/plugins/Automod/triggers/matchMentions.ts new file mode 100644 index 000000000..59833825c --- /dev/null +++ b/backend/src/plugins/Automod/triggers/matchMentions.ts @@ -0,0 +1,60 @@ +import { Snowflake } from "discord.js"; +import * as t from "io-ts"; +import { tNullable } from "../../../utils"; +import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary"; +import { automodTrigger } from "../helpers"; + +// I couldn't figure out how to get the type of the keys of the 'configType' dynamically +type ConfigTypeKeys = "channels" | "everyone" | "users" | "roles"; + +const summaryType: Record = { + channels: "channel", + everyone: "everyone", + users: "user", + roles: "role", +}; + +interface MatchResultType { + reason: typeof summaryType[ConfigTypeKeys]; +} + +const predicate = (items: Snowflake[], configIds?: Snowflake[] | null): boolean => + !!configIds?.length && items.some((item) => configIds.includes(item)); + +export const MatchMentionsTrigger = automodTrigger()({ + configType: t.type({ + channels: tNullable(t.array(t.string)), + everyone: tNullable(t.boolean), + roles: tNullable(t.array(t.string)), + users: tNullable(t.array(t.string)), + }), + + defaultConfig: { + channels: [], + everyone: false, + roles: [], + users: [], + }, + + async match({ context, triggerConfig }) { + if (!context.message?.data.mentions) return; + + for (const key of Object.keys(summaryType) as Array) { + if (key === "everyone") { + if (triggerConfig.everyone) return { extra: { reason: summaryType.everyone } }; + continue; + } + + if (predicate(context.message.data.mentions[key], triggerConfig[key])) { + return { extra: { reason: summaryType[key] } }; + } + } + + return null; + }, + + renderMatchInformation({ pluginData, contexts, matchResult }) { + const partialSummary = getTextMatchPartialSummary(pluginData, "message", contexts[0]); + return `Matched ${matchResult.extra.reason} mention in ${partialSummary}`; + }, +});