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,
Role,
BaseChannel,
TextChannel,
PermissionsString,
Channel,
APIEmbed,
@ -20,7 +19,8 @@ import {
ThreadChannel,
APIEmbedField,
VoiceState,
Invite
Invite,
GuildTextBasedChannel,
} from 'discord.js';
import { InvokerWrapper, MemberWrapper, UserWrapper } from '../src/client/components/wrappers/index.js';
import GuildWrapper from '../src/client/components/wrappers/GuildWrapper.js';
@ -384,9 +384,9 @@ export type BaseInfractionData = {
arguments?: InfractionArguments,
targetType?: InfractionTargetType,
guild: GuildWrapper,
channel?: TextChannel,
channel?: GuildTextBasedChannel,
invoker?: InvokerWrapper | null,
target?: MemberWrapper | UserWrapper | TextChannel,
target?: MemberWrapper | UserWrapper | GuildTextBasedChannel,
executor?: MemberWrapper | UserWrapper
duration?: number | null,
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 { CommandOption, Infraction } from '../src/client/interfaces/index.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 InfractionHandlerOptions = {
@ -14,7 +14,7 @@ export type InfractionHandlerOptions = {
export type HandleAutomodOptions = {
prune: boolean,
channel: TextChannel
channel: GuildTextBasedChannel
}
export type HandleTargetData = {
@ -25,7 +25,7 @@ export type HandleTargetData = {
expiration?: number | null,
invoker?: InvokerWrapper,
arguments?: { [key: string]: CommandOption | undefined },
channel: TextChannel,
channel: GuildTextBasedChannel,
executor: MemberWrapper,
duration?: number | null,
data: object,

View File

@ -1,7 +1,7 @@
import { inspect } from 'node:util';
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 { DiscordStruct, InfractionJSON, InfractionType, ModerationCallback } from '../../../@types/Client.js';
@ -172,7 +172,7 @@ class ModerationManager implements Initialisable
if (!executor)
throw new Error('Missing executor');
if (!(invoker.channel instanceof TextChannel))
if (!invoker.channel?.isTextBased())
throw new Error('Invalid channel');
const responses = [];
@ -181,7 +181,7 @@ class ModerationManager implements Initialisable
const response = await this._handleTarget(Infraction, target, {
invoker,
guild: invoker.guild!,
channel: invoker.channel!,
channel: invoker.channel,
executor,
arguments: args,
points: args.points?.asNumber,
@ -338,7 +338,11 @@ class ModerationManager implements Initialisable
* @memberof ModerationManager
*/
// 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
const { reason, force, guild } = info;
@ -542,7 +546,7 @@ class ModerationManager implements Initialisable
else if (i.targetType === 'CHANNEL')
{
target = guild.channels.resolve(i.target!);
if (!(target instanceof TextChannel))
if (!target?.isTextBased())
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 channel = guild.channels.resolve(i.channel!);
if (!(channel instanceof TextChannel))
if (!channel?.isTextBased())
throw new Error('Bad channel');
if (!executor)
throw new Error('Missing executor');

View File

@ -1,6 +1,6 @@
// 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';
type QueueEntry = {
@ -58,11 +58,11 @@ class RateLimiter
* @returns {Promise<Boolean>}
* @memberof RateLimiter
*/
queueDelete (channel: TextChannel, message: Message)
queueDelete (channel: GuildTextBasedChannel, message: Message)
{
return new Promise((resolve, reject) =>
{
if (!channel || !(channel instanceof TextChannel))
if (!channel || !(channel.isTextBased()))
reject(new Error('Missing channel'));
if (!message || !(message instanceof 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)
return;
@ -142,11 +142,11 @@ class RateLimiter
* @returns {Promise<Message>} Resolves when the message is sent, rejects if sending fails
* @memberof RateLimiter
*/
queueSend (channel: TextChannel, message: string)
queueSend (channel: GuildTextBasedChannel, message: string)
{
return new Promise((resolve, reject) =>
{
if (!channel || !(channel instanceof TextChannel))
if (!channel?.isTextBased())
reject(new Error('Missing channel.'));
if (!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)
return;
@ -231,7 +231,7 @@ class RateLimiter
{
return new Promise((resolve, reject) =>
{
if (!channel || !(channel instanceof TextChannel))
if (!channel?.isTextBased())
reject(new Error('Missing channel'));
if (!this.#client.user || !channel.permissionsFor(this.#client.user)?.has('SendMessages'))
reject(new Error('Missing permission SendMessages'));

View File

@ -418,7 +418,7 @@ class Resolver
{
const match = resolveable.toString().match(id) || [];
const [ , ch ] = match;
const channel = await CM.fetch(ch).catch(null);
const channel = await CM.fetch(ch).catch(() => null);
if (channel && filter(channel))
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 Util from '../../../../utilities/Util.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';
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 guild = invoker.guild!;
@ -64,8 +64,8 @@ class PollCommand extends SlashCommand
{
// await invoker.deferReply();
const questions = [];
const _channel = channel?.asChannel || invoker.channel;
if (!(_channel instanceof TextChannel))
const _channel = (channel?.asChannel || invoker.channel) as GuildTextBasedChannel;
if (!_channel?.isTextBased())
throw new CommandError(invoker, { index: 'ERR_INVALID_CHANNEL_TYPE' });
const botMissing = _channel.permissionsFor(this.client.user!)?.missing([ 'SendMessages', 'EmbedLinks' ]);
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 { CommandOptionType, CommandParams } from '../../../../../@types/Client.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 GuildWrapper from '../../wrappers/GuildWrapper.js';
@ -45,7 +45,7 @@ class RemindCommand extends SlashCommand
{
const { author, channel, guild, member } = invoker;
const subcommand = invoker.subcommand!.name;
if (!channel || !(channel instanceof TextChannel))
if (!channel?.isTextBased())
throw new Error('Missing channel?');
if (subcommand === 'create')

View File

@ -77,7 +77,7 @@ class SelfroleSetting extends Setting
// old channel for deleting old message if one exists
const oldChannel = await guild.resolveChannel<TextChannel>(setting.channel);
const newChannel = channel?.asChannel || oldChannel;
if (!(newChannel instanceof TextChannel))
if (!newChannel?.isTextBased())
throw new CommandError(invoker, { index: 'ERR_INVALID_CHANNEL_TYPE' });
if (channel)
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 { InfractionTargetType, InfractionType } from '../../../@types/Client.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 pkg from 'discord.js';
const { TextBasedChannelMixin } = pkg;
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
});
if (!(this.target instanceof TextBasedChannelMixin))
if (this.target instanceof BaseChannel && !this.target.isTextBased())
throw new Error('Invalid channel type given');
}
}

View File

@ -1,7 +1,7 @@
import { inspect } from 'node:util';
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 {
@ -60,14 +60,14 @@ class Infraction
#guild: GuildWrapper;
#channelId: Snowflake | null;
#channel: TextChannel | null;
#channel: GuildTextBasedChannel | null;
#messageId: Snowflake | null;
#message: InvokerWrapper | null;
#targetType: InfractionTargetType;
#targetId: Snowflake | null;
#target: UserWrapper | MemberWrapper | TextChannel | null;
#target: UserWrapper | MemberWrapper | GuildTextBasedChannel | null;
#executorId: Snowflake | null;
#executor: UserWrapper | null;

View File

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