diff --git a/README.md b/README.md index 266d60859..dbd4abb01 100644 --- a/README.md +++ b/README.md @@ -89,10 +89,10 @@ const customId = CustomID.parseCustomId(interaction.customId); To handle components (buttons, selects, modals) create a new method called `handleComponents` or `handleModals` for modals in the command/subcommand class. Then create a decorator for the method using the `@InteractionHandler` decorator with the customId prefix of the components/modals. The method will be called when the component is triggered. Example: -```ts +```typescript // you can change the type of `interaction` to ButtonInteraction etc. if you are aware of the type of component @InteractionHandler('cool_button_') -public async handleComponents(interaction: MessageComponentInteraction) { +static override async handleComponents(interaction: MessageComponentInteraction) { const customId = CustomID.parseCustomId(interaction.customId); // handle component logic, same as how it is with collectors } diff --git a/src/commands/context-menu/blacklist.ts b/src/commands/context-menu/blacklist.ts index 0a29162ec..af4d70adc 100644 --- a/src/commands/context-menu/blacklist.ts +++ b/src/commands/context-menu/blacklist.ts @@ -93,7 +93,7 @@ export default class Blacklist extends BaseCommand { } @RegisterInteractionHandler('blacklist') - async handleComponents(interaction: MessageComponentInteraction): Promise { + static override async handleComponents(interaction: MessageComponentInteraction): Promise { const customId = CustomID.parseCustomId(interaction.customId); if (interaction.user.id !== customId.args[0]) { diff --git a/src/commands/context-menu/deleteMsg.ts b/src/commands/context-menu/deleteMsg.ts index d9fad2621..73e529c49 100644 --- a/src/commands/context-menu/deleteMsg.ts +++ b/src/commands/context-menu/deleteMsg.ts @@ -59,13 +59,8 @@ export default class DeleteMessage extends BaseCommand { ); } - // find all the messages through the network - const channelSettingsArr = await db.connectedList.findMany({ - where: { channelId: { in: messageInDb.originalMsg.broadcastMsgs.map((c) => c.channelId) } }, - }); - const results = messageInDb.originalMsg.broadcastMsgs.map(async (element) => { - const connection = channelSettingsArr.find((c) => c.channelId === element.channelId); + const connection = interaction.client.connectionCache.find((c) => c.channelId === element.channelId); if (!connection) return false; const webhookURL = connection.webhookURL.split('/'); diff --git a/src/commands/context-menu/messageInfo.ts b/src/commands/context-menu/messageInfo.ts index ca8ea8484..3aac00a56 100644 --- a/src/commands/context-menu/messageInfo.ts +++ b/src/commands/context-menu/messageInfo.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity */ import { ActionRow, ActionRowBuilder, @@ -96,7 +97,7 @@ export default class MessageInfo extends BaseCommand { } @RegisterInteractionHandler('msgInfo') - async handleComponents(interaction: MessageComponentInteraction) { + static override async handleComponents(interaction: MessageComponentInteraction) { // create a variable to store the profile card buffer const customId = CustomID.parseCustomId(interaction.customId); const messageId = customId.args[0]; @@ -109,7 +110,7 @@ export default class MessageInfo extends BaseCommand { )?.originalMsg; if (!originalMsg) { - return await interaction.update({ + await interaction.update({ content: t( { phrase: 'errors.unknownNetworkMessage', locale: interaction.user.locale }, { emoji: emojis.no }, @@ -117,6 +118,7 @@ export default class MessageInfo extends BaseCommand { embeds: [], components: [], }); + return; } const author = await interaction.client.users.fetch(originalMsg.authorId); @@ -144,7 +146,7 @@ export default class MessageInfo extends BaseCommand { // server info button case 'serverInfo': { if (!server) { - return await interaction.update({ + await interaction.update({ content: t( { phrase: 'errors.unknownServer', locale: interaction.user.locale }, { emoji: emojis.no }, @@ -152,6 +154,7 @@ export default class MessageInfo extends BaseCommand { embeds: [], components: [], }); + return; } const owner = await interaction.client.users.fetch(server.ownerId); @@ -276,7 +279,7 @@ export default class MessageInfo extends BaseCommand { case 'report': { if (!originalMsg.hub?.logChannels?.reports) { - return await interaction.reply({ + await interaction.reply({ embeds: [ simpleEmbed( t( @@ -287,6 +290,7 @@ export default class MessageInfo extends BaseCommand { ], ephemeral: true, }); + return; } const modal = new ModalBuilder() @@ -323,7 +327,7 @@ export default class MessageInfo extends BaseCommand { }); if (!messageInDb?.originalMsg.hub?.logChannels?.reports) { - return await interaction.reply({ + await interaction.reply({ embeds: [ simpleEmbed( t( @@ -334,6 +338,7 @@ export default class MessageInfo extends BaseCommand { ], ephemeral: true, }); + return; } const { authorId, serverId } = messageInDb.originalMsg; diff --git a/src/commands/context-menu/translate.ts b/src/commands/context-menu/translate.ts index 115a5d0ee..91bfeca8b 100644 --- a/src/commands/context-menu/translate.ts +++ b/src/commands/context-menu/translate.ts @@ -93,7 +93,7 @@ export default class Translate extends BaseCommand { } @RegisterInteractionHandler('translate') - async handleComponents(interaction: ButtonInteraction) { + static override async handleComponents(interaction: ButtonInteraction) { const modal = new ModalBuilder() .setCustomId(new CustomID('translate_modal').toString()) .setTitle('Specify Language') diff --git a/src/commands/slash/Information/credits.ts b/src/commands/slash/Information/about.ts similarity index 95% rename from src/commands/slash/Information/credits.ts rename to src/commands/slash/Information/about.ts index b516deb37..d91160ee2 100644 --- a/src/commands/slash/Information/credits.ts +++ b/src/commands/slash/Information/about.ts @@ -8,13 +8,13 @@ import { } from 'discord.js'; import { badgeEmojis, emojis, LINKS } from '../../../utils/Constants.js'; import { getCredits, simpleEmbed } from '../../../utils/Utils.js'; -import BaseCommand from '../../../core/BaseCommand.js'; import { stripIndents } from 'common-tags'; +import BaseCommand from '../../../core/BaseCommand.js'; -export default class Credits extends BaseCommand { +export default class About extends BaseCommand { readonly data: RESTPostAPIChatInputApplicationCommandsJSONBody = { - name: 'credits', - description: 'Shows the credits for InterChat', + name: 'about', + description: 'Learn more about the InterChat team and project.', }; private async getUsernames(client: Client): Promise { diff --git a/src/commands/slash/Information/stats.ts b/src/commands/slash/Information/stats.ts index a5bd6ad00..21973b9a8 100644 --- a/src/commands/slash/Information/stats.ts +++ b/src/commands/slash/Information/stats.ts @@ -106,7 +106,7 @@ export default class Stats extends BaseCommand { } @RegisterInteractionHandler('stats') - async handleComponents(interaction: ButtonInteraction) { + static override async handleComponents(interaction: ButtonInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const allCusterData = await interaction.client.cluster.broadcastEval((client) => { diff --git a/src/commands/slash/Main/blacklist/index.ts b/src/commands/slash/Main/blacklist/index.ts index c7705804f..075ae2c8a 100644 --- a/src/commands/slash/Main/blacklist/index.ts +++ b/src/commands/slash/Main/blacklist/index.ts @@ -258,6 +258,8 @@ export default class BlacklistCommand extends BaseCommand { await interaction.respond(choices); break; } + default: + break; } } } diff --git a/src/commands/slash/Main/connection.ts b/src/commands/slash/Main/connection.ts index 007322a75..7e916bb36 100644 --- a/src/commands/slash/Main/connection.ts +++ b/src/commands/slash/Main/connection.ts @@ -3,6 +3,7 @@ import { ApplicationCommandOptionType, AutocompleteInteraction, ChannelSelectMenuBuilder, + ChannelSelectMenuInteraction, ChannelType, ChatInputCommandInteraction, MessageComponentInteraction, @@ -11,6 +12,7 @@ import { PermissionFlagsBits, RESTPostAPIApplicationCommandsJSONBody, StringSelectMenuBuilder, + StringSelectMenuInteraction, StringSelectMenuOptionBuilder, TextChannel, TextInputBuilder, @@ -23,7 +25,7 @@ import db from '../../../utils/Db.js'; import { RegisterInteractionHandler } from '../../../decorators/Interaction.js'; import { buildConnectionButtons } from '../../../scripts/network/components.js'; import { emojis } from '../../../utils/Constants.js'; -import { CustomID } from '../../../utils/CustomID.js'; +import { CustomID, ParsedCustomId } from '../../../utils/CustomID.js'; import { simpleEmbed, getOrCreateWebhook, @@ -31,6 +33,7 @@ import { escapeRegexChars, } from '../../../utils/Utils.js'; import { t } from '../../../utils/Locale.js'; +import { connectedList } from '@prisma/client'; export default class Connection extends BaseCommand { readonly data: RESTPostAPIApplicationCommandsJSONBody = { @@ -48,12 +51,14 @@ export default class Connection extends BaseCommand { }, ], }; - async execute(interaction: ChatInputCommandInteraction): Promise { + override async execute(interaction: ChatInputCommandInteraction) { + if (!interaction.deferred && !interaction.replied) await interaction.deferReply(); + const channelId = interaction.options.getString('channel', true).replace(/<#|!|>/g, ''); // in case they mention the channel const isInDb = await db.connectedList.findFirst({ where: { channelId } }); if (!isInDb) { - await interaction.reply({ + await interaction.editReply({ embeds: [ simpleEmbed( t( @@ -62,7 +67,6 @@ export default class Connection extends BaseCommand { ), ), ], - ephemeral: true, }); return; } @@ -70,8 +74,6 @@ export default class Connection extends BaseCommand { const embed = await buildEmbed(interaction, channelId); const buttons = buildConnectionButtons(true, channelId, { userId: interaction.user.id }); - if (!interaction.deferred && !interaction.replied) await interaction.deferReply(); - const customizeMenu = new ActionRowBuilder().addComponents([ new StringSelectMenuBuilder() .setCustomId( @@ -163,7 +165,7 @@ export default class Connection extends BaseCommand { } @RegisterInteractionHandler('connection') - async handleComponents(interaction: MessageComponentInteraction) { + static override async handleComponents(interaction: MessageComponentInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const channelId = customId.args[0]; @@ -210,157 +212,16 @@ export default class Connection extends BaseCommand { }); } - // String select menu interactions else if (interaction.isStringSelectMenu()) { - switch (interaction.values[0]) { - case 'compact': - await db.connectedList.update({ - where: { channelId }, - data: { compact: !isInDb.compact }, - }); - break; - - case 'profanity': - await db.connectedList.update({ - where: { channelId }, - data: { profFilter: !isInDb.profFilter }, - }); - break; - - case 'invite': { - const modal = new ModalBuilder() - .setTitle('Add Invite Link') - .setCustomId( - new CustomID() - .setIdentifier('connectionModal', 'invite') - .addArgs(channelId) - .toString(), - ) - .addComponents( - new ActionRowBuilder().addComponents( - new TextInputBuilder() - .setLabel('Invite Link') - .setValue('https://discord.gg/') - .setCustomId('connInviteField') - .setRequired(false) - .setStyle(TextInputStyle.Short), - ), - ); - - await interaction.showModal(modal); - break; - } - case 'change_channel': { - const channelSelect = new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId( - new CustomID() - .setIdentifier('connection', 'change_channel') - .addArgs(channelId) - .addArgs(interaction.user.id) - .toString(), - ) - .setChannelTypes( - ChannelType.GuildText, - ChannelType.PublicThread, - ChannelType.PrivateThread, - ) - .setPlaceholder('Select a channel to switch to.'), - ); - - await interaction.update({ - content: t( - { phrase: 'connection.switchChannel', locale: interaction.user.locale }, - { emoji: emojis.info }, - ), - embeds: [], - components: [channelSelect], - }); - break; - } - - case 'embed_color': { - const modal = new ModalBuilder() - .setTitle('Set Embed Color') - .setCustomId( - new CustomID() - .setIdentifier('connectionModal', 'embed_color') - .addArgs(channelId) - .toString(), - ) - .addComponents( - new ActionRowBuilder().addComponents( - new TextInputBuilder() - .setCustomId('embed_color') - .setStyle(TextInputStyle.Short) - .setLabel('Embed Color') - .setPlaceholder('Provide a hex color code or leave blank to remove.') - .setValue(isInDb.embedColor || '#000000') - .setRequired(false), - ), - ); - - await interaction.showModal(modal); - break; - } - - default: - break; - } - - const newEmbeds = await buildEmbed(interaction, channelId); - interaction.replied || interaction.deferred - ? await interaction.message.edit({ embeds: [newEmbeds] }).catch(() => null) - : await interaction.update({ embeds: [newEmbeds] }); + Connection.executeStringSelects(interaction, channelId, isInDb); } - - // channel select menu interactions else if (interaction.isChannelSelectMenu()) { - if (customId.suffix !== 'change_channel') return; - await interaction.deferUpdate(); - - const newChannel = interaction.channels.first(); - - const channelInHub = await db.connectedList.findFirst({ - where: { channelId: newChannel?.id }, - }); - - if (channelInHub) { - await interaction.editReply({ - content: null, - embeds: [ - simpleEmbed( - t( - { phrase: 'connection.alreadyConnected', locale: interaction.user.locale }, - { channel: `${newChannel?.toString()}`, emoji: emojis.no }, - ), - ), - ], - }); - return; - } - - const newWebhook = await getOrCreateWebhook(newChannel as TextChannel | ThreadChannel); - await db.connectedList.update({ - where: { channelId }, - data: { channelId: newChannel?.id, webhookURL: newWebhook?.url }, - }); - - await interaction.editReply({ - content: t( - { phrase: 'connection.switchSuccess', locale: interaction.user.locale }, - { channel: `${newChannel?.toString()}`, emoji: emojis.yes }, - ), - // remove error embed, if it occured - embeds: [], - // remove channel select menu - components: [], - }); + Connection.executeChannelSelects(interaction, channelId, customId); } } @RegisterInteractionHandler('connectionModal') - async handleModals(interaction: ModalSubmitInteraction): Promise { + static override async handleModals(interaction: ModalSubmitInteraction): Promise { const customId = CustomID.parseCustomId(interaction.customId); if (customId.suffix === 'invite') { await interaction.deferReply({ ephemeral: true }); @@ -436,4 +297,163 @@ export default class Connection extends BaseCommand { ?.edit({ embeds: [await buildEmbed(interaction, customId.args[0])] }) .catch(() => null); } + + static async executeStringSelects( + interaction: StringSelectMenuInteraction, + channelId: string, + connection: connectedList, + ) { + switch (interaction.values[0]) { + case 'compact': + await db.connectedList.update({ + where: { channelId }, + data: { compact: !connection.compact }, + }); + break; + + case 'profanity': + await db.connectedList.update({ + where: { channelId }, + data: { profFilter: !connection.profFilter }, + }); + break; + + case 'invite': { + const modal = new ModalBuilder() + .setTitle('Add Invite Link') + .setCustomId( + new CustomID().setIdentifier('connectionModal', 'invite').addArgs(channelId).toString(), + ) + .addComponents( + new ActionRowBuilder().addComponents( + new TextInputBuilder() + .setLabel('Invite Link') + .setValue('https://discord.gg/') + .setCustomId('connInviteField') + .setRequired(false) + .setStyle(TextInputStyle.Short), + ), + ); + + await interaction.showModal(modal); + break; + } + case 'change_channel': { + const channelSelect = new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId( + new CustomID() + .setIdentifier('connection', 'change_channel') + .addArgs(channelId) + .addArgs(interaction.user.id) + .toString(), + ) + .setChannelTypes( + ChannelType.GuildText, + ChannelType.PublicThread, + ChannelType.PrivateThread, + ) + .setPlaceholder('Select a channel to switch to.'), + ); + + await interaction.update({ + content: t( + { phrase: 'connection.switchChannel', locale: interaction.user.locale }, + { emoji: emojis.info }, + ), + embeds: [], + components: [channelSelect], + }); + return; + } + + case 'embed_color': { + const modal = new ModalBuilder() + .setTitle('Set Embed Color') + .setCustomId( + new CustomID() + .setIdentifier('connectionModal', 'embed_color') + .addArgs(channelId) + .toString(), + ) + .addComponents( + new ActionRowBuilder().addComponents( + new TextInputBuilder() + .setCustomId('embed_color') + .setStyle(TextInputStyle.Short) + .setLabel('Embed Color') + .setPlaceholder('Provide a hex color code or leave blank to remove.') + .setValue(connection.embedColor || '#000000') + .setRequired(false), + ), + ); + + await interaction.showModal(modal); + break; + } + + default: + break; + } + + const newEmbeds = await buildEmbed(interaction, channelId); + interaction.replied || interaction.deferred + ? await interaction.message.edit({ embeds: [newEmbeds] }).catch(() => null) + : await interaction.update({ embeds: [newEmbeds] }); + } + + + static async executeChannelSelects( + interaction: ChannelSelectMenuInteraction, + channelId: string, + customId: ParsedCustomId, + ) { + if (customId.suffix !== 'change_channel') return; + + await interaction.deferUpdate(); + + const { locale } = interaction.user; + const newChannel = interaction.channels.first(); + + const channelInHub = await db.connectedList.findFirst({ + where: { channelId: newChannel?.id }, + }); + + if (!newChannel) { + await interaction.editReply({ + content: t({ phrase: 'hub.invalidChannel', locale }, { emoji: emojis.no }), + }); + return; + } + else if (channelInHub) { + await interaction.editReply({ + content: null, + components: [], + embeds: [ + simpleEmbed( + t( + { phrase: 'connection.alreadyConnected', locale }, + { channel: `${newChannel?.toString()}`, emoji: emojis.no }, + ), + ), + ], + }); + return; + } + + const newWebhook = await getOrCreateWebhook(newChannel as TextChannel | ThreadChannel); + await db.connectedList.update({ + where: { channelId }, + data: { channelId: newChannel?.id, webhookURL: newWebhook?.url }, + }); + + await interaction.editReply({ + content: t( + { phrase: 'connection.switchSuccess', locale }, + { channel: `${newChannel?.toString()}`, emoji: emojis.yes }, + ), + embeds: [], // remove error embed, if it occured + components: [], // remove channel select menu + }); + } } diff --git a/src/commands/slash/Main/hub/browse.ts b/src/commands/slash/Main/hub/browse.ts index 0bb3e460d..9b202b808 100644 --- a/src/commands/slash/Main/hub/browse.ts +++ b/src/commands/slash/Main/hub/browse.ts @@ -151,7 +151,9 @@ export default class Browse extends Hub { } @RegisterInteractionHandler('hub_browse') - async handleComponents(interaction: ButtonInteraction | ChannelSelectMenuInteraction) { + static override async handleComponents( + interaction: ButtonInteraction | ChannelSelectMenuInteraction, + ): Promise { const customId = CustomID.parseCustomId(interaction.customId); const { locale } = interaction.user; @@ -160,10 +162,11 @@ export default class Browse extends Hub { include: { connections: true }, }); if (!hubDetails) { - return await interaction.reply({ + await interaction.reply({ content: t({ phrase: 'hub.notFound', locale }, { emoji: emojis.no }), ephemeral: true, }); + return; } if (customId.suffix === 'rate') { @@ -203,7 +206,7 @@ export default class Browse extends Hub { const { fetchUserBlacklist, fetchServerBlacklist } = BlacklistManager; const userBlacklisted = await fetchUserBlacklist(hubDetails.id, interaction.user.id); - const serverBlacklisted = await fetchServerBlacklist(hubDetails.id, interaction.guildId!); + const serverBlacklisted = await fetchServerBlacklist(hubDetails.id, interaction.guildId); if (userBlacklisted || serverBlacklisted) { const phrase = userBlacklisted ? 'errors.userBlacklisted' : 'errors.serverBlacklisted'; @@ -275,10 +278,11 @@ export default class Browse extends Hub { if (!interaction.inCachedGuild()) return; if (!hubDetails) { - return await interaction.reply({ + await interaction.reply({ content: t({ phrase: 'hub.notFound', locale }, { emoji: emojis.no }), ephemeral: true, }); + return; } const channel = interaction.isChannelSelectMenu() @@ -331,11 +335,14 @@ export default class Browse extends Hub { if (channelConnected) { await interaction.update({ - content: t( - { phrase: 'connection.alreadyConnected', locale }, - { channel: channel.toString(), emoji: emojis.no }, - ), - embeds: [], + embeds: [ + simpleEmbed( + t( + { phrase: 'connection.alreadyConnected', locale }, + { channel: channel.toString(), emoji: emojis.no }, + ), + ), + ], components: [], }); return; @@ -350,14 +357,16 @@ export default class Browse extends Hub { ); // if user cancels onboarding or it times out if (!onboardingCompleted) { - return await interaction.deleteReply().catch(() => null); + await interaction.deleteReply().catch(() => null); + return; } else if (onboardingCompleted === 'in-progress') { - return await interaction.update({ + await interaction.update({ content: t({ phrase: 'onboarding.inProgress', locale }, { channel: `${channel}` }), embeds: [], components: [], }); + return; } const webhook = await getOrCreateWebhook(channel); diff --git a/src/commands/slash/Main/hub/delete.ts b/src/commands/slash/Main/hub/delete.ts index e1e2aa516..adf86df7e 100644 --- a/src/commands/slash/Main/hub/delete.ts +++ b/src/commands/slash/Main/hub/delete.ts @@ -67,7 +67,7 @@ export default class Delete extends Hub { } @RegisterInteractionHandler('hub_delete') - async handleComponents(interaction: ButtonInteraction) { + static override async handleComponents(interaction: ButtonInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const userId = customId.args[0]; const hubId = customId.args[1]; @@ -98,7 +98,7 @@ export default class Delete extends Hub { where: { id: hubId, ownerId: interaction.user.id }, }); if (!hubInDb) { - return await interaction.editReply({ + await interaction.editReply({ embeds: [ simpleEmbed( t( @@ -108,6 +108,7 @@ export default class Delete extends Hub { ), ], }); + return; } await deleteHubs([hubInDb.id]); diff --git a/src/commands/slash/Main/hub/joined.ts b/src/commands/slash/Main/hub/joined.ts index 3a07e7dd1..e6fea6ed7 100644 --- a/src/commands/slash/Main/hub/joined.ts +++ b/src/commands/slash/Main/hub/joined.ts @@ -12,6 +12,7 @@ export default class Joined extends Hub { where: { serverId: interaction.guild?.id }, include: { hub: true }, }); + if (connections.length === 0) { return await interaction.reply({ embeds: [ diff --git a/src/commands/slash/Main/hub/leave.ts b/src/commands/slash/Main/hub/leave.ts index 636555731..4b0ad4186 100644 --- a/src/commands/slash/Main/hub/leave.ts +++ b/src/commands/slash/Main/hub/leave.ts @@ -82,7 +82,7 @@ export default class Leave extends Hub { } @RegisterInteractionHandler('hub_leave') - async handleComponents(interaction: MessageComponentInteraction) { + static override async handleComponents(interaction: MessageComponentInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const channelId = customId.args[0]; const { locale } = interaction.user; diff --git a/src/commands/slash/Main/hub/manage.ts b/src/commands/slash/Main/hub/manage.ts index dde3c7746..25777b001 100644 --- a/src/commands/slash/Main/hub/manage.ts +++ b/src/commands/slash/Main/hub/manage.ts @@ -97,7 +97,7 @@ export default class Manage extends Hub { } @RegisterInteractionHandler('hub_manage') - async handleComponents(interaction: MessageComponentInteraction) { + static override async handleComponents(interaction: MessageComponentInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const locale = interaction.user.locale; @@ -356,7 +356,7 @@ export default class Manage extends Hub { // TODO: implement BlockNSFW, only allow hubs that are explicitly marked as NSFW to have this setting // & only allow network channels to be marked as NSFW if (selected === 'BlockNSFW') { - return interaction.reply({ + interaction.reply({ embeds: [ simpleEmbed( `${emojis.no} This setting cannot be changed yet. Please wait for the next update.`, @@ -364,6 +364,7 @@ export default class Manage extends Hub { ], ephemeral: true, }); + return; } const hubSettings = new HubSettingsBitField(hubInDb.settings); diff --git a/src/commands/slash/Staff/find/server.ts b/src/commands/slash/Staff/find/server.ts index 695ace1bb..b9ba98b82 100644 --- a/src/commands/slash/Staff/find/server.ts +++ b/src/commands/slash/Staff/find/server.ts @@ -62,7 +62,7 @@ export default class Server extends Find { name: 'Server Features:', value: guild.features - .map((feat) => '> ' + toTitleCase(feat.replaceAll('_', ' ')) + '\n') + .map((feat) => `> ${toTitleCase(feat.replaceAll('_', ' '))}\n`) .join('') || `> ${emojis.no} No Features Enabled`, }, diff --git a/src/commands/slash/Support/support/report.ts b/src/commands/slash/Support/support/report.ts index b8b2507c7..e937503a9 100644 --- a/src/commands/slash/Support/support/report.ts +++ b/src/commands/slash/Support/support/report.ts @@ -95,7 +95,7 @@ export default class Report extends Support { } @RegisterInteractionHandler('report') - async handleComponents(interaction: MessageComponentInteraction) { + static override async handleComponents(interaction: MessageComponentInteraction) { if (interaction.isStringSelectMenu()) { const modal = new ModalBuilder() .setCustomId( diff --git a/src/core/BaseCommand.ts b/src/core/BaseCommand.ts index 102b7f02b..4cfeef65e 100644 --- a/src/core/BaseCommand.ts +++ b/src/core/BaseCommand.ts @@ -28,8 +28,8 @@ export default abstract class BaseCommand { abstract execute(interaction: CmdInteraction): Promise; // optional methods - async handleComponents?(interaction: MessageComponentInteraction): Promise; - async handleModals?(interaction: ModalSubmitInteraction): Promise; + static async handleComponents?(interaction: MessageComponentInteraction): Promise; + static async handleModals?(interaction: ModalSubmitInteraction): Promise; async autocomplete?(interaction: AutocompleteInteraction): Promise; async checkAndSetCooldown(interaction: RepliableInteraction): Promise { @@ -60,7 +60,7 @@ export default abstract class BaseCommand { } getRemainingCooldown(interaction: RepliableInteraction): number { - let remainingCooldown: number | undefined = undefined; + let remainingCooldown: number | undefined; if (interaction.isChatInputCommand()) { const subcommand = interaction.options.getSubcommand(false); diff --git a/src/managers/BlacklistManager.ts b/src/managers/BlacklistManager.ts index 2e10ae5a0..92e454bc2 100644 --- a/src/managers/BlacklistManager.ts +++ b/src/managers/BlacklistManager.ts @@ -109,7 +109,7 @@ export default class BlacklistManager { const hub = await db.hubs.findUnique({ where: { id: hubId } }); const expireString = expires ? `` : 'Never'; const embed = new EmbedBuilder() - .setTitle(emojis.blobFastBan + ' Blacklist Notification') + .setTitle(`${emojis.blobFastBan} Blacklist Notification`) .setColor(colors.interchatBlue) .setFields( { name: 'Reason', value: reason, inline: true }, diff --git a/src/managers/EventManager.ts b/src/managers/EventManager.ts index 7560331e8..a555b6665 100644 --- a/src/managers/EventManager.ts +++ b/src/managers/EventManager.ts @@ -113,9 +113,9 @@ export default abstract class EventManager { if (!channel.isTextBased()) return; try { - const connection = await db.connectedList.findFirst({ - where: { OR: [{ channelId: channel.id }, { parentId: channel.id }], connected: true }, - }); + const connection = channel.client.connectionCache.find( + (c) => c.connected && (c.channelId === channel.id || c.parentId === channel.id), + ); if (!connection) return; diff --git a/src/scripts/network/helpers.ts b/src/scripts/network/helpers.ts index e0e37bf01..7e06e9ae4 100644 --- a/src/scripts/network/helpers.ts +++ b/src/scripts/network/helpers.ts @@ -27,7 +27,7 @@ export const getReferredContent = (referredMessage: Message) => { referredContent = '*Original message contains attachment <:attachment:1102464803647275028>*'; } else if (referredContent.length > 100) { - referredContent = referredContent.slice(0, 100) + '...'; + referredContent = `${referredContent.slice(0, 100)}...`; } return referredContent; diff --git a/src/services/HubLoggerService.ts b/src/services/HubLoggerService.ts index afa8834ac..e84c5f128 100644 --- a/src/services/HubLoggerService.ts +++ b/src/services/HubLoggerService.ts @@ -31,7 +31,7 @@ export type LogReportOpts = { }; export default class HubLoggerService extends Factory { - public async fetchHub(id: string) { + public static async fetchHub(id: string) { return await db.hubs.findFirst({ where: { id } }); } @@ -42,20 +42,20 @@ export default class HubLoggerService extends Factory { ) { if (type === 'reports') { await SuperClient.instance.reportLogger.setChannelId(hubId, channelId); - return; } - - return await db.hubs.update({ - where: { id: hubId }, - data: { - logChannels: { - upsert: { - set: { [type]: channelId }, - update: { [type]: channelId }, + else { + await db.hubs.update({ + where: { id: hubId }, + data: { + logChannels: { + upsert: { + set: { [type]: channelId }, + update: { [type]: channelId }, + }, }, }, - }, - }); + }); + } } /** @@ -95,7 +95,7 @@ export class ModLogsLogger extends HubLoggerService { ) { const { userOrServer, mod, reason, expires } = opts; - const hub = await this.fetchHub(hubId); + const hub = await HubLoggerService.fetchHub(hubId); if (!hub?.logChannels?.modLogs) return; const name = userOrServer instanceof User ? userOrServer.username : userOrServer.name; @@ -135,12 +135,12 @@ export class ModLogsLogger extends HubLoggerService { mod: User, reason?: string, ) { - const hub = await this.fetchHub(hubId); + const hub = await HubLoggerService.fetchHub(hubId); if (!hub?.logChannels?.modLogs) return; let name: string | undefined; let blacklisted; - let originalReason: string | undefined = undefined; + let originalReason: string | undefined; if (type === 'user') { blacklisted = await BlacklistManager.fetchUserBlacklist(hub.id, userOrServerId); @@ -184,7 +184,7 @@ export class JoinLeaveLogger extends HubLoggerService { server: Guild, opt?: { totalConnections: number; hubName: string }, ) { - const hub = await this.fetchHub(hubId); + const hub = await HubLoggerService.fetchHub(hubId); if (!hub?.logChannels?.joinLeaves) return; const owner = await server.fetchOwner(); @@ -208,13 +208,14 @@ export class JoinLeaveLogger extends HubLoggerService { } async logServerLeave(hubId: string, server: Guild) { - const hub = await this.fetchHub(hubId); + const hub = await HubLoggerService.fetchHub(hubId); if (!hub?.logChannels?.joinLeaves) return; - const totalConnections = await db.connectedList.count({ - where: { hubId: hub.id, connected: true }, - }); const owner = await server.client.users.fetch(server.ownerId).catch(() => null); + const totalConnections = server.client.connectionCache.reduce( + (total, c) => total + (c.hubId === hub.id && c.connected ? 1 : 0), + 0, + ); const embed = new EmbedBuilder() .setTitle('Server Left') @@ -243,7 +244,7 @@ export class ProfanityLogger extends HubLoggerService { * @param server - The server where the content was posted. */ async log(hubId: string, rawContent: string, author: User, server: Guild) { - const hub = await this.fetchHub(hubId); + const hub = await HubLoggerService.fetchHub(hubId); if (!hub?.logChannels?.profanity) return; const embed = new EmbedBuilder() @@ -273,7 +274,7 @@ export class ReportLogger extends HubLoggerService { * @param evidence - Optional evidence for the report. */ async log(hubId: string, { userId, serverId, reason, reportedBy, evidence }: LogReportOpts) { - const hub = await this.fetchHub(hubId); + const hub = await HubLoggerService.fetchHub(hubId); if (!hub?.logChannels?.reports?.channelId) return; const { channelId: reportsChannelId, roleId: reportsRoleId } = hub.logChannels.reports; @@ -345,29 +346,31 @@ export class ReportLogger extends HubLoggerService { return networkChannel && reportsServerMsg ? messageLink(networkChannel.channelId, reportsServerMsg.messageId, networkChannel.serverId) - : undefined; + : null; } } + // skipcq: JS-0105 + async updateChannels( + hubId: string, + logChannels: + | Prisma.HubLogChannelsCreateInput + | Prisma.HubLogChannelsNullableUpdateEnvelopeInput, + ) { + await db.hubs.update({ where: { id: hubId }, data: { logChannels } }); + } + public async removeReports(hubId: string) { - await db.hubs.update({ - where: { id: hubId }, - data: { logChannels: { upsert: { set: null, update: { reports: null } } } }, - }); + await this.updateChannels(hubId, { upsert: { set: null, update: { reports: null } } }); } public async setChannelId(hubId: string, channelId: string) { const data = { channelId }; - await db.hubs.update({ - where: { id: hubId }, - data: { - logChannels: { - upsert: { - set: { reports: data }, - update: { reports: { upsert: { set: data, update: data } } }, - }, - }, + await this.updateChannels(hubId, { + upsert: { + set: { reports: data }, + update: { reports: { upsert: { set: data, update: data } } }, }, }); } @@ -377,20 +380,14 @@ export class ReportLogger extends HubLoggerService { throw new Error('Channel ID not found. Role ID cannot be set.'); } - const logChannels = { ...hub.logChannels, reports: { ...hub.logChannels.reports, roleId } }; - - await db.hubs.update({ - where: { id: hub.id }, - data: { logChannels }, + await this.updateChannels(hub.id, { + ...hub.logChannels, + reports: { ...hub.logChannels.reports, roleId }, }); } public async setChannelIdAndRoleId(hubId: string, channelId: string, roleId: string) { const data = { reports: { channelId, roleId } }; - - await db.hubs.update({ - where: { id: hubId }, - data: { logChannels: { upsert: { set: data, update: data } } }, - }); + await this.updateChannels(hubId, { upsert: { set: data, update: data } }); } } diff --git a/src/utils/CustomID.ts b/src/utils/CustomID.ts index 0acbfab50..16aa33a6d 100644 --- a/src/utils/CustomID.ts +++ b/src/utils/CustomID.ts @@ -1,6 +1,6 @@ import lz from 'lz-string'; -interface ParsedCustomId { +export interface ParsedCustomId { prefix: string; suffix: string; expiry?: number; diff --git a/src/utils/RegisterCmdCli.ts b/src/utils/RegisterCmdCli.ts index fde747ddf..940c8e290 100644 --- a/src/utils/RegisterCmdCli.ts +++ b/src/utils/RegisterCmdCli.ts @@ -45,6 +45,8 @@ process.argv.forEach(async (arg) => { case '--help': Logger.info('Usage: node utils/RegisterCmdCli.js [--public|--private|--help]'); break; + default: + break; } } catch (error) {