From 24badc9003baeaf65432e9378b447d4f48f5a6c1 Mon Sep 17 00:00:00 2001 From: Aura Date: Mon, 1 Jan 2024 12:21:59 +0100 Subject: [PATCH] fix: resolved more issues (#2533) --- src/lib/util/common/promises.ts | 11 +++++++- src/lib/util/functions/index.ts | 1 + src/lib/util/functions/pieces.ts | 10 ++++++++ .../guilds/channels/channelUpdateNotify.ts | 10 ++++++-- .../members/notMutedMemberAddInitialRole.ts | 25 +++++++++++-------- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 src/lib/util/functions/pieces.ts diff --git a/src/lib/util/common/promises.ts b/src/lib/util/common/promises.ts index 773f4203a30..c9150b27c10 100644 --- a/src/lib/util/common/promises.ts +++ b/src/lib/util/common/promises.ts @@ -1,4 +1,4 @@ -import { container } from '@sapphire/framework'; +import { Result, container, err, ok } from '@sapphire/framework'; import { isThenable, type Awaitable } from '@sapphire/utilities'; import { DiscordAPIError, type RESTJSONErrorCodes } from 'discord.js'; @@ -11,6 +11,15 @@ export async function resolveOnErrorCodes(promise: Promise, ...codes: read } } +export async function toErrorCodeResult(promise: Promise): Promise> { + try { + return ok(await promise); + } catch (error) { + if (error instanceof DiscordAPIError) return err(error.code as RESTJSONErrorCodes); + throw error; + } +} + export function floatPromise(promise: Awaitable) { if (isThenable(promise)) promise.catch((error: Error) => container.logger.fatal(error)); } diff --git a/src/lib/util/functions/index.ts b/src/lib/util/functions/index.ts index dc946579e3b..2875a8b6a62 100644 --- a/src/lib/util/functions/index.ts +++ b/src/lib/util/functions/index.ts @@ -3,3 +3,4 @@ export * from '#lib/util/functions/emojis'; export * from '#lib/util/functions/guild'; export * from '#lib/util/functions/messages'; export * from '#lib/util/functions/permissions'; +export * from '#lib/util/functions/pieces'; diff --git a/src/lib/util/functions/pieces.ts b/src/lib/util/functions/pieces.ts new file mode 100644 index 00000000000..077df9bb9df --- /dev/null +++ b/src/lib/util/functions/pieces.ts @@ -0,0 +1,10 @@ +import type { Piece } from '@sapphire/framework'; +import { bgBlue, bgRed } from 'colorette'; + +export function getLogPrefix(piece: Piece) { + return bgBlue(`[ ${piece.store.name} => ${piece.name} ]`); +} + +export function getCodeStyle(code: string | number) { + return bgRed(`[ ${code} ]`); +} diff --git a/src/listeners/guilds/channels/channelUpdateNotify.ts b/src/listeners/guilds/channels/channelUpdateNotify.ts index 2b1b5f22326..0224c92995b 100644 --- a/src/listeners/guilds/channels/channelUpdateNotify.ts +++ b/src/listeners/guilds/channels/channelUpdateNotify.ts @@ -6,7 +6,13 @@ import { differenceBitField, differenceMap } from '#utils/common/comparators'; import { Colors, LongWidthSpace } from '#utils/constants'; import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { isDMChannel, isNsfwChannel, type GuildBasedChannelTypes, type NonThreadGuildBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { + canSendMessages, + isDMChannel, + isNsfwChannel, + type GuildBasedChannelTypes, + type NonThreadGuildBasedChannelTypes +} from '@sapphire/discord.js-utilities'; import { Events, Listener } from '@sapphire/framework'; import type { TFunction } from '@sapphire/plugin-i18next'; import { isNullish } from '@sapphire/utilities'; @@ -35,7 +41,7 @@ export class UserListener extends Listener { if (isNullish(channelId)) return; const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; - if (channel === undefined) { + if (isNullish(channel) || !canSendMessages(channel)) { await writeSettings(next.guild, [[GuildSettings.Channels.Logs.ChannelUpdate, null]]); return; } diff --git a/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts b/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts index 8f727d97db9..78c3a131e87 100644 --- a/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts +++ b/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts @@ -1,9 +1,11 @@ import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { Events } from '#lib/types'; +import { toErrorCodeResult } from '#utils/common'; +import { getCodeStyle, getLogPrefix } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; import { Listener } from '@sapphire/framework'; import { isNullish } from '@sapphire/utilities'; -import { PermissionFlagsBits, type GuildMember } from 'discord.js'; +import { PermissionFlagsBits, RESTJSONErrorCodes, type GuildMember } from 'discord.js'; @ApplyOptions({ event: Events.NotMutedMemberAdd }) export class UserListener extends Listener { @@ -16,22 +18,23 @@ export class UserListener extends Listener { GuildSettings.Roles.InitialHumans, GuildSettings.Roles.InitialBots ]); - if (!initial && !initialHumans && !initialBots) return; const roleId = initial ?? (member.user.bot ? initialBots : initialHumans); if (!roleId) return; - const role = member.guild.roles.cache.get(roleId); - if (role && role.position < member.guild.members.me!.roles.highest.position) { - return member.roles.add(role); + const result = await toErrorCodeResult(member.roles.add(roleId)); + // If the role was not found or the bot can't give the role, remove it from the settings: + if (result.isErrAnd((code) => code === RESTJSONErrorCodes.UnknownRole || code === RESTJSONErrorCodes.MissingPermissions)) { + const key = initial // + ? GuildSettings.Roles.Initial + : member.user.bot + ? GuildSettings.Roles.InitialBots + : GuildSettings.Roles.InitialHumans; + return writeSettings(member, [[key, null]]); } - const key = role // - ? GuildSettings.Roles.Initial - : member.user.bot - ? GuildSettings.Roles.InitialBots - : GuildSettings.Roles.InitialHumans; - return writeSettings(member, [[key, null]]); + // In any other case, log the error as unexpected: + result.inspectErr((code) => this.container.logger.error(`${getLogPrefix(this)} Failed to give role: ${getCodeStyle(code)}`)); } private canGiveRoles(member: GuildMember) {