From 8a3097f63ea7ac83f71b9e73af44123c8dbf213c Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Sat, 4 May 2019 19:18:16 +0300 Subject: [PATCH] Add a generic bot alert log type. Use this in several places. --- src/data/DefaultLogMessages.json | 4 ++- src/data/LogType.ts | 2 ++ src/plugins/Cases.ts | 29 ++++++++++++--------- src/plugins/Logs.ts | 13 ++++++++-- src/plugins/Mutes.ts | 7 +++++- src/plugins/Post.ts | 16 +++++++++--- src/plugins/Slowmode.ts | 43 +++++++++++++++++++++++++++----- src/plugins/WelcomeMessage.ts | 23 +++++++++++++++-- 8 files changed, 110 insertions(+), 27 deletions(-) diff --git a/src/data/DefaultLogMessages.json b/src/data/DefaultLogMessages.json index da307d81..b0291d5c 100644 --- a/src/data/DefaultLogMessages.json +++ b/src/data/DefaultLogMessages.json @@ -55,5 +55,7 @@ "MEMBER_MUTE_REJOIN": "⚠ Reapplied active mute for {userMention(member)} on rejoin", "SCHEDULED_MESSAGE": "⏰ {userMention(author)} scheduled a message to be posted to {channelMention(channel)} on {date} at {time} (UTC)", - "POSTED_SCHEDULED_MESSAGE": "\uD83D\uDCE8 Posted scheduled message (`{messageId}`) to {channelMention(channel)} as scheduled by {userMention(author)}" + "POSTED_SCHEDULED_MESSAGE": "\uD83D\uDCE8 Posted scheduled message (`{messageId}`) to {channelMention(channel)} as scheduled by {userMention(author)}", + + "BOT_ALERT": "⚠ {tmplEval(body)}" } diff --git a/src/data/LogType.ts b/src/data/LogType.ts index fb198e85..f08cc964 100644 --- a/src/data/LogType.ts +++ b/src/data/LogType.ts @@ -56,4 +56,6 @@ export enum LogType { SCHEDULED_MESSAGE, POSTED_SCHEDULED_MESSAGE, + + BOT_ALERT, } diff --git a/src/plugins/Cases.ts b/src/plugins/Cases.ts index b51de8e6..1ea0b09e 100644 --- a/src/plugins/Cases.ts +++ b/src/plugins/Cases.ts @@ -7,6 +7,8 @@ import { CaseTypeColors } from "../data/CaseTypeColors"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; import { GuildArchives } from "../data/GuildArchives"; import { IPluginOptions } from "knub"; +import { GuildLogs } from "../data/GuildLogs"; +import { LogType } from "../data/LogType"; interface ICasesPluginConfig { log_automatic_actions: boolean; @@ -43,6 +45,7 @@ export class CasesPlugin extends ZeppelinPlugin { protected cases: GuildCases; protected archives: GuildArchives; + protected logs: GuildLogs; getDefaultOptions(): IPluginOptions { return { @@ -56,11 +59,7 @@ export class CasesPlugin extends ZeppelinPlugin { onLoad() { this.cases = GuildCases.getInstance(this.guildId); this.archives = GuildArchives.getInstance(this.guildId); - - // this.actions.register("postCase", async args => { - // const embed = await this.getCaseEmbed(args.caseId); - // return (args.channel as TextableChannel).createMessage(embed); - // }); + this.logs = new GuildLogs(this.guildId); } protected resolveCaseId(caseOrCaseId: Case | number): number { @@ -124,9 +123,7 @@ export class CasesPlugin extends ZeppelinPlugin { (!args.automatic || config.log_automatic_actions) && args.postInCaseLogOverride !== false ) { - try { - await this.postCaseToCaseLogChannel(createdCase); - } catch (e) {} // tslint:disable-line + await this.postCaseToCaseLogChannel(createdCase); } return createdCase; @@ -173,9 +170,7 @@ export class CasesPlugin extends ZeppelinPlugin { } if ((!args.automatic || this.getConfig().log_automatic_actions) && args.postInCaseLogOverride !== false) { - try { - await this.postCaseToCaseLogChannel(theCase.id); - } catch (e) {} // tslint:disable-line + await this.postCaseToCaseLogChannel(theCase.id); } } @@ -256,9 +251,19 @@ export class CasesPlugin extends ZeppelinPlugin { * A helper to post a case embed to the case log channel */ public async postCaseToCaseLogChannel(caseOrCaseId: Case | number): Promise { + const theCase = await this.cases.find(this.resolveCaseId(caseOrCaseId)); + if (!theCase) return; + const caseEmbed = await this.getCaseEmbed(caseOrCaseId); if (!caseEmbed) return; - return this.postToCaseLogChannel(caseEmbed); + try { + return this.postToCaseLogChannel(caseEmbed); + } catch (e) { + this.logs.log(LogType.BOT_ALERT, { + body: `Failed to post case #${theCase.case_number} to the case log channel`, + }); + return null; + } } } diff --git a/src/plugins/Logs.ts b/src/plugins/Logs.ts index 4280d952..dd86dbc7 100644 --- a/src/plugins/Logs.ts +++ b/src/plugins/Logs.ts @@ -169,7 +169,7 @@ export class LogsPlugin extends ZeppelinPlugin { let formatted; try { - formatted = await renderTemplate(format, { + const values = { ...data, userMention: async userOrMember => { if (!userOrMember) return ""; @@ -217,7 +217,16 @@ export class LogsPlugin extends ZeppelinPlugin { return result; }, - }); + }; + + if (type === LogType.BOT_ALERT) { + const valuesWithoutTmplEval = { ...values }; + values.tmplEval = str => { + return renderTemplate(str, valuesWithoutTmplEval); + }; + } + + formatted = await renderTemplate(format, values); } catch (e) { if (e instanceof TemplateParseError) { logger.error(`Error when parsing template:\nError: ${e.message}\nTemplate: ${format}`); diff --git a/src/plugins/Mutes.ts b/src/plugins/Mutes.ts index ea4593fc..f009b976 100644 --- a/src/plugins/Mutes.ts +++ b/src/plugins/Mutes.ts @@ -571,7 +571,12 @@ export class MutesPlugin extends ZeppelinPlugin { if (member) { try { await member.removeRole(this.getConfig().mute_role); - } catch (e) {} // tslint:disable-line + } catch (e) { + this.serverLogs.log(LogType.BOT_ALERT, { + body: `Failed to remove mute role from {userMention(member)}`, + member: stripObjectToScalars(member), + }); + } } await this.mutes.clear(mute.user_id); diff --git a/src/plugins/Post.ts b/src/plugins/Post.ts index a7dcfc7c..cbf61277 100644 --- a/src/plugins/Post.ts +++ b/src/plugins/Post.ts @@ -152,16 +152,26 @@ export class PostPlugin extends ZeppelinPlugin { for (const post of duePosts) { const channel = this.guild.channels.get(post.channel_id); if (channel instanceof TextChannel) { + const [username, discriminator] = post.author_name.split("#"); + const author: Partial = this.bot.users.get(post.author_id) || { + id: post.author_id, + username, + discriminator, + }; + try { const postedMessage = await this.postMessage(channel, post.content, post.attachments, post.enable_mentions); - - const [username, discriminator] = post.author_name.split("#"); this.logs.log(LogType.POSTED_SCHEDULED_MESSAGE, { - author: ({ id: post.author_id, username, discriminator } as any) as Partial, + author: stripObjectToScalars(author), channel: stripObjectToScalars(channel), messageId: postedMessage.id, }); } catch (e) { + this.logs.log(LogType.BOT_ALERT, { + body: `Failed to post scheduled message by {userMention(author)} to {channelMention(channel)}`, + channel: stripObjectToScalars(channel), + author: stripObjectToScalars(author), + }); logger.warn( `Failed to post scheduled message to #${channel.name} (${channel.id}) on ${this.guild.name} (${ this.guildId diff --git a/src/plugins/Slowmode.ts b/src/plugins/Slowmode.ts index e5014d1b..cd03d061 100644 --- a/src/plugins/Slowmode.ts +++ b/src/plugins/Slowmode.ts @@ -1,12 +1,22 @@ import { decorators as d, IPluginOptions, logger } from "knub"; import { GuildChannel, Message, TextChannel, Constants as ErisConstants, User } from "eris"; -import { convertDelayStringToMS, createChunkedMessage, errorMessage, noop, successMessage } from "../utils"; +import { + convertDelayStringToMS, + createChunkedMessage, + errorMessage, + noop, + stripObjectToScalars, + successMessage, + UnknownUser, +} from "../utils"; import { GuildSlowmodes } from "../data/GuildSlowmodes"; import humanizeDuration from "humanize-duration"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line +import { GuildLogs } from "../data/GuildLogs"; +import { LogType } from "../data/LogType"; const NATIVE_SLOWMODE_LIMIT = 6 * 60 * 60; // 6 hours const MAX_SLOWMODE = 60 * 60 * 24 * 365 * 100; // 100 years @@ -24,6 +34,7 @@ export class SlowmodePlugin extends ZeppelinPlugin { protected slowmodes: GuildSlowmodes; protected savedMessages: GuildSavedMessages; + protected logs: GuildLogs; protected clearInterval; private onMessageCreateFn; @@ -52,6 +63,7 @@ export class SlowmodePlugin extends ZeppelinPlugin { onLoad() { this.slowmodes = GuildSlowmodes.getInstance(this.guildId); this.savedMessages = GuildSavedMessages.getInstance(this.guildId); + this.logs = new GuildLogs(this.guildId); this.clearInterval = setInterval(() => this.clearExpiredSlowmodes(), BOT_SLOWMODE_CLEAR_INTERVAL); this.onMessageCreateFn = this.onMessageCreate.bind(this); @@ -78,13 +90,25 @@ export class SlowmodePlugin extends ZeppelinPlugin { try { await channel.editPermission(userId, newAllowedPermissions, newDeniedPermissions, "member"); } catch (e) { + const user = this.bot.users.get(userId) || new UnknownUser({ id: userId }); + if (e instanceof DiscordRESTError && e.code === 50013) { logger.warn( `Missing permissions to apply bot slowmode to user ${userId} on channel ${channel.name} (${ channel.id }) on server ${this.guild.name} (${this.guildId})`, ); + this.logs.log(LogType.BOT_ALERT, { + body: `Missing permissions to apply bot slowmode to {userMention(user)} in {channelMention(channel)}`, + user: stripObjectToScalars(user), + channel: stripObjectToScalars(channel), + }); } else { + this.logs.log(LogType.BOT_ALERT, { + body: `Failed to apply bot slowmode to {userMention(user)} in {channelMention(channel)}`, + user: stripObjectToScalars(user), + channel: stripObjectToScalars(channel), + }); throw e; } } @@ -190,11 +214,18 @@ export class SlowmodePlugin extends ZeppelinPlugin { return; } - await this.clearBotSlowmodeFromUserId(args.channel, args.user.id); - msg.channel.createMessage( - successMessage( - `Slowmode cleared from **${args.user.username}#${args.user.discriminator}** in <#${args.channel.id}>`, - ), + try { + await this.clearBotSlowmodeFromUserId(args.channel, args.user.id); + } catch (e) { + return this.sendErrorMessage( + msg.channel, + `Failed to clear slowmode from **${args.user.username}#${args.user.discriminator}** in <#${args.channel.id}>`, + ); + } + + this.sendSuccessMessage( + msg.channel, + `Slowmode cleared from **${args.user.username}#${args.user.discriminator}** in <#${args.channel.id}>`, ); } diff --git a/src/plugins/WelcomeMessage.ts b/src/plugins/WelcomeMessage.ts index 5812f40d..82de2a60 100644 --- a/src/plugins/WelcomeMessage.ts +++ b/src/plugins/WelcomeMessage.ts @@ -3,6 +3,8 @@ import { decorators as d, IPluginOptions } from "knub"; import { Member, TextChannel } from "eris"; import { renderTemplate } from "../templateFormatter"; import { createChunkedMessage, stripObjectToScalars } from "../utils"; +import { LogType } from "../data/LogType"; +import { GuildLogs } from "../data/GuildLogs"; interface IWelcomeMessageConfig { send_dm: boolean; @@ -13,6 +15,8 @@ interface IWelcomeMessageConfig { export class WelcomeMessagePlugin extends ZeppelinPlugin { public static pluginName = "welcome_message"; + protected logs: GuildLogs; + protected getDefaultOptions(): IPluginOptions { return { config: { @@ -23,6 +27,10 @@ export class WelcomeMessagePlugin extends ZeppelinPlugin }; } + protected onLoad() { + this.logs = new GuildLogs(this.guildId); + } + @d.event("guildMemberAdd") async onGuildMemberAdd(_, member: Member) { const config = this.getConfig(); @@ -39,7 +47,12 @@ export class WelcomeMessagePlugin extends ZeppelinPlugin try { createChunkedMessage(dmChannel, formatted); - } catch (e) {} // tslint:disable-line + } catch (e) { + this.logs.log(LogType.BOT_ALERT, { + body: `Failed send a welcome DM to {userMention(member)}`, + member: stripObjectToScalars(member), + }); + } } if (config.send_to_channel) { @@ -48,7 +61,13 @@ export class WelcomeMessagePlugin extends ZeppelinPlugin try { createChunkedMessage(channel, formatted); - } catch (e) {} // tslint:disable-line + } catch (e) { + this.logs.log(LogType.BOT_ALERT, { + body: `Failed send a welcome message for {userMention(member)} to {channelMention(channel)}`, + member: stripObjectToScalars(member), + channel: stripObjectToScalars(channel), + }); + } } } }