Check for channel type properly

This commit is contained in:
Erik 2023-12-08 21:20:36 +02:00
parent c1fee71211
commit 6fa715fb8b
11 changed files with 40 additions and 37 deletions

View File

@ -8,7 +8,6 @@ import {
GuildMember, GuildMember,
Role, Role,
BaseChannel, BaseChannel,
TextChannel,
PermissionsString, PermissionsString,
Channel, Channel,
APIEmbed, APIEmbed,
@ -20,7 +19,8 @@ import {
ThreadChannel, ThreadChannel,
APIEmbedField, APIEmbedField,
VoiceState, VoiceState,
Invite Invite,
GuildTextBasedChannel,
} from 'discord.js'; } from 'discord.js';
import { InvokerWrapper, MemberWrapper, UserWrapper } from '../src/client/components/wrappers/index.js'; import { InvokerWrapper, MemberWrapper, UserWrapper } from '../src/client/components/wrappers/index.js';
import GuildWrapper from '../src/client/components/wrappers/GuildWrapper.js'; import GuildWrapper from '../src/client/components/wrappers/GuildWrapper.js';
@ -384,9 +384,9 @@ export type BaseInfractionData = {
arguments?: InfractionArguments, arguments?: InfractionArguments,
targetType?: InfractionTargetType, targetType?: InfractionTargetType,
guild: GuildWrapper, guild: GuildWrapper,
channel?: TextChannel, channel?: GuildTextBasedChannel,
invoker?: InvokerWrapper | null, invoker?: InvokerWrapper | null,
target?: MemberWrapper | UserWrapper | TextChannel, target?: MemberWrapper | UserWrapper | GuildTextBasedChannel,
executor?: MemberWrapper | UserWrapper executor?: MemberWrapper | UserWrapper
duration?: number | null, duration?: number | null,
reason?: string, reason?: string,

View File

@ -1,9 +1,9 @@
import { GuildBasedChannel, Message, TextChannel } from 'discord.js'; import { GuildBasedChannel, Message } from 'discord.js';
import { GuildWrapper, InvokerWrapper, MemberWrapper, UserWrapper } from '../src/client/components/wrappers/index.ts'; import { GuildWrapper, InvokerWrapper, MemberWrapper, UserWrapper } from '../src/client/components/wrappers/index.ts';
import { CommandOption, Infraction } from '../src/client/interfaces/index.ts'; import { CommandOption, Infraction } from '../src/client/interfaces/index.ts';
import { FormatParams, InfractionType } from './Client.ts'; import { FormatParams, InfractionType } from './Client.ts';
export type ModerationTarget = UserWrapper | MemberWrapper | TextChannel export type ModerationTarget = UserWrapper | MemberWrapper | GuildTextBasedChannel
export type ModerationTargets = ModerationTarget[] export type ModerationTargets = ModerationTarget[]
export type InfractionHandlerOptions = { export type InfractionHandlerOptions = {
@ -14,7 +14,7 @@ export type InfractionHandlerOptions = {
export type HandleAutomodOptions = { export type HandleAutomodOptions = {
prune: boolean, prune: boolean,
channel: TextChannel channel: GuildTextBasedChannel
} }
export type HandleTargetData = { export type HandleTargetData = {
@ -25,7 +25,7 @@ export type HandleTargetData = {
expiration?: number | null, expiration?: number | null,
invoker?: InvokerWrapper, invoker?: InvokerWrapper,
arguments?: { [key: string]: CommandOption | undefined }, arguments?: { [key: string]: CommandOption | undefined },
channel: TextChannel, channel: GuildTextBasedChannel,
executor: MemberWrapper, executor: MemberWrapper,
duration?: number | null, duration?: number | null,
data: object, data: object,

View File

@ -1,7 +1,7 @@
import { inspect } from 'node:util'; import { inspect } from 'node:util';
import { stripIndents } from 'common-tags'; import { stripIndents } from 'common-tags';
import { Collection, GuildTextBasedChannel, Message, TextChannel } from 'discord.js'; import { Collection, GuildTextBasedChannel, Message } from 'discord.js';
import { LoggerClient } from '@navy.gif/logger'; import { LoggerClient } from '@navy.gif/logger';
import { DiscordStruct, InfractionJSON, InfractionType, ModerationCallback } from '../../../@types/Client.js'; import { DiscordStruct, InfractionJSON, InfractionType, ModerationCallback } from '../../../@types/Client.js';
@ -172,7 +172,7 @@ class ModerationManager implements Initialisable
if (!executor) if (!executor)
throw new Error('Missing executor'); throw new Error('Missing executor');
if (!(invoker.channel instanceof TextChannel)) if (!invoker.channel?.isTextBased())
throw new Error('Invalid channel'); throw new Error('Invalid channel');
const responses = []; const responses = [];
@ -181,7 +181,7 @@ class ModerationManager implements Initialisable
const response = await this._handleTarget(Infraction, target, { const response = await this._handleTarget(Infraction, target, {
invoker, invoker,
guild: invoker.guild!, guild: invoker.guild!,
channel: invoker.channel!, channel: invoker.channel,
executor, executor,
arguments: args, arguments: args,
points: args.points?.asNumber, points: args.points?.asNumber,
@ -338,7 +338,11 @@ class ModerationManager implements Initialisable
* @memberof ModerationManager * @memberof ModerationManager
*/ */
// eslint-disable-next-line max-lines-per-function // eslint-disable-next-line max-lines-per-function
async _handleTarget (Infraction: typeof InfractionClass, target: UserWrapper | MemberWrapper | TextChannel, info: HandleTargetData) async _handleTarget (
Infraction: typeof InfractionClass,
target: UserWrapper | MemberWrapper | GuildTextBasedChannel,
info: HandleTargetData
)
{ {
// wrapper: guildWrapper // wrapper: guildWrapper
const { reason, force, guild } = info; const { reason, force, guild } = info;
@ -542,7 +546,7 @@ class ModerationManager implements Initialisable
else if (i.targetType === 'CHANNEL') else if (i.targetType === 'CHANNEL')
{ {
target = guild.channels.resolve(i.target!); target = guild.channels.resolve(i.target!);
if (!(target instanceof TextChannel)) if (!target?.isTextBased())
throw new Error('Invalid channel'); throw new Error('Invalid channel');
} }
@ -550,7 +554,7 @@ class ModerationManager implements Initialisable
{ {
const executor = await guild.memberWrapper(i.executor!).catch(() => null) ?? await guild.memberWrapper(guild.me!); const executor = await guild.memberWrapper(i.executor!).catch(() => null) ?? await guild.memberWrapper(guild.me!);
const channel = guild.channels.resolve(i.channel!); const channel = guild.channels.resolve(i.channel!);
if (!(channel instanceof TextChannel)) if (!channel?.isTextBased())
throw new Error('Bad channel'); throw new Error('Bad channel');
if (!executor) if (!executor)
throw new Error('Missing executor'); throw new Error('Missing executor');

View File

@ -1,6 +1,6 @@
// const { TextChannel, Message } = require('discord.js'); // const { TextChannel, Message } = require('discord.js');
import { Message, MessageCreateOptions, TextChannel } from 'discord.js'; import { GuildTextBasedChannel, Message, MessageCreateOptions, TextChannel } from 'discord.js';
import DiscordClient from '../DiscordClient.js'; import DiscordClient from '../DiscordClient.js';
type QueueEntry = { type QueueEntry = {
@ -58,11 +58,11 @@ class RateLimiter
* @returns {Promise<Boolean>} * @returns {Promise<Boolean>}
* @memberof RateLimiter * @memberof RateLimiter
*/ */
queueDelete (channel: TextChannel, message: Message) queueDelete (channel: GuildTextBasedChannel, message: Message)
{ {
return new Promise((resolve, reject) => return new Promise((resolve, reject) =>
{ {
if (!channel || !(channel instanceof TextChannel)) if (!channel || !(channel.isTextBased()))
reject(new Error('Missing channel')); reject(new Error('Missing channel'));
if (!message || !(message instanceof Message)) if (!message || !(message instanceof Message))
reject(new Error('Missing message')); reject(new Error('Missing message'));
@ -78,7 +78,7 @@ class RateLimiter
}); });
} }
async #delete (channel: TextChannel) async #delete (channel: GuildTextBasedChannel)
{ {
if (!this.#deleteQueue[channel.id] || !this.#deleteQueue[channel.id].length) if (!this.#deleteQueue[channel.id] || !this.#deleteQueue[channel.id].length)
return; return;
@ -142,11 +142,11 @@ class RateLimiter
* @returns {Promise<Message>} Resolves when the message is sent, rejects if sending fails * @returns {Promise<Message>} Resolves when the message is sent, rejects if sending fails
* @memberof RateLimiter * @memberof RateLimiter
*/ */
queueSend (channel: TextChannel, message: string) queueSend (channel: GuildTextBasedChannel, message: string)
{ {
return new Promise((resolve, reject) => return new Promise((resolve, reject) =>
{ {
if (!channel || !(channel instanceof TextChannel)) if (!channel?.isTextBased())
reject(new Error('Missing channel.')); reject(new Error('Missing channel.'));
if (!message) if (!message)
reject(new Error('Missing message.')); reject(new Error('Missing message.'));
@ -167,7 +167,7 @@ class RateLimiter
}); });
} }
async #send (channel: TextChannel) async #send (channel: GuildTextBasedChannel)
{ {
if (!this.#sendQueue[channel.id] || !this.#sendQueue[channel.id].length) if (!this.#sendQueue[channel.id] || !this.#sendQueue[channel.id].length)
return; return;
@ -231,7 +231,7 @@ class RateLimiter
{ {
return new Promise((resolve, reject) => return new Promise((resolve, reject) =>
{ {
if (!channel || !(channel instanceof TextChannel)) if (!channel?.isTextBased())
reject(new Error('Missing channel')); reject(new Error('Missing channel'));
if (!this.#client.user || !channel.permissionsFor(this.#client.user)?.has('SendMessages')) if (!this.#client.user || !channel.permissionsFor(this.#client.user)?.has('SendMessages'))
reject(new Error('Missing permission SendMessages')); reject(new Error('Missing permission SendMessages'));

View File

@ -418,7 +418,7 @@ class Resolver
{ {
const match = resolveable.toString().match(id) || []; const match = resolveable.toString().match(id) || [];
const [ , ch ] = match; const [ , ch ] = match;
const channel = await CM.fetch(ch).catch(null); const channel = await CM.fetch(ch).catch(() => null);
if (channel && filter(channel)) if (channel && filter(channel))
resolved.push(channel as unknown as T); resolved.push(channel as unknown as T);
} }

View File

@ -4,7 +4,7 @@ import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
import { CommandOptionType, CommandParams } from '../../../../../@types/Client.js'; import { CommandOptionType, CommandParams } from '../../../../../@types/Client.js';
import Util from '../../../../utilities/Util.js'; import Util from '../../../../utilities/Util.js';
import { EmbedDefaultColor, PollReactions } from '../../../../constants/Constants.js'; import { EmbedDefaultColor, PollReactions } from '../../../../constants/Constants.js';
import { TextChannel } from 'discord.js'; import { GuildTextBasedChannel, TextChannel } from 'discord.js';
import { CallbackData, PollData } from '../../../../../@types/Guild.js'; import { CallbackData, PollData } from '../../../../../@types/Guild.js';
class PollCommand extends SlashCommand class PollCommand extends SlashCommand
@ -54,7 +54,7 @@ class PollCommand extends SlashCommand
}); });
} }
async execute (invoker: InvokerWrapper, { choices, channel, duration, multichoice, message }: CommandParams) async execute (invoker: InvokerWrapper<true>, { choices, channel, duration, multichoice, message }: CommandParams)
{ {
const { subcommand, author } = invoker; const { subcommand, author } = invoker;
const guild = invoker.guild!; const guild = invoker.guild!;
@ -64,8 +64,8 @@ class PollCommand extends SlashCommand
{ {
// await invoker.deferReply(); // await invoker.deferReply();
const questions = []; const questions = [];
const _channel = channel?.asChannel || invoker.channel; const _channel = (channel?.asChannel || invoker.channel) as GuildTextBasedChannel;
if (!(_channel instanceof TextChannel)) if (!_channel?.isTextBased())
throw new CommandError(invoker, { index: 'ERR_INVALID_CHANNEL_TYPE' }); throw new CommandError(invoker, { index: 'ERR_INVALID_CHANNEL_TYPE' });
const botMissing = _channel.permissionsFor(this.client.user!)?.missing([ 'SendMessages', 'EmbedLinks' ]); const botMissing = _channel.permissionsFor(this.client.user!)?.missing([ 'SendMessages', 'EmbedLinks' ]);
const userMissing = _channel.permissionsFor(member).missing([ 'SendMessages' ]); const userMissing = _channel.permissionsFor(member).missing([ 'SendMessages' ]);

View File

@ -3,7 +3,7 @@ import DiscordClient from '../../../DiscordClient.js';
import InvokerWrapper from '../../wrappers/InvokerWrapper.js'; import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
import { CommandOptionType, CommandParams } from '../../../../../@types/Client.js'; import { CommandOptionType, CommandParams } from '../../../../../@types/Client.js';
import Util from '../../../../utilities/Util.js'; import Util from '../../../../utilities/Util.js';
import { APIEmbed, TextChannel } from 'discord.js'; import { APIEmbed } from 'discord.js';
import { CallbackData, ReminderData } from '../../../../../@types/Guild.js'; import { CallbackData, ReminderData } from '../../../../../@types/Guild.js';
import GuildWrapper from '../../wrappers/GuildWrapper.js'; import GuildWrapper from '../../wrappers/GuildWrapper.js';
@ -45,7 +45,7 @@ class RemindCommand extends SlashCommand
{ {
const { author, channel, guild, member } = invoker; const { author, channel, guild, member } = invoker;
const subcommand = invoker.subcommand!.name; const subcommand = invoker.subcommand!.name;
if (!channel || !(channel instanceof TextChannel)) if (!channel?.isTextBased())
throw new Error('Missing channel?'); throw new Error('Missing channel?');
if (subcommand === 'create') if (subcommand === 'create')

View File

@ -77,7 +77,7 @@ class SelfroleSetting extends Setting
// old channel for deleting old message if one exists // old channel for deleting old message if one exists
const oldChannel = await guild.resolveChannel<TextChannel>(setting.channel); const oldChannel = await guild.resolveChannel<TextChannel>(setting.channel);
const newChannel = channel?.asChannel || oldChannel; const newChannel = channel?.asChannel || oldChannel;
if (!(newChannel instanceof TextChannel)) if (!newChannel?.isTextBased())
throw new CommandError(invoker, { index: 'ERR_INVALID_CHANNEL_TYPE' }); throw new CommandError(invoker, { index: 'ERR_INVALID_CHANNEL_TYPE' });
if (channel) if (channel)
setting.channel = channel.asChannel.id; // Set the new channel if one is given setting.channel = channel.asChannel.id; // Set the new channel if one is given

View File

@ -4,10 +4,8 @@ import DiscordClient from '../DiscordClient.js';
import { LoggerClient } from '@navy.gif/logger'; import { LoggerClient } from '@navy.gif/logger';
import { InfractionTargetType, InfractionType } from '../../../@types/Client.js'; import { InfractionTargetType, InfractionType } from '../../../@types/Client.js';
import { PruneData } from '../../../@types/Infractions.js'; import { PruneData } from '../../../@types/Infractions.js';
import { DMChannel, GuildTextBasedChannel, Message, PartialDMChannel, Snowflake, TextBasedChannel } from 'discord.js'; import { BaseChannel, DMChannel, GuildTextBasedChannel, Message, PartialDMChannel, Snowflake, TextBasedChannel } from 'discord.js';
import { Collection } from '@discordjs/collection'; import { Collection } from '@discordjs/collection';
import pkg from 'discord.js';
const { TextBasedChannelMixin } = pkg;
const Arguments = [ 'users', 'bots', 'humans', 'contains', 'startswith', 'endswith', 'emojis', 'reactions', 'text', 'invites', 'links', 'emojis', 'reactions', 'images', 'attachments' ]; const Arguments = [ 'users', 'bots', 'humans', 'contains', 'startswith', 'endswith', 'emojis', 'reactions', 'text', 'invites', 'links', 'emojis', 'reactions', 'images', 'attachments' ];
@ -48,7 +46,7 @@ class PruneInfraction extends Infraction
hyperlink: opts.hyperlink hyperlink: opts.hyperlink
}); });
if (!(this.target instanceof TextBasedChannelMixin)) if (this.target instanceof BaseChannel && !this.target.isTextBased())
throw new Error('Invalid channel type given'); throw new Error('Invalid channel type given');
} }
} }

View File

@ -1,7 +1,7 @@
import { inspect } from 'node:util'; import { inspect } from 'node:util';
import { LoggerClient } from '@navy.gif/logger'; import { LoggerClient } from '@navy.gif/logger';
import { APIEmbed, GuildChannel, Message, Snowflake, TextChannel } from 'discord.js'; import { APIEmbed, GuildChannel, GuildTextBasedChannel, Message, Snowflake, TextChannel } from 'discord.js';
import { ObjectId, WithId } from 'mongodb'; import { ObjectId, WithId } from 'mongodb';
import { import {
@ -60,14 +60,14 @@ class Infraction
#guild: GuildWrapper; #guild: GuildWrapper;
#channelId: Snowflake | null; #channelId: Snowflake | null;
#channel: TextChannel | null; #channel: GuildTextBasedChannel | null;
#messageId: Snowflake | null; #messageId: Snowflake | null;
#message: InvokerWrapper | null; #message: InvokerWrapper | null;
#targetType: InfractionTargetType; #targetType: InfractionTargetType;
#targetId: Snowflake | null; #targetId: Snowflake | null;
#target: UserWrapper | MemberWrapper | TextChannel | null; #target: UserWrapper | MemberWrapper | GuildTextBasedChannel | null;
#executorId: Snowflake | null; #executorId: Snowflake | null;
#executor: UserWrapper | null; #executor: UserWrapper | null;

View File

@ -12,6 +12,7 @@ type CommandUsageLimits = {
usages: number, usages: number,
duration: number duration: number
} }
type CommandThrottle = { type CommandThrottle = {
usages: number, usages: number,
start: number, start: number,