Update main branch #15
@ -116,6 +116,15 @@ declare interface DiscordClient extends Client {
|
|||||||
on<K extends keyof ClientEvents>(event: K, listener: EventHook<K>): this
|
on<K extends keyof ClientEvents>(event: K, listener: EventHook<K>): this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client class
|
||||||
|
* Should not house much functionality itself,
|
||||||
|
* rather it should mostly house components that implement behaviour.
|
||||||
|
*
|
||||||
|
* @class DiscordClient
|
||||||
|
* @typedef {DiscordClient}
|
||||||
|
* @extends {Client}
|
||||||
|
*/
|
||||||
class DiscordClient extends Client
|
class DiscordClient extends Client
|
||||||
{
|
{
|
||||||
#logger: Logger;
|
#logger: Logger;
|
||||||
@ -204,13 +213,6 @@ class DiscordClient extends Client
|
|||||||
this.#resolver = new Resolver(this);
|
this.#resolver = new Resolver(this);
|
||||||
this.#rateLimiter = new RateLimiter(this);
|
this.#rateLimiter = new RateLimiter(this);
|
||||||
|
|
||||||
|
|
||||||
// As of d.js v14 these events are emitted from the rest manager, rebinding them to the client
|
|
||||||
// this.rest.on('request', (...args) =>
|
|
||||||
// {
|
|
||||||
// this.emit('apiRequest', ...args);
|
|
||||||
// });
|
|
||||||
|
|
||||||
this.rest.on('response', (...args) =>
|
this.rest.on('response', (...args) =>
|
||||||
{
|
{
|
||||||
this.emit('apiResponse', ...args);
|
this.emit('apiResponse', ...args);
|
||||||
@ -228,10 +230,6 @@ class DiscordClient extends Client
|
|||||||
|
|
||||||
this.#loadEevents();
|
this.#loadEevents();
|
||||||
|
|
||||||
// process.on('uncaughtException', (err) => {
|
|
||||||
// this.logger.error(`Uncaught exception:\n${err.stack || err}`);
|
|
||||||
// });
|
|
||||||
|
|
||||||
process.on('unhandledRejection', (err: Error) =>
|
process.on('unhandledRejection', (err: Error) =>
|
||||||
{
|
{
|
||||||
this.#logger.error(`Unhandled rejection:\n${err?.stack || err}`);
|
this.#logger.error(`Unhandled rejection:\n${err?.stack || err}`);
|
||||||
@ -314,7 +312,6 @@ class DiscordClient extends Client
|
|||||||
this.shutdown();
|
this.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
async managerEval<Result> (script: ((controller: Controller) => Promise<Result> | Result) | string, options: ManagerEvalOptions = {})
|
async managerEval<Result> (script: ((controller: Controller) => Promise<Result> | Result) | string, options: ManagerEvalOptions = {})
|
||||||
: Promise<Result>
|
: Promise<Result>
|
||||||
{
|
{
|
||||||
@ -384,6 +381,7 @@ class DiscordClient extends Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to pass options to the logger in a unified way
|
// Helper function to pass options to the logger in a unified way
|
||||||
|
// also avoids having to import the logger everywhere
|
||||||
createLogger (comp: object, options: LoggerClientOptions = {})
|
createLogger (comp: object, options: LoggerClientOptions = {})
|
||||||
{
|
{
|
||||||
return new Logger({ name: comp.constructor.name, ...this.#options.logger, ...options });
|
return new Logger({ name: comp.constructor.name, ...this.#options.logger, ...options });
|
||||||
@ -445,17 +443,6 @@ class DiscordClient extends Client
|
|||||||
return this.shard.ids[0];
|
return this.shard.ids[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// on<K extends keyof ClientEvents>(event: K, listener: (...args: unknown[]) => Awaitable<void>): this;
|
|
||||||
// on<K extends keyof ClientEvents> (event: K, listener: (...args: unknown[]) => Awaitable<void>)
|
|
||||||
// {
|
|
||||||
// // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// // @ts-ignore
|
|
||||||
// return super.on(event, listener);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
#loadEevents ()
|
#loadEevents ()
|
||||||
{
|
{
|
||||||
this.#eventHooker.hook('ready', () =>
|
this.#eventHooker.hook('ready', () =>
|
||||||
@ -518,9 +505,6 @@ class DiscordClient extends Client
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
#createWrappers ()
|
#createWrappers ()
|
||||||
{
|
{
|
||||||
this.guilds.cache.forEach((guild) =>
|
this.guilds.cache.forEach((guild) =>
|
||||||
@ -567,7 +551,6 @@ class DiscordClient extends Client
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signatures for typescript inferral
|
|
||||||
getUserWrapper(resolveable: UserResolveable, fetch?: false): UserWrapper | null;
|
getUserWrapper(resolveable: UserResolveable, fetch?: false): UserWrapper | null;
|
||||||
getUserWrapper(resolveable: UserResolveable, fetch?: true): Promise<UserWrapper | null>;
|
getUserWrapper(resolveable: UserResolveable, fetch?: true): Promise<UserWrapper | null>;
|
||||||
getUserWrapper (resolveable: UserResolveable, fetch = true)
|
getUserWrapper (resolveable: UserResolveable, fetch = true)
|
||||||
@ -631,13 +614,6 @@ class DiscordClient extends Client
|
|||||||
return this.#built;
|
return this.#built;
|
||||||
}
|
}
|
||||||
|
|
||||||
// override get user ()
|
|
||||||
// {
|
|
||||||
// if (!super.user)
|
|
||||||
// throw new Error('User not set');
|
|
||||||
// return super.user;
|
|
||||||
// }
|
|
||||||
|
|
||||||
get prefix ()
|
get prefix ()
|
||||||
{
|
{
|
||||||
return this.#options.prefix;
|
return this.#options.prefix;
|
||||||
@ -745,6 +721,8 @@ class DiscordClient extends Client
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is what actually starts the client.
|
||||||
|
// Just running this file directly will not start the client and the process will just hang.
|
||||||
process.once('message', (msg: IPCMessage) =>
|
process.once('message', (msg: IPCMessage) =>
|
||||||
{
|
{
|
||||||
if (msg._start)
|
if (msg._start)
|
||||||
@ -754,8 +732,4 @@ process.once('message', (msg: IPCMessage) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default DiscordClient;
|
export default DiscordClient;
|
||||||
|
|
||||||
// process.on("unhandledRejection", (error) => {
|
|
||||||
// console.error("[DiscordClient.js] Unhandled promise rejection:", error); //eslint-disable-line no-console
|
|
||||||
// });
|
|
@ -22,6 +22,15 @@ import { EventHook } from '../../../@types/Client.js';
|
|||||||
import { ClientEvents } from '../../../@types/Events.js';
|
import { ClientEvents } from '../../../@types/Events.js';
|
||||||
import { Interaction } from 'discord.js';
|
import { Interaction } from 'discord.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooks events to their handlers.
|
||||||
|
* This is done in order to dispatch events to their handlers sequentially.
|
||||||
|
* The order of handler execution matters due to priority and to avoid
|
||||||
|
* race conditions and simultaneous execution in filter hooks.
|
||||||
|
*
|
||||||
|
* @class EventHooker
|
||||||
|
* @typedef {EventHooker}
|
||||||
|
*/
|
||||||
class EventHooker
|
class EventHooker
|
||||||
{
|
{
|
||||||
#target: DiscordClient;
|
#target: DiscordClient;
|
||||||
@ -84,9 +93,8 @@ class EventHooker
|
|||||||
}
|
}
|
||||||
|
|
||||||
let guild = null;
|
let guild = null;
|
||||||
// this.logger.debug(`Handler ${eventName}`);
|
|
||||||
// Should probably move this elsewhere, but testing this out -- or maybe not, might be the most appropriate place for this
|
|
||||||
const eventArgs = [];
|
const eventArgs = [];
|
||||||
|
// Add guildWrapper property to d.js structures
|
||||||
for (const arg of args)
|
for (const arg of args)
|
||||||
{
|
{
|
||||||
if (arg && typeof arg === 'object' && 'guild' in arg && arg.guild)
|
if (arg && typeof arg === 'object' && 'guild' in arg && arg.guild)
|
||||||
@ -102,19 +110,9 @@ class EventHooker
|
|||||||
|
|
||||||
if (eventName === 'interactionCreate')
|
if (eventName === 'interactionCreate')
|
||||||
{
|
{
|
||||||
// const idx = eventArgs.findIndex(val =>
|
|
||||||
// {
|
|
||||||
// console.log(val!.constructor.name, val instanceof BaseInteraction, val instanceof ChatInputCommandInteraction);
|
|
||||||
// return val instanceof BaseInteraction;
|
|
||||||
// });
|
|
||||||
// // ChatInputCommandInteraction;
|
|
||||||
// console.log(idx, args);
|
|
||||||
eventArgs[0] = new InteractionWrapper(this.#target, args[0] as Interaction);
|
eventArgs[0] = new InteractionWrapper(this.#target, args[0] as Interaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// async-await does nothing in a .forEach loop,
|
|
||||||
// the forEach implementation does not await the results of the function before moving onto the next iteration
|
|
||||||
// which is a problem if we don't want functionality to be overlapping, i.e. different filters trying to delete the same message
|
|
||||||
for (const handler of this.#events.get(eventName) || [])
|
for (const handler of this.#events.get(eventName) || [])
|
||||||
{
|
{
|
||||||
if (process.env.NODE_ENV === 'development')
|
if (process.env.NODE_ENV === 'development')
|
||||||
|
@ -17,6 +17,14 @@
|
|||||||
import DiscordClient from '../DiscordClient.js';
|
import DiscordClient from '../DiscordClient.js';
|
||||||
import SlashCommand from '../interfaces/commands/SlashCommand.js';
|
import SlashCommand from '../interfaces/commands/SlashCommand.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPC module.
|
||||||
|
* Currently primarily only used to tell the controller to update slash commands.
|
||||||
|
* Wraps sending messages to the main process.
|
||||||
|
*
|
||||||
|
* @class Intercom
|
||||||
|
* @typedef {Intercom}
|
||||||
|
*/
|
||||||
class Intercom
|
class Intercom
|
||||||
{
|
{
|
||||||
#client: DiscordClient;
|
#client: DiscordClient;
|
||||||
|
@ -31,6 +31,16 @@ type Languages = {
|
|||||||
[key: string]: Language
|
[key: string]: Language
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes care of localisation.
|
||||||
|
* Loads languages from files and takes care of formatting the strings.
|
||||||
|
*
|
||||||
|
* This class should rarely be called directly from most code,
|
||||||
|
* rather used through wrappers that fill in options, e.g. GuildWrapper.format
|
||||||
|
*
|
||||||
|
* @class LocaleLoader
|
||||||
|
* @typedef {LocaleLoader}
|
||||||
|
*/
|
||||||
class LocaleLoader
|
class LocaleLoader
|
||||||
{
|
{
|
||||||
#logger: LoggerClient;
|
#logger: LoggerClient;
|
||||||
|
@ -30,6 +30,17 @@ type DeleteQueueEntry = {
|
|||||||
message: Message,
|
message: Message,
|
||||||
} & QueueEntry
|
} & QueueEntry
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class used for limiting the amount of messages the bot sends.
|
||||||
|
* Most useful when filtering and sending certain log messages.
|
||||||
|
*
|
||||||
|
* Filters usually notify the user about their message being deleted, but that notice should be sent out infrequently.
|
||||||
|
* Logs like member logs may sometimes have to send out multiple messages in a short span, and can be batched easily.
|
||||||
|
* Also used when batching deletions.
|
||||||
|
*
|
||||||
|
* @class RateLimiter
|
||||||
|
* @typedef {RateLimiter}
|
||||||
|
*/
|
||||||
class RateLimiter
|
class RateLimiter
|
||||||
{
|
{
|
||||||
#client: DiscordClient;
|
#client: DiscordClient;
|
||||||
|
@ -24,6 +24,13 @@ import { Command, Component, Module, Setting } from '../interfaces/index.js';
|
|||||||
import { Util } from '../../utilities/index.js';
|
import { Util } from '../../utilities/index.js';
|
||||||
import { isInitialisable } from '../interfaces/Initialisable.js';
|
import { isInitialisable } from '../interfaces/Initialisable.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component registry.
|
||||||
|
* Takes care of instantiating and storing most components.
|
||||||
|
*
|
||||||
|
* @class Registry
|
||||||
|
* @typedef {Registry}
|
||||||
|
*/
|
||||||
class Registry
|
class Registry
|
||||||
{
|
{
|
||||||
#client: DiscordClient;
|
#client: DiscordClient;
|
||||||
|
@ -38,17 +38,19 @@ const filterInexact = <T extends Component>(search: string) => (comp: T) => comp
|
|||||||
|| ((comp instanceof Command || comp instanceof Setting) && comp.aliases && (comp.aliases.some((ali) => `${comp.type}:${ali}`.toLowerCase().includes(search)))
|
|| ((comp instanceof Command || comp instanceof Setting) && comp.aliases && (comp.aliases.some((ali) => `${comp.type}:${ali}`.toLowerCase().includes(search)))
|
||||||
|| ((comp instanceof Command || comp instanceof Setting) && comp.aliases.some((ali) => ali.toLowerCase().includes(search))));
|
|| ((comp instanceof Command || comp instanceof Setting) && comp.aliases.some((ali) => ali.toLowerCase().includes(search))));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves various structures.
|
||||||
|
* E.g. string -> discord user
|
||||||
|
*
|
||||||
|
* @class Resolver
|
||||||
|
* @typedef {Resolver}
|
||||||
|
*/
|
||||||
class Resolver
|
class Resolver
|
||||||
{
|
{
|
||||||
#client: DiscordClient;
|
#client: DiscordClient;
|
||||||
#dnsresolver: DNSResolver;
|
#dnsresolver: DNSResolver;
|
||||||
#logger: LoggerClient;
|
#logger: LoggerClient;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of Resolver.
|
|
||||||
* @param {DiscordClient} client
|
|
||||||
* @memberof Resolver
|
|
||||||
*/
|
|
||||||
constructor (client: DiscordClient)
|
constructor (client: DiscordClient)
|
||||||
{
|
{
|
||||||
this.#client = client;
|
this.#client = client;
|
||||||
|
@ -52,6 +52,14 @@ const Constants = {
|
|||||||
RemovedInfractions: [ 'BAN', 'SOFTBAN', 'KICK' ]
|
RemovedInfractions: [ 'BAN', 'SOFTBAN', 'KICK' ]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Infraction class.
|
||||||
|
* This class is responsible for logging and storing the infraction.
|
||||||
|
* Subclasses are responsible for implementing the behaviour of the infraction.
|
||||||
|
*
|
||||||
|
* @class Infraction
|
||||||
|
* @typedef {Infraction}
|
||||||
|
*/
|
||||||
class Infraction
|
class Infraction
|
||||||
{
|
{
|
||||||
static get Type (): InfractionType
|
static get Type (): InfractionType
|
||||||
|
@ -21,6 +21,16 @@ import InvokerWrapper from '../components/wrappers/InvokerWrapper.js';
|
|||||||
import Component from './Component.js';
|
import Component from './Component.js';
|
||||||
import { Command } from './index.js';
|
import { Command } from './index.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base inhibitor class.
|
||||||
|
* Inhibitors are what stop commands from executing in the wrong conditions,
|
||||||
|
* e.g. if a user is missing permissions or the channel is ignored.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @class Inhibitor
|
||||||
|
* @typedef {Inhibitor}
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
abstract class Inhibitor extends Component
|
abstract class Inhibitor extends Component
|
||||||
{
|
{
|
||||||
#name: string;
|
#name: string;
|
||||||
|
@ -20,6 +20,15 @@ import DiscordClient from '../DiscordClient.js';
|
|||||||
import Component from './Component.js';
|
import Component from './Component.js';
|
||||||
import { LoggerClient } from '@navy.gif/logger';
|
import { LoggerClient } from '@navy.gif/logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Observer class.
|
||||||
|
* Observers are what drives the bot's functionality. They listen to the events emitted by Discord.
|
||||||
|
* Most important ones being the CommandHandler and Automoderation classes.
|
||||||
|
*
|
||||||
|
* @class Observer
|
||||||
|
* @typedef {Observer}
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
class Observer extends Component
|
class Observer extends Component
|
||||||
{
|
{
|
||||||
#logger: LoggerClient;
|
#logger: LoggerClient;
|
||||||
|
@ -37,40 +37,13 @@ import CommandOption from './CommandOption.js';
|
|||||||
import { GuildSettingTypes as GuildSettingType } from '../../../@types/Guild.js';
|
import { GuildSettingTypes as GuildSettingType } from '../../../@types/Guild.js';
|
||||||
import { SettingModifyResult, SettingResult } from '../../../@types/Commands/Settings.js';
|
import { SettingModifyResult, SettingResult } from '../../../@types/Commands/Settings.js';
|
||||||
|
|
||||||
// const EMOJIS = {
|
|
||||||
// 'GUILD_TEXT': {
|
|
||||||
// name: 'textchannel',
|
|
||||||
// id: '716414423094525952'
|
|
||||||
// },
|
|
||||||
// 'GUILD_VOICE': {
|
|
||||||
// name: 'voicechannel',
|
|
||||||
// id: '716414422662512762'
|
|
||||||
// },
|
|
||||||
// 'GUILD_NEWS': {
|
|
||||||
// name: 'news',
|
|
||||||
// id: '741725913171099810'
|
|
||||||
// },
|
|
||||||
// 'GUILD_CATEGORY': {
|
|
||||||
// name: 'category',
|
|
||||||
// id: '741731053818871901'
|
|
||||||
// },
|
|
||||||
// 'GUILD_ROLE': {
|
|
||||||
// name: 'role',
|
|
||||||
// id: '743563678292639794'
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
type HelperResult = {
|
type HelperResult = {
|
||||||
modified: string[]
|
modified: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// declare interface Setting extends Component {
|
|
||||||
// add: () => HelperResult;
|
|
||||||
// remove: () => HelperResult;
|
|
||||||
// set: () => HelperResult;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Base setting class.
|
||||||
|
*
|
||||||
* @class Setting
|
* @class Setting
|
||||||
* @extends {Component}
|
* @extends {Component}
|
||||||
*/
|
*/
|
||||||
@ -243,22 +216,6 @@ abstract class Setting<IsGuildSetting extends boolean = true> extends Component
|
|||||||
fields.push({
|
fields.push({
|
||||||
name: `》 ${guild.format('GENERAL_OPTIONS')}`,
|
name: `》 ${guild.format('GENERAL_OPTIONS')}`,
|
||||||
value: options.map((opt) => opt.usage(guild, true)).map((f) => f.value).join('\n\n')
|
value: options.map((opt) => opt.usage(guild, true)).map((f) => f.value).join('\n\n')
|
||||||
// value: options.map(
|
|
||||||
// (opt) => {
|
|
||||||
// let msg = `**${opt.name} [${opt.type}]:** ${opt.description}`;
|
|
||||||
// if (opt.choices.length)
|
|
||||||
// msg += `\n__${guild.format('GENERAL_CHOICES')}__: ${opt.choices.map((choice) => choice.name).join(', ')}`;
|
|
||||||
// if (opt.dependsOn.length)
|
|
||||||
// msg += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: opt.dependsOn.join('`, `') })}`;
|
|
||||||
// if (opt.minimum !== undefined)
|
|
||||||
// msg += `\nMIN: \`${opt.minimum}\``;
|
|
||||||
// if (opt.maximum !== undefined) {
|
|
||||||
// const newline = opt.minimum !== undefined ? ', ' : '\n';
|
|
||||||
// msg += `${newline}MAX: \`${opt.maximum}\``;
|
|
||||||
// }
|
|
||||||
// return msg;
|
|
||||||
// }
|
|
||||||
// ).join('\n\n')
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,11 +35,19 @@ type CommandThrottle = {
|
|||||||
timeout: NodeJS.Timeout
|
timeout: NodeJS.Timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// declare interface Command extends Component
|
/**
|
||||||
// {
|
* Base class for commands. These can be invoked as text commands (as opposed to slash commands).
|
||||||
// get type(): 'command'
|
* Most commands should not inherit this class directly, rather inherit the SlashCommand class, as most commands
|
||||||
// }
|
* should work as slash commands.
|
||||||
|
*
|
||||||
|
* Note that even though most commands are slash commands, the SlashCommand class inherits this one,
|
||||||
|
* meaning they can also be invoked as text commands.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @class Command
|
||||||
|
* @typedef {Command}
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
abstract class Command extends Component
|
abstract class Command extends Component
|
||||||
{
|
{
|
||||||
#logger: LoggerClient;
|
#logger: LoggerClient;
|
||||||
@ -58,6 +66,7 @@ abstract class Command extends Component
|
|||||||
#clientPermissions: PermissionsString[];
|
#clientPermissions: PermissionsString[];
|
||||||
#memberPermissions: PermissionsString[];
|
#memberPermissions: PermissionsString[];
|
||||||
|
|
||||||
|
// For statistics purposes
|
||||||
#invokes: {
|
#invokes: {
|
||||||
success: number,
|
success: number,
|
||||||
successTime: number,
|
successTime: number,
|
||||||
@ -217,9 +226,6 @@ abstract class Command extends Component
|
|||||||
|
|
||||||
abstract execute(invoker: InvokerWrapper, options: CommandParams):
|
abstract execute(invoker: InvokerWrapper, options: CommandParams):
|
||||||
Promise<string | Message | null | ReplyOptions | void | EmbedBuilder>;
|
Promise<string | Message | null | ReplyOptions | void | EmbedBuilder>;
|
||||||
// {
|
|
||||||
// throw new Error(`${this.resolveable} is missing an execute function.`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
success (when: number)
|
success (when: number)
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,17 @@ import DiscordClient from '../../DiscordClient.js';
|
|||||||
import { ModerationCommandOptions } from '../../../../@types/Commands/Moderation.js';
|
import { ModerationCommandOptions } from '../../../../@types/Commands/Moderation.js';
|
||||||
import { CommandOptionParams, CommandOptionType } from '../../../../@types/Client.js';
|
import { CommandOptionParams, CommandOptionType } from '../../../../@types/Client.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for moderation commands.
|
||||||
|
* Mostly a convenience class as most moderation commands share a lot of the options.
|
||||||
|
* Meaning that strictly speaking a moderation command does not need to inherit this,
|
||||||
|
* but for consistentcy probably should as long as it doesn't prove inconvenient.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @class ModerationCommand
|
||||||
|
* @typedef {ModerationCommand}
|
||||||
|
* @extends {SlashCommand}
|
||||||
|
*/
|
||||||
abstract class ModerationCommand extends SlashCommand
|
abstract class ModerationCommand extends SlashCommand
|
||||||
{
|
{
|
||||||
constructor (client: DiscordClient, opts: ModerationCommandOptions)
|
constructor (client: DiscordClient, opts: ModerationCommandOptions)
|
||||||
|
@ -25,6 +25,13 @@ import { CommandOptionType, CommandParams } from '../../../../@types/Client.js';
|
|||||||
import InvokerWrapper from '../../components/wrappers/InvokerWrapper.js';
|
import InvokerWrapper from '../../components/wrappers/InvokerWrapper.js';
|
||||||
import { APIEmbed } from 'discord.js';
|
import { APIEmbed } from 'discord.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass for any settings commands.
|
||||||
|
*
|
||||||
|
* @class SettingsCommand
|
||||||
|
* @typedef {SettingsCommand}
|
||||||
|
* @extends {SlashCommand}
|
||||||
|
*/
|
||||||
class SettingsCommand extends SlashCommand
|
class SettingsCommand extends SlashCommand
|
||||||
{
|
{
|
||||||
constructor (client: DiscordClient, opts: SettingsCommandOptions)
|
constructor (client: DiscordClient, opts: SettingsCommandOptions)
|
||||||
@ -51,10 +58,6 @@ class SettingsCommand extends SlashCommand
|
|||||||
const settings = this.client.registry
|
const settings = this.client.registry
|
||||||
.filter((c: Setting) => c.type === 'setting' && c.module.name === this.name);
|
.filter((c: Setting) => c.type === 'setting' && c.module.name === this.name);
|
||||||
|
|
||||||
// const allSettings = this.client.registry.components.filter((c) => c._type ==='setting');
|
|
||||||
// Organise modules into subcommand groups
|
|
||||||
// const modules = new Set(allSettings.map((set) => set.module.name));
|
|
||||||
|
|
||||||
for (const setting of settings.values())
|
for (const setting of settings.values())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -77,28 +80,6 @@ class SettingsCommand extends SlashCommand
|
|||||||
this.client.logger.error(`Setting ${setting.name} errored during options build:\n${error.stack}`);
|
this.client.logger.error(`Setting ${setting.name} errored during options build:\n${error.stack}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (const module of modules) {
|
|
||||||
// const settingsModule = allSettings.filter((s) => s.module.name === module);
|
|
||||||
// // /settings moderation
|
|
||||||
// const moduleSubcommand = new CommandOption({
|
|
||||||
// name: module,
|
|
||||||
// description: `Configure ${module} settings`,
|
|
||||||
// type: 'SUB_COMMAND_GROUP'
|
|
||||||
// });
|
|
||||||
// for (const setting of settingsModule.values()) {
|
|
||||||
// // Each setting becomes its own subcommand with options defined in the settings
|
|
||||||
// // /settings moderation mute role:@muted permanent:false default:1h type:1
|
|
||||||
// const settingSubcommand = new CommandOption({
|
|
||||||
// name: setting.name,
|
|
||||||
// description: setting.description,
|
|
||||||
// type: 'SUB_COMMAND',
|
|
||||||
// options: setting.commandOptions
|
|
||||||
// });
|
|
||||||
// moduleSubcommand.options.push(settingSubcommand);
|
|
||||||
// }
|
|
||||||
// this.options.push(moduleSubcommand);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute (invoker: InvokerWrapper<true>, opts: CommandParams)
|
async execute (invoker: InvokerWrapper<true>, opts: CommandParams)
|
||||||
@ -125,7 +106,6 @@ class SettingsCommand extends SlashCommand
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// await invoker.deferReply();
|
|
||||||
const settings = await guild.settings();
|
const settings = await guild.settings();
|
||||||
if (!Object.keys(opts).length && this.subcommand(subcommand!.name)!.options.length)
|
if (!Object.keys(opts).length && this.subcommand(subcommand!.name)!.options.length)
|
||||||
return this._showSetting(invoker, setting);
|
return this._showSetting(invoker, setting);
|
||||||
|
@ -20,6 +20,16 @@ import Command from './Command.js';
|
|||||||
|
|
||||||
import { ApplicationCommandType, PermissionsBitField } from 'discord.js';
|
import { ApplicationCommandType, PermissionsBitField } from 'discord.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for most of the commands on the bot.
|
||||||
|
* Only commands that SHOULD NOT inherit this are ones that shouldn't appear as slash commands,
|
||||||
|
* e.g. certain developer only commands (ex. eval)
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @class SlashCommand
|
||||||
|
* @typedef {SlashCommand}
|
||||||
|
* @extends {Command}
|
||||||
|
*/
|
||||||
abstract class SlashCommand extends Command
|
abstract class SlashCommand extends Command
|
||||||
{
|
{
|
||||||
#type: ApplicationCommandType;
|
#type: ApplicationCommandType;
|
||||||
|
Loading…
Reference in New Issue
Block a user