feat: reset

This commit is contained in:
TresAbhi committed 2023-04-18 00:59:39 +00:00
1 parent d769b852a9
commit f7c356de1e
111 files changed
-11745

No files matched your search

-83
View File
@@ -1,83 +0,0 @@
import { ButtonInteraction } from 'discord.js';
import { RateLimiter } from 'discord.js-rate-limiter';
import { createRequire } from 'node:module';
import { EventHandler } from './index.js';
import { Button, ButtonDeferType } from '../buttons/index.js';
import { EventDataService } from '../services/index.js';
import { InteractionUtils } from '../utils/index.js';
const require = createRequire(import.meta.url);
let Config = require('../../config/config.json');
export class ButtonHandler implements EventHandler {
private rateLimiter = new RateLimiter(
Config.rateLimiting.buttons.amount,
Config.rateLimiting.buttons.interval * 1000
);
constructor(private buttons: Button[], private eventDataService: EventDataService) {}
public async process(intr: ButtonInteraction): Promise<void> {
// Don't respond to self, or other bots
if (intr.user.id === intr.client.user?.id || intr.user.bot) {
return;
}
// Check if user is rate limited
let limited = this.rateLimiter.take(intr.user.id);
if (limited) {
return;
}
// Try to find the button the user wants
let button = this.findButton(intr.customId);
if (!button) {
return;
}
if (button.requireGuild && !intr.guild) {
return;
}
// Check if the embeds author equals the users tag
if (
button.requireEmbedAuthorTag &&
intr.message.embeds[0]?.author?.name !== intr.user.tag
) {
return;
}
// Defer interaction
// NOTE: Anything after this point we should be responding to the interaction
switch (button.deferType) {
case ButtonDeferType.REPLY: {
await InteractionUtils.deferReply(intr);
break;
}
case ButtonDeferType.UPDATE: {
await InteractionUtils.deferUpdate(intr);
break;
}
}
// Return if defer was unsuccessful
if (button.deferType !== ButtonDeferType.NONE && !intr.deferred) {
return;
}
// Get data from database
let data = await this.eventDataService.create({
user: intr.user,
channel: intr.channel,
guild: intr.guild,
});
// Execute the button
await button.execute(intr, data);
}
private findButton(id: string): Button {
return this.buttons.find(button => button.ids.includes(id));
}
}
-182
View File
@@ -1,182 +0,0 @@
import {
AutocompleteInteraction,
ChatInputCommandInteraction,
CommandInteraction,
NewsChannel,
TextChannel,
ThreadChannel,
} from 'discord.js';
import { RateLimiter } from 'discord.js-rate-limiter';
import { createRequire } from 'node:module';
import { EventHandler } from './index.js';
import { Command, CommandDeferType } from '../commands/index.js';
import { DiscordLimits } from '../constants/index.js';
import { EventData } from '../models/internal-models.js';
import { EventDataService, Lang, Logger } from '../services/index.js';
import { CommandUtils, InteractionUtils } from '../utils/index.js';
const require = createRequire(import.meta.url);
let Config = require('../../config/config.json');
let Logs = require('../../lang/logs.json');
export class CommandHandler implements EventHandler {
private rateLimiter = new RateLimiter(
Config.rateLimiting.commands.amount,
Config.rateLimiting.commands.interval * 1000
);
constructor(public commands: Command[], private eventDataService: EventDataService) {}
public async process(intr: CommandInteraction | AutocompleteInteraction): Promise<void> {
// Don't respond to self, or other bots
if (intr.user.id === intr.client.user?.id || intr.user.bot) {
return;
}
let commandParts =
intr instanceof ChatInputCommandInteraction || intr instanceof AutocompleteInteraction
? [
intr.commandName,
intr.options.getSubcommandGroup(false),
intr.options.getSubcommand(false),
].filter(Boolean)
: [intr.commandName];
let commandName = commandParts.join(' ');
// Try to find the command the user wants
let command = CommandUtils.findCommand(this.commands, commandParts);
if (!command) {
Logger.error(
Logs.error.commandNotFound
.replaceAll('{INTERACTION_ID}', intr.id)
.replaceAll('{COMMAND_NAME}', commandName)
);
return;
}
if (intr instanceof AutocompleteInteraction) {
if (!command.autocomplete) {
Logger.error(
Logs.error.autocompleteNotFound
.replaceAll('{INTERACTION_ID}', intr.id)
.replaceAll('{COMMAND_NAME}', commandName)
);
return;
}
try {
let option = intr.options.getFocused(true);
let choices = await command.autocomplete(intr, option);
await InteractionUtils.respond(
intr,
choices?.slice(0, DiscordLimits.CHOICES_PER_AUTOCOMPLETE)
);
} catch (error) {
Logger.error(
intr.channel instanceof TextChannel ||
intr.channel instanceof NewsChannel ||
intr.channel instanceof ThreadChannel
? Logs.error.autocompleteGuild
.replaceAll('{INTERACTION_ID}', intr.id)
.replaceAll('{OPTION_NAME}', commandName)
.replaceAll('{COMMAND_NAME}', commandName)
.replaceAll('{USER_TAG}', intr.user.tag)
.replaceAll('{USER_ID}', intr.user.id)
.replaceAll('{CHANNEL_NAME}', intr.channel.name)
.replaceAll('{CHANNEL_ID}', intr.channel.id)
.replaceAll('{GUILD_NAME}', intr.guild?.name)
.replaceAll('{GUILD_ID}', intr.guild?.id)
: Logs.error.autocompleteOther
.replaceAll('{INTERACTION_ID}', intr.id)
.replaceAll('{OPTION_NAME}', commandName)
.replaceAll('{COMMAND_NAME}', commandName)
.replaceAll('{USER_TAG}', intr.user.tag)
.replaceAll('{USER_ID}', intr.user.id),
error
);
}
return;
}
// Check if user is rate limited
let limited = this.rateLimiter.take(intr.user.id);
if (limited) {
return;
}
// Defer interaction
// NOTE: Anything after this point we should be responding to the interaction
switch (command.deferType) {
case CommandDeferType.PUBLIC: {
await InteractionUtils.deferReply(intr, false);
break;
}
case CommandDeferType.HIDDEN: {
await InteractionUtils.deferReply(intr, true);
break;
}
}
// Return if defer was unsuccessful
if (command.deferType !== CommandDeferType.NONE && !intr.deferred) {
return;
}
// Get data from database
let data = await this.eventDataService.create({
user: intr.user,
channel: intr.channel,
guild: intr.guild,
args: intr instanceof ChatInputCommandInteraction ? intr.options : undefined,
});
try {
// Check if interaction passes command checks
let passesChecks = await CommandUtils.runChecks(command, intr, data);
if (passesChecks) {
// Execute the command
await command.execute(intr, data);
}
} catch (error) {
await this.sendError(intr, data);
// Log command error
Logger.error(
intr.channel instanceof TextChannel ||
intr.channel instanceof NewsChannel ||
intr.channel instanceof ThreadChannel
? Logs.error.commandGuild
.replaceAll('{INTERACTION_ID}', intr.id)
.replaceAll('{COMMAND_NAME}', commandName)
.replaceAll('{USER_TAG}', intr.user.tag)
.replaceAll('{USER_ID}', intr.user.id)
.replaceAll('{CHANNEL_NAME}', intr.channel.name)
.replaceAll('{CHANNEL_ID}', intr.channel.id)
.replaceAll('{GUILD_NAME}', intr.guild?.name)
.replaceAll('{GUILD_ID}', intr.guild?.id)
: Logs.error.commandOther
.replaceAll('{INTERACTION_ID}', intr.id)
.replaceAll('{COMMAND_NAME}', commandName)
.replaceAll('{USER_TAG}', intr.user.tag)
.replaceAll('{USER_ID}', intr.user.id),
error
);
}
}
private async sendError(intr: CommandInteraction, data: EventData): Promise<void> {
try {
await InteractionUtils.send(
intr,
Lang.getEmbed('errorEmbeds.command', data.lang, {
ERROR_CODE: intr.id,
GUILD_ID: intr.guild?.id ?? Lang.getRef('other.na', data.lang),
SHARD_ID: (intr.guild?.shardId ?? 0).toString(),
})
);
} catch {
// Ignore
}
}
}
-3
View File
@@ -1,3 +0,0 @@
export interface EventHandler {
process(...args: any[]): Promise<void>;
}
-67
View File
@@ -1,67 +0,0 @@
import { Guild } from 'discord.js';
import { createRequire } from 'node:module';
import { EventHandler } from './index.js';
import { Language } from '../models/enum-helpers/index.js';
import { EventDataService, Lang, Logger } from '../services/index.js';
import { ClientUtils, FormatUtils, MessageUtils } from '../utils/index.js';
const require = createRequire(import.meta.url);
let Logs = require('../../lang/logs.json');
export class GuildJoinHandler implements EventHandler {
constructor(private eventDataService: EventDataService) {}
public async process(guild: Guild): Promise<void> {
Logger.info(
Logs.info.guildJoined
.replaceAll('{GUILD_NAME}', guild.name)
.replaceAll('{GUILD_ID}', guild.id)
);
let owner = await guild.fetchOwner();
// Get data from database
let data = await this.eventDataService.create({
user: owner?.user,
guild,
});
// Send welcome message to the server's notify channel
let notifyChannel = await ClientUtils.findNotifyChannel(guild, data.langGuild);
if (notifyChannel) {
await MessageUtils.send(
notifyChannel,
Lang.getEmbed('displayEmbeds.welcome', data.langGuild, {
CMD_LINK_HELP: FormatUtils.commandMention(
await ClientUtils.findAppCommand(
guild.client,
Lang.getRef('chatCommands.help', Language.Default)
)
),
}).setAuthor({
name: guild.name,
iconURL: guild.iconURL(),
})
);
}
// Send welcome message to owner
if (owner) {
await MessageUtils.send(
owner.user,
Lang.getEmbed('displayEmbeds.welcome', data.lang, {
CMD_LINK_HELP: FormatUtils.commandMention(
await ClientUtils.findAppCommand(
guild.client,
Lang.getRef('chatCommands.help', Language.Default)
)
),
}).setAuthor({
name: guild.name,
iconURL: guild.iconURL(),
})
);
}
}
}
-18
View File
@@ -1,18 +0,0 @@
import { Guild } from 'discord.js';
import { createRequire } from 'node:module';
import { EventHandler } from './index.js';
import { Logger } from '../services/index.js';
const require = createRequire(import.meta.url);
let Logs = require('../../lang/logs.json');
export class GuildLeaveHandler implements EventHandler {
public async process(guild: Guild): Promise<void> {
Logger.info(
Logs.info.guildLeft
.replaceAll('{GUILD_NAME}', guild.name)
.replaceAll('{GUILD_ID}', guild.id)
);
}
}
-8
View File
@@ -1,8 +0,0 @@
export { ButtonHandler } from './button-handler.js';
export { CommandHandler } from './command-handler.js';
export { EventHandler } from './event-handler.js';
export { GuildJoinHandler } from './guild-join-handler.js';
export { GuildLeaveHandler } from './guild-leave-handler.js';
export { ReactionHandler } from './reaction-handler.js';
export { MessageHandler } from './message-handler.js';
export { TriggerHandler } from './trigger-handler.js';
-17
View File
@@ -1,17 +0,0 @@
import { Message } from 'discord.js';
import { EventHandler, TriggerHandler } from './index.js';
export class MessageHandler implements EventHandler {
constructor(private triggerHandler: TriggerHandler) {}
public async process(msg: Message): Promise<void> {
// Don't respond to system messages or self
if (msg.system || msg.author.id === msg.client.user?.id) {
return;
}
// Process trigger
await this.triggerHandler.process(msg);
}
}
-65
View File
@@ -1,65 +0,0 @@
import { Message, MessageReaction, User } from 'discord.js';
import { RateLimiter } from 'discord.js-rate-limiter';
import { createRequire } from 'node:module';
import { EventHandler } from './index.js';
import { Reaction } from '../reactions/index.js';
import { EventDataService } from '../services/index.js';
const require = createRequire(import.meta.url);
let Config = require('../../config/config.json');
export class ReactionHandler implements EventHandler {
private rateLimiter = new RateLimiter(
Config.rateLimiting.reactions.amount,
Config.rateLimiting.reactions.interval * 1000
);
constructor(private reactions: Reaction[], private eventDataService: EventDataService) {}
public async process(msgReaction: MessageReaction, msg: Message, reactor: User): Promise<void> {
// Don't respond to self, or other bots
if (reactor.id === msgReaction.client.user?.id || reactor.bot) {
return;
}
// Check if user is rate limited
let limited = this.rateLimiter.take(msg.author.id);
if (limited) {
return;
}
// Try to find the reaction the user wants
let reaction = this.findReaction(msgReaction.emoji.name);
if (!reaction) {
return;
}
if (reaction.requireGuild && !msg.guild) {
return;
}
if (reaction.requireSentByClient && msg.author.id !== msg.client.user?.id) {
return;
}
// Check if the embeds author equals the reactors tag
if (reaction.requireEmbedAuthorTag && msg.embeds[0]?.author?.name !== reactor.tag) {
return;
}
// Get data from database
let data = await this.eventDataService.create({
user: reactor,
channel: msg.channel,
guild: msg.guild,
});
// Execute the reaction
await reaction.execute(msgReaction, msg, reactor, data);
}
private findReaction(emoji: string): Reaction {
return this.reactions.find(reaction => reaction.emoji === emoji);
}
}
-56
View File
@@ -1,56 +0,0 @@
import { Message } from 'discord.js';
import { RateLimiter } from 'discord.js-rate-limiter';
import { createRequire } from 'node:module';
import { EventDataService } from '../services/index.js';
import { Trigger } from '../triggers/index.js';
const require = createRequire(import.meta.url);
let Config = require('../../config/config.json');
export class TriggerHandler {
private rateLimiter = new RateLimiter(
Config.rateLimiting.triggers.amount,
Config.rateLimiting.triggers.interval * 1000
);
constructor(private triggers: Trigger[], private eventDataService: EventDataService) {}
public async process(msg: Message): Promise<void> {
// Check if user is rate limited
let limited = this.rateLimiter.take(msg.author.id);
if (limited) {
return;
}
// Find triggers caused by this message
let triggers = this.triggers.filter(trigger => {
if (trigger.requireGuild && !msg.guild) {
return false;
}
if (!trigger.triggered(msg)) {
return false;
}
return true;
});
// If this message causes no triggers then return
if (triggers.length === 0) {
return;
}
// Get data from database
let data = await this.eventDataService.create({
user: msg.author,
channel: msg.channel,
guild: msg.guild,
});
// Execute triggers
for (let trigger of triggers) {
await trigger.execute(msg, data);
}
}
}