diff --git a/src/bot/commands/checkin/validators/checkin-status.ts b/src/bot/commands/checkin/validators/checkin-status.ts index 1c48614..e4085d1 100644 --- a/src/bot/commands/checkin/validators/checkin-status.ts +++ b/src/bot/commands/checkin/validators/checkin-status.ts @@ -95,7 +95,7 @@ export class CheckinStatus extends CheckinStatusMessage { return { content, embed } } - const flamewarden = await getMember(guild, checkin.reviewed_by!) + const flamewarden = checkin.reviewed_by ? await getMember(guild, checkin.reviewed_by) : undefined embed = createEmbed( `🕯️ Check-In #${checkin.public_id}`, CheckinStatus.MSG.LastCheckin(guild.name, userDiscordId, checkin, flamewarden), diff --git a/src/bot/events/client-ready/jobs/validators/reset-grinder-roles.ts b/src/bot/events/client-ready/jobs/validators/reset-grinder-roles.ts index c7af2f5..6a4fcd5 100644 --- a/src/bot/events/client-ready/jobs/validators/reset-grinder-roles.ts +++ b/src/bot/events/client-ready/jobs/validators/reset-grinder-roles.ts @@ -8,7 +8,7 @@ import { FLAMEWARDEN_ROLE, getGrindRoles, GRINDER_ROLE } from '@config/discord' import { GOODBYE_NOTE_BUTTON_ID, ResetGrinderRolesButtonError } from '@events/interaction-create/jobs/handlers/reset-grinder-roles-button' import { decodeSnowflakes, encodeSnowflake, getCustomId } from '@utils/component' import { isDateToday, isDateYesterday } from '@utils/date' -import { DiscordAssert, getChannel, getMember, sendAsBot } from '@utils/discord' +import { DiscordAssert, getChannel, getMembers, sendAsBot } from '@utils/discord' import { log } from '@utils/logger' import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js' import { ResetGrinderRolesMessage } from '../messages/reset-grinder-roles' @@ -91,6 +91,9 @@ export class ResetGrinderRoles extends ResetGrinderRolesMessage { } static async validateUsers(prisma: PrismaClient, guild: Guild, grindAshesChannel: TextChannel, auditFlameChannel: TextChannel, users: User[]) { + const discordIds = users.map(u => u.discord_id).filter(Boolean) + const members = await getMembers(guild, discordIds, { withPresences: false }) + for (const user of users) { const checkinStreak = user.checkin_streaks?.[0] if (!checkinStreak) @@ -100,7 +103,7 @@ export class ResetGrinderRoles extends ResetGrinderRolesMessage { if (this.hasValidCheckin(lastCheckin)) continue - const member = await getMember(guild, user.discord_id) + const member = members.get(user.discord_id) as GuildMember await this.removeGrinderRoles(member) await this.breakCheckinStreakAt(prisma, checkinStreak, lastCheckin!) const thread = await this.validateWaitingCheckin(guild, auditFlameChannel, member, user, lastCheckin!) diff --git a/src/utils/discord/index.ts b/src/utils/discord/index.ts index 74e92ad..3dbddcc 100644 --- a/src/utils/discord/index.ts +++ b/src/utils/discord/index.ts @@ -1,21 +1,31 @@ -import type { Attachment, ChatInputCommandInteraction, ClientUser, Guild, GuildMember, Interaction, InteractionDeferReplyOptions, InteractionReplyOptions, MessageCreateOptions, PermissionsBitField, Role, TextChannel, ThreadChannel } from 'discord.js' +import type { Attachment, ChatInputCommandInteraction, ClientUser, FetchMembersOptions, Guild, GuildMember, Interaction, InteractionDeferReplyOptions, InteractionReplyOptions, MessageCreateOptions, PermissionsBitField, Role, TextChannel, ThreadChannel } from 'discord.js' import { MessageFlags } from 'discord.js' export async function getChannel(guild: Guild, id: string, isThread: boolean = false): Promise { + const cached = guild!.channels.cache.get(id) + if (isThread) { - return guild!.channels.cache.get(id) as TextChannel ?? await guild!.channels.fetch(id).then(channel => channel as TextChannel) + return cached as TextChannel ?? await guild!.channels.fetch(id).then(channel => channel as TextChannel) } else { - return guild!.channels.cache.get(id) as ThreadChannel ?? await guild!.channels.fetch(id).then(channel => channel as ThreadChannel) + return cached as ThreadChannel ?? await guild!.channels.fetch(id).then(channel => channel as ThreadChannel) } } export async function getRole(guild: Guild, id: string): Promise { - return guild!.roles.cache.get(id) as Role ?? await guild!.roles.fetch(id) + const cached = guild!.roles.cache.get(id) + + return cached as Role ?? await guild!.roles.fetch(id) } export async function getMember(guild: Guild, discordId: string) { - return guild.members.cache.get(discordId) as GuildMember ?? await guild.members.fetch(discordId) + const cached = guild.members.cache.get(discordId) + + return cached as GuildMember ?? await guild.members.fetch(discordId) +} + +export async function getMembers(guild: Guild, userIds: string[], opts?: FetchMembersOptions) { + return await guild.members.fetch({ user: userIds, ...opts }) } export const getMissPerms = (channelPerms: Readonly, requiredPerms: bigint[]): bigint[] => requiredPerms.filter(p => !channelPerms.has(p))