Centralize DM logic, don't attempt DMs for an hour after a 20026 error
This commit is contained in:
parent
1d4c32d8f9
commit
902be16ae8
5 changed files with 60 additions and 16 deletions
|
@ -47,6 +47,7 @@
|
||||||
"CLEAN": "🚿 {userMention(mod)} cleaned **{count}** message(s) in {channelMention(channel)}\n{archiveUrl}",
|
"CLEAN": "🚿 {userMention(mod)} cleaned **{count}** message(s) in {channelMention(channel)}\n{archiveUrl}",
|
||||||
|
|
||||||
"CASE_CREATE": "✏ {userMention(mod)} manually created new **{caseType}** case (#{caseNum})",
|
"CASE_CREATE": "✏ {userMention(mod)} manually created new **{caseType}** case (#{caseNum})",
|
||||||
|
"CASE_DELETE": "✂️ **Case #{case.case_number}** was deleted by {userMention(mod)}",
|
||||||
|
|
||||||
"MASSBAN": "⚒ {userMention(mod)} massbanned {count} users",
|
"MASSBAN": "⚒ {userMention(mod)} massbanned {count} users",
|
||||||
"MASSMUTE": "📢🚫 {userMention(mod)} massmuted {count} users",
|
"MASSMUTE": "📢🚫 {userMention(mod)} massmuted {count} users",
|
||||||
|
@ -63,10 +64,9 @@
|
||||||
"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": "⚠ **BOT ALERT:** {tmplEval(body)}",
|
"BOT_ALERT": "⚠ **BOT ALERT:** {tmplEval(body)}",
|
||||||
|
"DM_FAILED": "\uD83D\uDEA7 Failed to send DM ({source}) to {userMention(user)}",
|
||||||
|
|
||||||
"AUTOMOD_ACTION": "\uD83E\uDD16 Automod rule **{rule}** triggered by {userMention(users)}\n{matchSummary}\nActions taken: **{actionsTaken}**",
|
"AUTOMOD_ACTION": "\uD83E\uDD16 Automod rule **{rule}** triggered by {userMention(users)}\n{matchSummary}\nActions taken: **{actionsTaken}**",
|
||||||
|
|
||||||
"SET_ANTIRAID_USER": "⚔ {userMention(user)} set anti-raid to **{level}**",
|
"SET_ANTIRAID_USER": "⚔ {userMention(user)} set anti-raid to **{level}**",
|
||||||
"SET_ANTIRAID_AUTO": "⚔ Anti-raid automatically set to **{level}**",
|
"SET_ANTIRAID_AUTO": "⚔ Anti-raid automatically set to **{level}**"
|
||||||
|
|
||||||
"CASE_DELETE": "✂️ **Case #{case.case_number}** was deleted by {userMention(mod)}"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,4 +77,6 @@ export enum LogType {
|
||||||
MEMBER_NOTE,
|
MEMBER_NOTE,
|
||||||
|
|
||||||
CASE_DELETE,
|
CASE_DELETE,
|
||||||
|
|
||||||
|
DM_FAILED,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { renderTemplate } from "src/templateFormatter";
|
||||||
import { createChunkedMessage, stripObjectToScalars } from "src/utils";
|
import { createChunkedMessage, stripObjectToScalars } from "src/utils";
|
||||||
import { LogType } from "src/data/LogType";
|
import { LogType } from "src/data/LogType";
|
||||||
import { TextChannel } from "eris";
|
import { TextChannel } from "eris";
|
||||||
|
import { sendDM } from "../../../utils/sendDM";
|
||||||
|
|
||||||
export const SendWelcomeMessageEvt = welcomeEvent({
|
export const SendWelcomeMessageEvt = welcomeEvent({
|
||||||
event: "guildMemberAdd",
|
event: "guildMemberAdd",
|
||||||
|
@ -21,14 +22,11 @@ export const SendWelcomeMessageEvt = welcomeEvent({
|
||||||
|
|
||||||
if (config.send_dm) {
|
if (config.send_dm) {
|
||||||
try {
|
try {
|
||||||
console.log(`Sending welcome message to ${member.id}`);
|
await sendDM(member.user, formatted, "welcome message");
|
||||||
const dmChannel = await member.user.getDMChannel();
|
|
||||||
if (!dmChannel) return;
|
|
||||||
await createChunkedMessage(dmChannel, formatted);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
pluginData.state.logs.log(LogType.DM_FAILED, {
|
||||||
body: `Failed send a welcome DM to {userMention(member)}`,
|
source: "welcome message",
|
||||||
member: stripObjectToScalars(member, ["user"]),
|
user: stripObjectToScalars(member.user),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ import moment from "moment-timezone";
|
||||||
import { SimpleCache } from "./SimpleCache";
|
import { SimpleCache } from "./SimpleCache";
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
import { unsafeCoerce } from "fp-ts/lib/function";
|
import { unsafeCoerce } from "fp-ts/lib/function";
|
||||||
|
import { sendDM } from "./utils/sendDM";
|
||||||
|
import { LogType } from "./data/LogType";
|
||||||
|
|
||||||
const fsp = fs.promises;
|
const fsp = fs.promises;
|
||||||
|
|
||||||
|
@ -878,9 +880,7 @@ export async function notifyUser(
|
||||||
for (const method of methods) {
|
for (const method of methods) {
|
||||||
if (method.type === "dm") {
|
if (method.type === "dm") {
|
||||||
try {
|
try {
|
||||||
console.log(`Notifying user ${user.id} via DM`);
|
await sendDM(user, body, "mod action notification");
|
||||||
const dmChannel = await user.getDMChannel();
|
|
||||||
await dmChannel.createMessage(body);
|
|
||||||
return {
|
return {
|
||||||
method,
|
method,
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -1069,8 +1069,6 @@ export async function resolveMember(bot: Client, guild: Guild, value: string): P
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Fetching unknown member (${userId} in ${guild.name} (${guild.id})) from the API`);
|
|
||||||
|
|
||||||
const freshMember = await bot.getRESTGuildMember(guild.id, userId).catch(noop);
|
const freshMember = await bot.getRESTGuildMember(guild.id, userId).catch(noop);
|
||||||
if (freshMember) {
|
if (freshMember) {
|
||||||
freshMember.id = userId;
|
freshMember.id = userId;
|
||||||
|
|
46
backend/src/utils/sendDM.ts
Normal file
46
backend/src/utils/sendDM.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { MessageContent, MessageFile, User } from "eris";
|
||||||
|
import { createChunkedMessage, HOURS, isDiscordRESTError } from "../utils";
|
||||||
|
import { logger } from "../logger";
|
||||||
|
|
||||||
|
let dmsDisabled = false;
|
||||||
|
let dmsDisabledTimeout = null;
|
||||||
|
|
||||||
|
function disableDMs(duration) {
|
||||||
|
dmsDisabled = true;
|
||||||
|
clearTimeout(dmsDisabledTimeout);
|
||||||
|
dmsDisabledTimeout = setTimeout(() => (dmsDisabled = false), duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DMError extends Error {}
|
||||||
|
|
||||||
|
const error20026 = "The bot cannot currently send DMs";
|
||||||
|
|
||||||
|
export async function sendDM(user: User, content: MessageContent, source: string) {
|
||||||
|
if (dmsDisabled) {
|
||||||
|
throw new DMError(error20026);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(`Sending ${source} DM to ${user.id}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dmChannel = await user.getDMChannel();
|
||||||
|
if (!dmChannel) {
|
||||||
|
throw new DMError("Unable to open DM channel");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof content === "string") {
|
||||||
|
await createChunkedMessage(dmChannel, content);
|
||||||
|
} else {
|
||||||
|
await dmChannel.createMessage(content);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (isDiscordRESTError(e) && e.code === 20026) {
|
||||||
|
logger.warn(`Received error code 20026: ${e.message}`);
|
||||||
|
logger.warn("Disabling attempts to send DMs for 1 hour");
|
||||||
|
disableDMs(1 * HOURS);
|
||||||
|
throw new DMError(error20026);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue