diff --git a/src/plugins/Logs.ts b/src/plugins/Logs.ts index 78a8974f..5e23d308 100644 --- a/src/plugins/Logs.ts +++ b/src/plugins/Logs.ts @@ -1,16 +1,15 @@ import { decorators as d, IPluginOptions, logger } from "knub"; import { GuildLogs } from "../data/GuildLogs"; import { LogType } from "../data/LogType"; -import { Attachment, Channel, Constants as ErisConstants, Embed, Member, TextChannel, User } from "eris"; +import { Attachment, Channel, Constants as ErisConstants, Embed, Guild, Member, TextChannel, User } from "eris"; +import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line import { createChunkedMessage, - deactivateMentions, disableCodeBlocks, disableLinkPreviews, findRelevantAuditLogEntry, noop, stripObjectToScalars, - trimLines, UnknownUser, useMediaUrls, } from "../utils"; @@ -249,6 +248,20 @@ export class LogsPlugin extends ZeppelinPlugin { } } + async findRelevantAuditLogEntry(actionType: number, userId: string, attempts?: number, attemptDelay?: number) { + try { + return await findRelevantAuditLogEntry(this.guild, actionType, userId, attempts, attemptDelay); + } catch (e) { + if (e instanceof DiscordRESTError && e.code === 50013) { + this.guildLogs.log(LogType.BOT_ALERT, { + body: "Missing permissions to read audit log", + }); + } else { + throw e; + } + } + } + @d.event("guildMemberAdd") async onMemberJoin(_, member) { const newThreshold = moment().valueOf() - 1000 * 60 * 60; @@ -299,8 +312,7 @@ export class LogsPlugin extends ZeppelinPlugin { @d.event("guildBanAdd") async onMemberBan(_, user) { - const relevantAuditLogEntry = await findRelevantAuditLogEntry( - this.guild, + const relevantAuditLogEntry = await this.findRelevantAuditLogEntry( ErisConstants.AuditLogActions.MEMBER_BAN_ADD, user.id, ); @@ -318,8 +330,7 @@ export class LogsPlugin extends ZeppelinPlugin { @d.event("guildBanRemove") async onMemberUnban(_, user) { - const relevantAuditLogEntry = await findRelevantAuditLogEntry( - this.guild, + const relevantAuditLogEntry = await this.findRelevantAuditLogEntry( ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE, user.id, ); @@ -351,8 +362,7 @@ export class LogsPlugin extends ZeppelinPlugin { const addedRoles = diff(member.roles, oldMember.roles); const removedRoles = diff(oldMember.roles, member.roles); - const relevantAuditLogEntry = await findRelevantAuditLogEntry( - this.guild, + const relevantAuditLogEntry = await this.findRelevantAuditLogEntry( ErisConstants.AuditLogActions.MEMBER_ROLE_UPDATE, member.id, ); diff --git a/src/plugins/ModActions.ts b/src/plugins/ModActions.ts index 43f74c93..21a57f44 100644 --- a/src/plugins/ModActions.ts +++ b/src/plugins/ModActions.ts @@ -1,5 +1,6 @@ import { decorators as d, IPluginOptions, logger, waitForReaction, waitForReply } from "knub"; import { Attachment, Constants as ErisConstants, Guild, Member, Message, TextChannel, User } from "eris"; +import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line import humanizeDuration from "humanize-duration"; import { GuildCases } from "../data/GuildCases"; import { @@ -164,6 +165,20 @@ export class ModActionsPlugin extends ZeppelinPlugin { return bans.some(b => b.user.id === userId); } + async findRelevantAuditLogEntry(actionType: number, userId: string, attempts?: number, attemptDelay?: number) { + try { + return await findRelevantAuditLogEntry(this.guild, actionType, userId, attempts, attemptDelay); + } catch (e) { + if (e instanceof DiscordRESTError && e.code === 50013) { + this.serverLogs.log(LogType.BOT_ALERT, { + body: "Missing permissions to read audit log", + }); + } else { + throw e; + } + } + } + /** * Add a BAN action automatically when a user is banned. * Attempts to find the ban's details in the audit log. @@ -175,8 +190,7 @@ export class ModActionsPlugin extends ZeppelinPlugin { return; } - const relevantAuditLogEntry = await findRelevantAuditLogEntry( - this.guild, + const relevantAuditLogEntry = await this.findRelevantAuditLogEntry( ErisConstants.AuditLogActions.MEMBER_BAN_ADD, user.id, ); @@ -214,8 +228,7 @@ export class ModActionsPlugin extends ZeppelinPlugin { return; } - const relevantAuditLogEntry = await findRelevantAuditLogEntry( - this.guild, + const relevantAuditLogEntry = await this.findRelevantAuditLogEntry( ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE, user.id, ); @@ -273,8 +286,7 @@ export class ModActionsPlugin extends ZeppelinPlugin { return; } - const kickAuditLogEntry = await findRelevantAuditLogEntry( - this.guild, + const kickAuditLogEntry = await this.findRelevantAuditLogEntry( ErisConstants.AuditLogActions.MEMBER_KICK, member.id, ); diff --git a/src/utils.ts b/src/utils.ts index 9aded3d7..c41fa665 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,12 +3,14 @@ import { EmbedOptions, Emoji, Guild, + GuildAuditLog, GuildAuditLogEntry, Member, TextableChannel, TextChannel, User, } from "eris"; +import DiscordHTTPError from "eris/lib/errors/DiscordHTTPError"; // tslint:disable-line import url from "url"; import tlds from "tlds"; import emojiRegex from "emoji-regex"; @@ -129,9 +131,19 @@ export async function findRelevantAuditLogEntry( attempts: number = 3, attemptDelay: number = 3000, ): Promise { - const auditLogEntries = await guild.getAuditLogs(5, null, actionType); + let auditLogs: GuildAuditLog; + try { + auditLogs = await guild.getAuditLogs(5, null, actionType); + } catch (e) { + // Ignore internal server errors which seem to be pretty common with audit log requests + if (!(e instanceof DiscordHTTPError) || e.code !== 500) { + throw e; + } + } - auditLogEntries.entries.sort((a, b) => { + const entries = auditLogs ? auditLogs.entries : []; + + entries.sort((a, b) => { if (a.createdAt > b.createdAt) return -1; if (a.createdAt > b.createdAt) return 1; return 0; @@ -139,7 +151,7 @@ export async function findRelevantAuditLogEntry( const cutoffTS = Date.now() - 1000 * 60 * 2; - const relevantEntry = auditLogEntries.entries.find(entry => { + const relevantEntry = entries.find(entry => { return entry.targetID === userId && entry.createdAt >= cutoffTS; });