From 713333f35e1afb307621250e4fc82947b7f129d2 Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Fri, 11 Oct 2019 23:16:15 +0300 Subject: [PATCH] automod: don't use log system for alert actions, require channel id directly instead; allow disabling logging from specific rules --- src/data/DefaultLogMessages.json | 1 - src/data/LogType.ts | 1 - src/plugins/Automod.ts | 65 ++++++++++++++++++++++---------- src/plugins/ZeppelinPlugin.ts | 5 +++ 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/data/DefaultLogMessages.json b/src/data/DefaultLogMessages.json index 623f0278..3bd715be 100644 --- a/src/data/DefaultLogMessages.json +++ b/src/data/DefaultLogMessages.json @@ -58,6 +58,5 @@ "POSTED_SCHEDULED_MESSAGE": "\uD83D\uDCE8 Posted scheduled message (`{messageId}`) to {channelMention(channel)} as scheduled by {userMention(author)}", "BOT_ALERT": "⚠ {tmplEval(body)}", - "AUTOMOD_ALERT": "{text}", "AUTOMOD_ACTION": "\uD83E\uDD16 Automod rule **{rule}** triggered by {userMention(user)}. Actions taken: **{actionsTaken}**\n{matchSummary}" } diff --git a/src/data/LogType.ts b/src/data/LogType.ts index 64df22d8..1be6580b 100644 --- a/src/data/LogType.ts +++ b/src/data/LogType.ts @@ -58,6 +58,5 @@ export enum LogType { POSTED_SCHEDULED_MESSAGE, BOT_ALERT, - AUTOMOD_ALERT, AUTOMOD_ACTION, } diff --git a/src/plugins/Automod.ts b/src/plugins/Automod.ts index 5f13e0cd..a683a98a 100644 --- a/src/plugins/Automod.ts +++ b/src/plugins/Automod.ts @@ -13,11 +13,12 @@ import { SECONDS, stripObjectToScalars, tNullable, + UnknownUser, verboseChannelMention, } from "../utils"; import { decorators as d } from "knub"; import { mergeConfig } from "knub/dist/configUtils"; -import { Invite, Member, Message } from "eris"; +import { Invite, Member, Message, TextChannel } from "eris"; import escapeStringRegexp from "escape-string-regexp"; import { SimpleCache } from "../SimpleCache"; import { Queue } from "../Queue"; @@ -32,6 +33,7 @@ import { GuildArchives } from "../data/GuildArchives"; import { GuildLogs } from "../data/GuildLogs"; import { SavedMessage } from "../data/entities/SavedMessage"; import moment from "moment-timezone"; +import { renderTemplate } from "../templateFormatter"; type MessageInfo = { channelId: string; messageId: string }; @@ -81,7 +83,7 @@ interface RaidSpamTriggerMatchResult extends TriggerMatchResult { interface OtherSpamTriggerMatchResult extends TriggerMatchResult { type: "otherspam"; actionType: RecentActionType; - userIds: string[]; + userId: string; } type AnyTriggerMatchResult = @@ -233,6 +235,7 @@ const BanAction = t.type({ }); const AlertAction = t.type({ + channel: t.string, text: t.string, }); @@ -240,6 +243,8 @@ const ChangeNicknameAction = t.type({ name: t.string, }); +const LogAction = t.boolean; + /** * FULL CONFIG SCHEMA */ @@ -273,6 +278,7 @@ const Rule = t.type({ ban: tNullable(BanAction), alert: tNullable(AlertAction), change_nickname: tNullable(ChangeNicknameAction), + log: tNullable(LogAction), }), }); type TRule = t.TypeOf; @@ -487,6 +493,13 @@ export class AutomodPlugin extends ZeppelinPlugin { } } } + + // Enable logging of automod actions by default + if (rule["actions"] && typeof rule["actions"] === "object") { + if (rule["actions"]["log"] == null) { + rule["actions"]["log"] = true; + } + } } } @@ -1153,10 +1166,7 @@ export class AutomodPlugin extends ZeppelinPlugin { } if (rule.actions.change_nickname) { - const userIdsToChange = - matchResult.type === "raidspam" || matchResult.type === "otherspam" - ? matchResult.userIds - : [matchResult.userId]; + const userIdsToChange = matchResult.type === "raidspam" ? matchResult.userIds : [matchResult.userId]; for (const userId of userIdsToChange) { if (this.recentNicknameChanges.has(userId)) continue; @@ -1175,30 +1185,45 @@ export class AutomodPlugin extends ZeppelinPlugin { actionsTaken.push("nickname"); } - if (rule.actions.alert || matchResult.type !== "raidspam") { - const user = await this.resolveUser((matchResult as any).userId || "0"); + // Don't wait for the rest before continuing to other automod items in the queue + (async () => { + const user = matchResult.type !== "raidspam" ? this.getUser(matchResult.userId) : new UnknownUser(); + const users = matchResult.type === "raidspam" ? matchResult.userIds.map(id => this.getUser(id)) : []; + const safeUser = stripObjectToScalars(user); + const safeUsers = users.map(u => stripObjectToScalars(u)); if (rule.actions.alert) { - const text = rule.actions.alert.text; - this.getLogs().log(LogType.AUTOMOD_ALERT, { - rule: rule.name, - user: stripObjectToScalars(user), - text, - matchSummary, - }); - - actionsTaken.push("alert"); + const channel = this.guild.channels.get(rule.actions.alert.channel); + if (channel && channel instanceof TextChannel) { + const text = rule.actions.alert.text; + const rendered = await renderTemplate(rule.actions.alert.text, { + rule: rule.name, + user: safeUser, + users: safeUsers, + text, + matchSummary, + }); + channel.createMessage(rendered); + actionsTaken.push("alert"); + } else { + this.getLogs().log(LogType.BOT_ALERT, { + body: `Invalid channel id \`${rule.actions.alert.channel}\` for alert action in automod rule **${ + rule.name + }**`, + }); + } } - if (matchResult.type !== "raidspam") { + if (rule.actions.log) { this.getLogs().log(LogType.AUTOMOD_ACTION, { rule: rule.name, - user: stripObjectToScalars(user), + user: safeUser, + users: safeUsers, actionsTaken: actionsTaken.length ? actionsTaken.join(", ") : "", matchSummary, }); } - } + })(); } protected onMessageCreate(msg: SavedMessage) { diff --git a/src/plugins/ZeppelinPlugin.ts b/src/plugins/ZeppelinPlugin.ts index 16e1ee1e..8055b20e 100644 --- a/src/plugins/ZeppelinPlugin.ts +++ b/src/plugins/ZeppelinPlugin.ts @@ -204,6 +204,11 @@ export class ZeppelinPlugin extends Plug return this.getMergedOptions(); } + getUser(userResolvable: string): User | UnknownUser { + const id = resolveUserId(this.bot, userResolvable); + return id ? this.bot.users.get(id) || new UnknownUser({ id }) : new UnknownUser(); + } + /** * Resolves a user from the passed string. The passed string can be a user id, a user mention, a full username (with discrim), etc. * If the user is not found in the cache, it's fetched from the API.