diff --git a/src/commands/context-menu/blacklist.ts b/src/commands/context-menu/blacklist.ts index 0190bb072..aa316c6f6 100644 --- a/src/commands/context-menu/blacklist.ts +++ b/src/commands/context-menu/blacklist.ts @@ -20,7 +20,7 @@ import { t } from '../../utils/Locale.js'; import { colors, emojis } from '../../utils/Constants.js'; import { CustomID } from '../../utils/CustomID.js'; import { RegisterInteractionHandler } from '../../decorators/Interaction.js'; -import { checkIfStaff, simpleEmbed } from '../../utils/Utils.js'; +import { checkIfStaff, getUserLocale, simpleEmbed } from '../../utils/Utils.js'; import { stripIndents } from 'common-tags'; import { logBlacklist } from '../../utils/HubLogger/ModLogs.js'; import { deleteConnections } from '../../utils/ConnectedList.js'; @@ -34,7 +34,7 @@ export default class Blacklist extends BaseCommand { }; async execute(interaction: MessageContextMenuCommandInteraction) { - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const messageInDb = await db.broadcastedMessages.findFirst({ where: { messageId: interaction.targetId }, @@ -108,17 +108,11 @@ export default class Blacklist extends BaseCommand { @RegisterInteractionHandler('blacklist') static override async handleComponents(interaction: MessageComponentInteraction): Promise { const customId = CustomID.parseCustomId(interaction.customId); + const locale = await getUserLocale(interaction.user.id); if (interaction.user.id !== customId.args[0]) { await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'errors.notYourAction', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], + embeds: [simpleEmbed(t({ phrase: 'errors.notYourAction', locale }, { emoji: emojis.no }))], ephemeral: true, }); return; @@ -137,27 +131,16 @@ export default class Blacklist extends BaseCommand { new ActionRowBuilder().addComponents( new TextInputBuilder() .setCustomId('reason') - .setLabel( - t({ phrase: 'blacklist.modal.reason.label', locale: interaction.user.locale }), - ) - .setPlaceholder( - t({ phrase: 'blacklist.modal.reason.placeholder', locale: interaction.user.locale }), - ) + .setLabel(t({ phrase: 'blacklist.modal.reason.label', locale })) + .setPlaceholder(t({ phrase: 'blacklist.modal.reason.placeholder', locale })) .setStyle(TextInputStyle.Paragraph) .setMaxLength(500), ), new ActionRowBuilder().addComponents( new TextInputBuilder() .setCustomId('duration') - .setLabel( - t({ phrase: 'blacklist.modal.duration.label', locale: interaction.user.locale }), - ) - .setPlaceholder( - t({ - phrase: 'blacklist.modal.duration.placeholder', - locale: interaction.user.locale, - }), - ) + .setLabel(t({ phrase: 'blacklist.modal.duration.label', locale })) + .setPlaceholder(t({ phrase: 'blacklist.modal.duration.placeholder', locale })) .setStyle(TextInputStyle.Short) .setMinLength(2) .setRequired(false), @@ -171,7 +154,7 @@ export default class Blacklist extends BaseCommand { async handleModals(interaction: ModalSubmitInteraction): Promise { await interaction.deferUpdate(); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const customId = CustomID.parseCustomId(interaction.customId); const [messageId] = customId.args; const originalMsg = await db.originalMessages.findFirst({ where: { messageId } }); diff --git a/src/commands/context-menu/deleteMsg.ts b/src/commands/context-menu/deleteMsg.ts index 20b7cd5f6..45114215e 100644 --- a/src/commands/context-menu/deleteMsg.ts +++ b/src/commands/context-menu/deleteMsg.ts @@ -5,7 +5,7 @@ import { } from 'discord.js'; import db from '../../utils/Db.js'; import BaseCommand from '../../core/BaseCommand.js'; -import { checkIfStaff } from '../../utils/Utils.js'; +import { checkIfStaff, getUserLocale } from '../../utils/Utils.js'; import { REGEX, emojis } from '../../utils/Constants.js'; import { t } from '../../utils/Locale.js'; import { logMsgDelete } from '../../utils/HubLogger/ModLogs.js'; @@ -41,15 +41,10 @@ export default class DeleteMessage extends BaseCommand { originalMsg = broadcastedMsg?.originalMsg ?? null; } + const locale = await getUserLocale(interaction.user.id); if (!originalMsg?.hub) { await interaction.editReply( - t( - { - phrase: 'errors.unknownNetworkMessage', - locale: interaction.user.locale, - }, - { emoji: emojis.no }, - ), + t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), ); return; } @@ -64,13 +59,7 @@ export default class DeleteMessage extends BaseCommand { if (!isStaffOrHubMod && interaction.user.id !== originalMsg.authorId) { await interaction.editReply( - t( - { - phrase: 'errors.notMessageAuthor', - locale: interaction.user.locale, - }, - { emoji: emojis.no }, - ), + t({ phrase: 'errors.notMessageAuthor', locale }, { emoji: emojis.no }), ); return; } @@ -105,10 +94,7 @@ export default class DeleteMessage extends BaseCommand { await interaction .editReply( t( - { - phrase: 'network.deleteSuccess', - locale: interaction.user.locale, - }, + { phrase: 'network.deleteSuccess', locale }, { emoji: emojis.yes, user: `<@${originalMsg.authorId}>`, diff --git a/src/commands/context-menu/editMsg.ts b/src/commands/context-menu/editMsg.ts index 7a560ae9e..c00e6c1b3 100644 --- a/src/commands/context-menu/editMsg.ts +++ b/src/commands/context-menu/editMsg.ts @@ -19,6 +19,7 @@ import { checkIfStaff, containsInviteLinks, getAttachmentURL, + getUserLocale, replaceLinks, userVotedToday, } from '../../utils/Utils.js'; @@ -41,7 +42,7 @@ export default class EditMessage extends BaseCommand { if (isOnCooldown) return; const target = interaction.targetMessage; - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (!checkIfStaff(interaction.user.id) && !(await userVotedToday(interaction.user.id))) { await interaction.reply({ @@ -107,11 +108,12 @@ export default class EditMessage extends BaseCommand { const customId = CustomID.parseCustomId(interaction.customId); const [messageId] = customId.args; + const locale = await getUserLocale(interaction.user.id); const target = await interaction.channel?.messages.fetch(messageId).catch(() => null); if (!target) { await interaction.editReply( - t({ phrase: 'errors.unknownNetworkMessage' }, { emoji: emojis.no }), + t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), ); return; } @@ -132,10 +134,7 @@ export default class EditMessage extends BaseCommand { if (!originalMsg?.hub) { await interaction.editReply( - t( - { phrase: 'errors.unknownNetworkMessage', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), ); return; } @@ -149,7 +148,7 @@ export default class EditMessage extends BaseCommand { if (hubSettings.has('BlockInvites') && containsInviteLinks(newMessage)) { await interaction.editReply( - t({ phrase: 'errors.inviteLinks', locale: interaction.user.locale }, { emoji: emojis.no }), + t({ phrase: 'errors.inviteLinks', locale }, { emoji: emojis.no }), ); return; } @@ -191,7 +190,7 @@ export default class EditMessage extends BaseCommand { const edited = resultsArray.reduce((acc, cur) => acc + (cur ? 1 : 0), 0).toString(); await interaction.editReply( t( - { phrase: 'network.editSuccess', locale: interaction.user.locale }, + { phrase: 'network.editSuccess', locale }, { edited, total: resultsArray.length.toString(), diff --git a/src/commands/context-menu/messageInfo.ts b/src/commands/context-menu/messageInfo.ts index 269fe6721..1514b38dc 100644 --- a/src/commands/context-menu/messageInfo.ts +++ b/src/commands/context-menu/messageInfo.ts @@ -23,7 +23,7 @@ import { REGEX, colors, emojis } from '../../utils/Constants.js'; import { CustomID } from '../../utils/CustomID.js'; import { RegisterInteractionHandler } from '../../decorators/Interaction.js'; import { supportedLocaleCodes, t } from '../../utils/Locale.js'; -import { simpleEmbed } from '../../utils/Utils.js'; +import { getUserLocale, simpleEmbed } from '../../utils/Utils.js'; import { sendHubReport } from '../../utils/HubLogger/Report.js'; import { getAllConnections } from '../../utils/ConnectedList.js'; @@ -38,6 +38,7 @@ export default class MessageInfo extends BaseCommand { await interaction.deferReply({ ephemeral: true }); const target = interaction.targetMessage; + const locale = await getUserLocale(interaction.user.id); const originalMsg = ( await db.broadcastedMessages.findFirst({ where: { messageId: target.id }, @@ -47,10 +48,7 @@ export default class MessageInfo extends BaseCommand { if (!originalMsg) { await interaction.followUp({ - content: t( - { phrase: 'errors.unknownNetworkMessage', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -61,7 +59,7 @@ export default class MessageInfo extends BaseCommand { const embed = new EmbedBuilder() .setDescription( t( - { phrase: 'msgInfo.message.description', locale: interaction.user.locale }, + { phrase: 'msgInfo.message.description', locale }, { emoji: emojis.clipart, author: author.discriminator !== '0' ? author.tag : author.username, @@ -75,7 +73,7 @@ export default class MessageInfo extends BaseCommand { .setThumbnail(`https://cdn.discordapp.com/icons/${server?.id}/${server?.icon}.png`) .setColor('Random'); - const components = MessageInfo.buildButtons(target.id, interaction.user.locale); + const components = MessageInfo.buildButtons(target.id, locale); const guildConnected = (await getAllConnections())?.find( (c) => c.serverId === originalMsg.serverId && c.hubId === originalMsg.hub?.id, @@ -111,12 +109,11 @@ export default class MessageInfo extends BaseCommand { }) )?.originalMsg; + const locale = await getUserLocale(interaction.user.id); + if (!originalMsg) { await interaction.update({ - content: t( - { phrase: 'errors.unknownNetworkMessage', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), embeds: [], components: [], }); @@ -149,10 +146,7 @@ export default class MessageInfo extends BaseCommand { case 'serverInfo': { if (!server) { await interaction.update({ - content: t( - { phrase: 'errors.unknownServer', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.unknownServer', locale }, { emoji: emojis.no }), embeds: [], components: [], }); @@ -176,12 +170,10 @@ export default class MessageInfo extends BaseCommand { .setImage(bannerUrL) .setDescription( t( - { phrase: 'msgInfo.server.description', locale: interaction.user.locale }, + { phrase: 'msgInfo.server.description', locale }, { server: server.name, - description: - server.description || - t({ phrase: 'misc.noDesc', locale: interaction.user.locale }), + description: server.description || t({ phrase: 'misc.noDesc', locale }), owner: `${owner.username}#${ owner.discriminator !== '0' ? `#${owner.discriminator}` : '' }`, @@ -212,7 +204,7 @@ export default class MessageInfo extends BaseCommand { .setImage(author.bannerURL() ?? null) .setDescription( t( - { phrase: 'msgInfo.user.description', locale: interaction.user.locale }, + { phrase: 'msgInfo.user.description', locale }, { username: author.discriminator !== '0' ? author.tag : author.username, id: author.id, @@ -242,10 +234,7 @@ export default class MessageInfo extends BaseCommand { if (!message) { await interaction.update({ - content: t( - { phrase: 'errors.unknownNetworkMessage', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), embeds: [], components: [], }); @@ -255,7 +244,7 @@ export default class MessageInfo extends BaseCommand { const embed = new EmbedBuilder() .setDescription( t( - { phrase: 'msgInfo.message.description', locale: interaction.user.locale }, + { phrase: 'msgInfo.message.description', locale }, { emoji: emojis.clipart, author: author.discriminator !== '0' ? author.tag : author.username, @@ -284,10 +273,7 @@ export default class MessageInfo extends BaseCommand { await interaction.reply({ embeds: [ simpleEmbed( - t( - { phrase: 'msgInfo.report.notEnabled', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + t({ phrase: 'msgInfo.report.notEnabled', locale }, { emoji: emojis.no }), ), ], ephemeral: true, @@ -327,16 +313,12 @@ export default class MessageInfo extends BaseCommand { where: { messageId }, include: { originalMsg: { include: { hub: true } } }, }); + const locale = await getUserLocale(interaction.user.id); if (!messageInDb?.originalMsg.hub?.logChannels?.reports) { await interaction.reply({ embeds: [ - simpleEmbed( - t( - { phrase: 'msgInfo.report.notEnabled', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), + simpleEmbed(t({ phrase: 'msgInfo.report.notEnabled', locale }, { emoji: emojis.no })), ], ephemeral: true, }); @@ -364,14 +346,7 @@ export default class MessageInfo extends BaseCommand { }); await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'msgInfo.report.success', locale: interaction.user.locale }, - { emoji: emojis.yes }, - ), - ), - ], + embeds: [simpleEmbed(t({ phrase: 'msgInfo.report.success', locale }, { emoji: emojis.yes }))], ephemeral: true, }); } diff --git a/src/commands/context-menu/translate.ts b/src/commands/context-menu/translate.ts index b07b1fb95..0b5e5b01b 100644 --- a/src/commands/context-menu/translate.ts +++ b/src/commands/context-menu/translate.ts @@ -15,7 +15,7 @@ import { } from 'discord.js'; import db from '../../utils/Db.js'; import BaseCommand from '../../core/BaseCommand.js'; -import { userVotedToday } from '../../utils/Utils.js'; +import { getUserLocale, userVotedToday } from '../../utils/Utils.js'; import { RegisterInteractionHandler } from '../../decorators/Interaction.js'; import { CustomID } from '../../utils/CustomID.js'; import { t } from '../../utils/Locale.js'; @@ -32,11 +32,10 @@ export default class Translate extends BaseCommand { async execute(interaction: MessageContextMenuCommandInteraction): Promise { await interaction.deferReply({ ephemeral: true }); + const locale = await getUserLocale(interaction.user.id); if (!(await userVotedToday(interaction.user.id))) { - await interaction.editReply( - t({ phrase: 'errors.mustVote', locale: interaction.user.locale }, { emoji: emojis.no }), - ); + await interaction.editReply(t({ phrase: 'errors.mustVote', locale }, { emoji: emojis.no })); return; } @@ -51,10 +50,7 @@ export default class Translate extends BaseCommand { if (!originalMsg) { await interaction.editReply( - t( - { phrase: 'errors.unknownNetworkMessage', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + t({ phrase: 'errors.unknownNetworkMessage', locale }, { emoji: emojis.no }), ); return; } @@ -65,7 +61,7 @@ export default class Translate extends BaseCommand { return; } - const translatedMessage = await translate(messageContent, { to: interaction.user.locale }); + const translatedMessage = await translate(messageContent, { to: locale }); const embed = new EmbedBuilder() .setDescription('### Translation Results') .setColor('Green') @@ -136,14 +132,12 @@ export default class Translate extends BaseCommand { return; } + const locale = await getUserLocale(interaction.user.id); const to = interaction.fields.getTextInputValue('to'); const from = interaction.fields.getTextInputValue('from'); if (!isSupported(from) || !isSupported(to)) { await interaction.reply({ - content: t( - { phrase: 'errors.invalidLangCode', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.invalidLangCode', locale }, { emoji: emojis.no }), ephemeral: true, }); return; diff --git a/src/commands/slash/Information/about.ts b/src/commands/slash/Information/about.ts index 03a85ec04..4e2f4bb6b 100644 --- a/src/commands/slash/Information/about.ts +++ b/src/commands/slash/Information/about.ts @@ -4,30 +4,17 @@ import { ButtonBuilder, ButtonStyle, Client, - RESTPostAPIChatInputApplicationCommandsJSONBody, } from 'discord.js'; import { badgeEmojis, emojis, LINKS } from '../../../utils/Constants.js'; import { getCredits, simpleEmbed } from '../../../utils/Utils.js'; import { stripIndents } from 'common-tags'; -import BaseCommand from '../../../core/BaseCommand.js'; +import BaseCommand, { CommandBody } from '../../../core/BaseCommand.js'; export default class About extends BaseCommand { - readonly data: RESTPostAPIChatInputApplicationCommandsJSONBody = { + public readonly data: CommandBody = { name: 'about', description: 'Learn more about the InterChat team and project.', }; - - private async getUsernames(client: Client): Promise { - const members: string[] = []; - - for (const credit of getCredits()) { - const member = await client.users.fetch(credit); - members.push(member.username.replaceAll('_', '\\_')); - } - - return members; - } - async execute(interaction: ChatInputCommandInteraction) { await interaction.deferReply(); @@ -38,10 +25,10 @@ export default class About extends BaseCommand { const creditsEmbed = simpleEmbed( stripIndents` ## ${emojis.wand} The Team - InterChat is a project driven by a passionate team dedicated to enhancing the Discord experience. We welcome new members to join our team; if you're interested, please join our [support server](${LINKS.SUPPORT_INVITE}). + InterChat is a project driven by a passionate team dedicated to enhancing the Discord experience. We welcome new members to join our team; if you're interested, please join our [support server](${LINKS.SUPPORT_INVITE}). ${creditsDivider} - ✨ **Design:** + ✨ **Design:** ${emojis.dotBlue} @${usernames[6]} (Mascot) ${badgeEmojis.Developer} **Developers:** @@ -55,7 +42,7 @@ export default class About extends BaseCommand { ${emojis.dotBlue} @${usernames[5]} ${linksDivider} - [Guide](${LINKS.DOCS}) • [Invite](https://discord.com/application-directory/769921109209907241) • [Support Server](${LINKS.SUPPORT_INVITE}) • [Vote](https://top.gg/bot/769921109209907241/vote) • [Privacy](${LINKS.DOCS}/legal/privacy) • [Terms](${LINKS.DOCS}/legal/terms) + [Guide](${LINKS.DOCS}) • [Invite](https://discord.com/application-directory/769921109209907241) • [Support Server](${LINKS.SUPPORT_INVITE}) • [Vote](https://top.gg/bot/769921109209907241/vote) • [Privacy](${LINKS.DOCS}/legal/privacy) • [Terms](${LINKS.DOCS}/legal/terms) `, ); @@ -85,4 +72,14 @@ export default class About extends BaseCommand { await interaction.editReply({ embeds: [creditsEmbed], components: [linkButtons] }); } + private async getUsernames(client: Client): Promise { + const members: string[] = []; + + for (const credit of getCredits()) { + const member = await client.users.fetch(credit); + members.push(member.username.replaceAll('_', '\\_')); + } + + return members; + } } diff --git a/src/commands/slash/Information/invite.ts b/src/commands/slash/Information/invite.ts index 209101586..4343c4f9d 100644 --- a/src/commands/slash/Information/invite.ts +++ b/src/commands/slash/Information/invite.ts @@ -2,6 +2,7 @@ import { ChatInputCommandInteraction } from 'discord.js'; import BaseCommand from '../../../core/BaseCommand.js'; import { LINKS, emojis } from '../../../utils/Constants.js'; import { t } from '../../../utils/Locale.js'; +import { getUserLocale } from '#main/utils/Utils.js'; export default class Invite extends BaseCommand { readonly data = { @@ -9,9 +10,10 @@ export default class Invite extends BaseCommand { description: 'Invite me to your server!', }; async execute(interaction: ChatInputCommandInteraction) { + const locale = await getUserLocale(interaction.user.id); await interaction.reply({ content: t( - { phrase: 'invite', locale: interaction.user.locale }, + { phrase: 'invite', locale }, { support: LINKS.SUPPORT_INVITE, invite: LINKS.APP_DIRECTORY, diff --git a/src/commands/slash/Information/rules.ts b/src/commands/slash/Information/rules.ts index 8da6c94d9..940fdaa47 100644 --- a/src/commands/slash/Information/rules.ts +++ b/src/commands/slash/Information/rules.ts @@ -2,19 +2,16 @@ import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js'; import BaseCommand from '../../../core/BaseCommand.js'; import { LINKS, colors } from '../../../utils/Constants.js'; import { t } from '../../../utils/Locale.js'; +import { getUserLocale } from '#main/utils/Utils.js'; export default class Rules extends BaseCommand { readonly data = { name: 'rules', description: 'Sends the network rules for InterChat.', }; async execute(interaction: ChatInputCommandInteraction) { + const locale = await getUserLocale(interaction.user.id); const rulesEmbed = new EmbedBuilder() - .setDescription( - t( - { phrase: 'rules', locale: interaction.user.locale }, - { support_invite: LINKS.SUPPORT_INVITE }, - ), - ) + .setDescription(t({ phrase: 'rules', locale }, { support_invite: LINKS.SUPPORT_INVITE })) .setImage(LINKS.RULES_BANNER) .setColor(colors.interchatBlue); diff --git a/src/commands/slash/Information/vote.ts b/src/commands/slash/Information/vote.ts index 8f02f4ecc..2c97819f8 100644 --- a/src/commands/slash/Information/vote.ts +++ b/src/commands/slash/Information/vote.ts @@ -8,7 +8,7 @@ import { import BaseCommand from '#main/core/BaseCommand.js'; import { colors, emojis } from '#main/utils/Constants.js'; import { t } from '#main/utils/Locale.js'; -import { getDbUser } from '#main/utils/Utils.js'; +import { getDbUser, getUserLocale } from '#main/utils/Utils.js'; export default class Vote extends BaseCommand { readonly data = { @@ -16,9 +16,10 @@ export default class Vote extends BaseCommand { description: 'Voting perks and vote link.', }; async execute(interaction: ChatInputCommandInteraction) { - const { locale, id } = interaction.user; + const { id } = interaction.user; const userData = await getDbUser(id); const voteCount = String(userData?.voteCount ?? 0); + const locale = await getUserLocale(interaction.user.id); const embed = new EmbedBuilder() .setDescription(t({ phrase: 'vote.description', locale })) diff --git a/src/commands/slash/Main/blacklist/index.ts b/src/commands/slash/Main/blacklist/index.ts index 8b82b797f..5c58fec03 100644 --- a/src/commands/slash/Main/blacklist/index.ts +++ b/src/commands/slash/Main/blacklist/index.ts @@ -1,5 +1,5 @@ import { emojis } from '#main/utils/Constants.js'; -import { t } from '#main/utils/Locale.js'; +import { supportedLocaleCodes, t } from '#main/utils/Locale.js'; import { hubs as hubsT } from '@prisma/client'; import { type AutocompleteInteraction, @@ -213,17 +213,17 @@ export default class BlacklistCommand extends BaseCommand { } protected async getHub({ name, userId }: { name: string | null; userId: Snowflake }) { - if (name) { - return await db.hubs.findFirst({ where: { name } }); - } - else { - const allHubs = await db.hubs.findMany({ - where: { OR: [{ ownerId: userId }, { moderators: { some: { userId } } }] }, - }); - if (allHubs.length > 1) return 'exceeds max length'; - // assign first value of the hub query - return allHubs[0]; - } + const allHubs = await db.hubs.findMany({ + where: { + name: name ?? undefined, + OR: [{ ownerId: userId }, { moderators: { some: { userId } } }], + }, + }); + + if (allHubs.length > 1) return 'exceeds max length'; + + // assign first value of the hub query + return allHubs[0]; } protected async sendSuccessResponse( @@ -252,8 +252,8 @@ export default class BlacklistCommand extends BaseCommand { protected isValidHub( interaction: ChatInputCommandInteraction, hub: hubsT | string | null, + locale: supportedLocaleCodes = 'en', ): hub is hubsT { - const { locale } = interaction.user; const hiddenOpt = { ephemeral: true }; if (!hub) { this.replyEmbed(interaction, t({ phrase: 'hub.notFound_mod', locale }), hiddenOpt); @@ -267,6 +267,7 @@ export default class BlacklistCommand extends BaseCommand { ); return false; } + return true; } diff --git a/src/commands/slash/Main/blacklist/list.ts b/src/commands/slash/Main/blacklist/list.ts index ea8b68d28..a15613088 100644 --- a/src/commands/slash/Main/blacklist/list.ts +++ b/src/commands/slash/Main/blacklist/list.ts @@ -3,7 +3,7 @@ import BlacklistCommand from './index.js'; import { colors, emojis } from '#main/utils/Constants.js'; import { supportedLocaleCodes, t } from '#main/utils/Locale.js'; import { paginate } from '#main/utils/Pagination.js'; -import { toTitleCase } from '#main/utils/Utils.js'; +import { getUserLocale, toTitleCase } from '#main/utils/Utils.js'; import { blacklistedServers, hubBlacklist, userData } from '@prisma/client'; import { ChatInputCommandInteraction, EmbedBuilder, User, time } from 'discord.js'; @@ -24,10 +24,11 @@ export default class ListBlacklists extends BlacklistCommand { ], }, }); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (!hubInDb) { - await this.replyEmbed(interaction, t( - { phrase: 'hub.notFound_mod', locale }, { emoji: emojis.no }), + await this.replyEmbed( + interaction, + t({ phrase: 'hub.notFound_mod', locale }, { emoji: emojis.no }), ); return; } @@ -54,6 +55,7 @@ export default class ListBlacklists extends BlacklistCommand { const fields = []; let counter = 0; const type = isUserType(list[0]) ? 'user' : 'server'; + const locale = await getUserLocale(interaction.user.id); for (const data of list) { const hubData = data.blacklistedFrom.find((d) => d.hubId === hubId); @@ -61,9 +63,7 @@ export default class ListBlacklists extends BlacklistCommand { ? await interaction.client.users.fetch(hubData.moderatorId).catch(() => null) : null; - fields.push( - this.createFieldData(data, type, { hubData, moderator, locale: interaction.user.locale }), - ); + fields.push(this.createFieldData(data, type, { hubData, moderator, locale })); counter++; if (counter >= opts.LIMIT || fields.length === list.length) { diff --git a/src/commands/slash/Main/blacklist/server.ts b/src/commands/slash/Main/blacklist/server.ts index 6eb75ac0d..c2f6f64f9 100644 --- a/src/commands/slash/Main/blacklist/server.ts +++ b/src/commands/slash/Main/blacklist/server.ts @@ -5,16 +5,18 @@ import { emojis } from '#main/utils/Constants.js'; import { logBlacklist, logServerUnblacklist } from '#main/utils/HubLogger/ModLogs.js'; import { t } from '#main/utils/Locale.js'; import BlacklistCommand from './index.js'; +import { getUserLocale } from '#main/utils/Utils.js'; export default class extends BlacklistCommand { async execute(interaction: ChatInputCommandInteraction) { await interaction.deferReply(); - const { locale, id: moderatorId } = interaction.user; + const { id: moderatorId } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const hubName = interaction.options.getString('hub'); const hub = await this.getHub({ name: hubName, userId: moderatorId }); - if (!this.isValidHub(interaction, hub)) return; + if (!this.isValidHub(interaction, hub, locale)) return; const { serverBlacklists } = interaction.client; const subCommandGroup = interaction.options.getSubcommandGroup(); @@ -67,7 +69,8 @@ export default class extends BlacklistCommand { else if (subCommandGroup === 'remove') { const result = await serverBlacklists.removeBlacklist(hub.id, serverId); if (!result) { - await this.replyEmbed(interaction, + await this.replyEmbed( + interaction, t({ phrase: 'errors.serverNotBlacklisted', locale }, { emoji: emojis.no }), ); return; diff --git a/src/commands/slash/Main/blacklist/user.ts b/src/commands/slash/Main/blacklist/user.ts index ed3d6a414..3e6fe14f7 100644 --- a/src/commands/slash/Main/blacklist/user.ts +++ b/src/commands/slash/Main/blacklist/user.ts @@ -5,15 +5,18 @@ import { logBlacklist } from '#main/utils/HubLogger/ModLogs.js'; import { t } from '#main/utils/Locale.js'; import Logger from '#main/utils/Logger.js'; import BlacklistCommand from './index.js'; +import { getUserLocale } from '#main/utils/Utils.js'; export default class extends BlacklistCommand { async execute(interaction: ChatInputCommandInteraction) { await interaction.deferReply(); - const { locale, id: moderatorId } = interaction.user; + const { id: moderatorId } = interaction.user; + const locale = await getUserLocale(interaction.user.id); + const hubName = interaction.options.getString('hub'); const hub = await this.getHub({ name: hubName, userId: moderatorId }); - if (!this.isValidHub(interaction, hub)) return; + if (!this.isValidHub(interaction, hub, locale)) return; const reason = interaction.options.getString('reason') ?? 'No reason provided.'; const duration = parse(`${interaction.options.getString('duration')}`); @@ -22,7 +25,9 @@ export default class extends BlacklistCommand { if (subcommandGroup === 'add') { const user = interaction.options.getUser('user', true); - const passedChecks = await this.runUserAddChecks(interaction, hub.id, user.id, { duration }); + const passedChecks = await this.runUserAddChecks(interaction, hub.id, user.id, { + duration, + }); if (!passedChecks) return; await this.addUserBlacklist(interaction, user, { expires, hubId: hub.id, reason }); @@ -91,7 +96,7 @@ export default class extends BlacklistCommand { userId: string, opts?: { duration?: number }, ) { - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const hiddenOpt = { ephemeral: true }; if (userId === interaction.client.user?.id) { await this.replyEmbed( diff --git a/src/commands/slash/Main/connection/customize.ts b/src/commands/slash/Main/connection/customize.ts index 67a0a824e..4716cf3d3 100644 --- a/src/commands/slash/Main/connection/customize.ts +++ b/src/commands/slash/Main/connection/customize.ts @@ -1,7 +1,24 @@ +import { RegisterInteractionHandler } from '#main/decorators/Interaction.js'; +import { + buildChannelSelect, + buildCustomizeSelect, + buildEmbed, +} from '#main/scripts/network/buildConnectionAssets.js'; +import { modifyConnection } from '#main/utils/ConnectedList.js'; +import { emojis } from '#main/utils/Constants.js'; +import { CustomID } from '#main/utils/CustomID.js'; +import db from '#main/utils/Db.js'; +import { t } from '#main/utils/Locale.js'; +import { + getOrCreateWebhook, + getUserLocale, + setComponentExpiry, + simpleEmbed, +} from '#main/utils/Utils.js'; import { - ChatInputCommandInteraction, ActionRowBuilder, ChannelSelectMenuInteraction, + ChatInputCommandInteraction, ModalBuilder, ModalSubmitInteraction, StringSelectMenuInteraction, @@ -10,37 +27,19 @@ import { TextInputStyle, ThreadChannel, } from 'discord.js'; -import db from '../../../../utils/Db.js'; -import { - buildChannelSelect, - buildCustomizeSelect, - buildEmbed, -} from '../../../../scripts/network/buildConnectionAssets.js'; import Connection from './index.js'; -import { t } from '../../../../utils/Locale.js'; -import { getOrCreateWebhook, setComponentExpiry, simpleEmbed } from '../../../../utils/Utils.js'; -import { modifyConnection } from '../../../../utils/ConnectedList.js'; -import { emojis } from '../../../../utils/Constants.js'; -import { CustomID } from '../../../../utils/CustomID.js'; -import { RegisterInteractionHandler } from '../../../../decorators/Interaction.js'; export default class Customize extends Connection { async execute(interaction: ChatInputCommandInteraction): Promise { - if (!interaction.deferred && !interaction.replied) await interaction.deferReply(); + 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 } }); + const locale = await getUserLocale(interaction.user.id); if (!isInDb) { await interaction.editReply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'connection.notFound', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], + embeds: [simpleEmbed(t({ phrase: 'connection.notFound', locale }, { emoji: emojis.no }))], }); return; } @@ -50,16 +49,11 @@ export default class Customize extends Connection { if (!channelExists) { await modifyConnection({ channelId }, { connected: !isInDb.connected }); await interaction.followUp({ - content: t( - { phrase: 'connection.channelNotFound', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'connection.channelNotFound', locale }, { emoji: emojis.no }), ephemeral: true, }); } - const { locale } = interaction.user; - const embed = await buildEmbed( channelId, interaction.guild?.iconURL() ?? interaction.user.avatarURL()?.toString(), @@ -83,6 +77,7 @@ export default class Customize extends Connection { @RegisterInteractionHandler('connectionModal') static override async handleModals(interaction: ModalSubmitInteraction): Promise { const customId = CustomID.parseCustomId(interaction.customId); + const locale = await getUserLocale(interaction.user.id); if (customId.suffix === 'invite') { await interaction.deferReply({ ephemeral: true }); @@ -92,10 +87,7 @@ export default class Customize extends Connection { if (!invite) { await modifyConnection({ channelId }, { invite: { unset: true } }); await interaction.followUp({ - content: t( - { phrase: 'connection.inviteRemoved', locale: interaction.user.locale }, - { emoji: emojis.yes }, - ), + content: t({ phrase: 'connection.inviteRemoved', locale }, { emoji: emojis.yes }), ephemeral: true, }); return; @@ -105,10 +97,7 @@ export default class Customize extends Connection { if (isValid?.guild?.id !== interaction.guildId) { await interaction.followUp({ - content: t( - { phrase: 'connection.inviteInvalid', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'connection.inviteInvalid', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -117,10 +106,7 @@ export default class Customize extends Connection { await modifyConnection({ channelId }, { invite }); await interaction.followUp({ - content: t( - { phrase: 'connection.inviteAdded', locale: interaction.user.locale }, - { emoji: emojis.yes }, - ), + content: t({ phrase: 'connection.inviteAdded', locale }, { emoji: emojis.yes }), ephemeral: true, }); } @@ -130,10 +116,7 @@ export default class Customize extends Connection { const hex_regex = /^#[0-9A-F]{6}$/i; if (embedColor && !hex_regex.test(embedColor)) { await interaction.reply({ - content: t( - { phrase: 'connection.emColorInvalid', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'connection.emColorInvalid', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -146,7 +129,7 @@ export default class Customize extends Connection { await interaction.reply({ content: t( - { phrase: 'connection.emColorChange', locale: interaction.user.locale }, + { phrase: 'connection.emColorChange', locale }, { action: embedColor ? `set to \`${embedColor}\`!` : 'unset', emoji: emojis.yes }, ), ephemeral: true, @@ -159,7 +142,7 @@ export default class Customize extends Connection { await buildEmbed( customId.args[0], interaction.guild?.iconURL() ?? interaction.user.avatarURL()?.toString(), - interaction.user.locale, + locale, ), ], }) @@ -173,7 +156,7 @@ export default class Customize extends Connection { const customId = CustomID.parseCustomId(interaction.customId); const channelId = customId.args.at(0); const userIdFilter = customId.args.at(1); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (userIdFilter !== interaction.user.id) { await interaction.reply({ @@ -265,7 +248,7 @@ export default class Customize extends Connection { if (!interaction.isChannelSelectMenu()) return; await interaction.deferUpdate(); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const emoji = emojis.no; const customId = CustomID.parseCustomId(interaction.customId); @@ -315,7 +298,6 @@ export default class Customize extends Connection { { channelId: newChannel.id, webhookURL: newWebhook?.url }, ); - const customizeSelect = buildCustomizeSelect(newChannel.id, interaction.user.id, locale); const channelSelect = buildChannelSelect(newChannel.id, interaction.user.id); diff --git a/src/commands/slash/Main/connection/pause.ts b/src/commands/slash/Main/connection/pause.ts index fa62ab8c3..688466ad8 100644 --- a/src/commands/slash/Main/connection/pause.ts +++ b/src/commands/slash/Main/connection/pause.ts @@ -1,20 +1,20 @@ +import { modifyConnection } from '#main/utils/ConnectedList.js'; +import { emojis } from '#main/utils/Constants.js'; +import db from '#main/utils/Db.js'; +import { t } from '#main/utils/Locale.js'; +import { fetchCommands, findCommand, getUserLocale, simpleEmbed } from '#main/utils/Utils.js'; import { ChatInputCommandInteraction, channelMention, chatInputApplicationCommandMention as slashCmdMention, } from 'discord.js'; import Connection from './index.js'; -import { fetchCommands, findCommand, simpleEmbed } from '../../../../utils/Utils.js'; -import { emojis } from '../../../../utils/Constants.js'; -import { t } from '../../../../utils/Locale.js'; -import { modifyConnection } from '../../../../utils/ConnectedList.js'; -import db from '../../../../utils/Db.js'; export default class Pause extends Connection { override async execute(interaction: ChatInputCommandInteraction): Promise { const channelId = interaction.options.getString('channel', true); const connected = await db.connectedList.findFirst({ where: { channelId } }); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (!connected) { await interaction.reply({ diff --git a/src/commands/slash/Main/connection/unpause.ts b/src/commands/slash/Main/connection/unpause.ts index 7538c8069..f5af8a4ab 100644 --- a/src/commands/slash/Main/connection/unpause.ts +++ b/src/commands/slash/Main/connection/unpause.ts @@ -9,18 +9,19 @@ import { fetchCommands, findCommand, getOrCreateWebhook, + getUserLocale, simpleEmbed, -} from '../../../../utils/Utils.js'; -import { emojis } from '../../../../utils/Constants.js'; -import { t } from '../../../../utils/Locale.js'; -import { modifyConnection } from '../../../../utils/ConnectedList.js'; -import db from '../../../../utils/Db.js'; +} from '#main/utils/Utils.js'; +import { emojis } from '#main/utils/Constants.js'; +import { t } from '#main/utils/Locale.js'; +import { modifyConnection } from '#main/utils/ConnectedList.js'; +import db from '#main/utils/Db.js'; export default class Unpause extends Connection { override async execute(interaction: ChatInputCommandInteraction): Promise { const channelId = interaction.options.getString('channel', true); const connected = await db.connectedList.findFirst({ where: { channelId } }); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (!connected) { await interaction.reply({ diff --git a/src/commands/slash/Main/hub/browse.ts b/src/commands/slash/Main/hub/browse.ts index 0600c5295..42643a339 100644 --- a/src/commands/slash/Main/hub/browse.ts +++ b/src/commands/slash/Main/hub/browse.ts @@ -1,39 +1,40 @@ /* eslint-disable complexity */ +import { RegisterInteractionHandler } from '#main/decorators/Interaction.js'; +import { showOnboarding } from '#main/scripts/network/onboarding.js'; +import { connectChannel, getAllConnections } from '#main/utils/ConnectedList.js'; +import { colors, emojis } from '#main/utils/Constants.js'; +import { CustomID } from '#main/utils/CustomID.js'; +import db from '#main/utils/Db.js'; +import { logJoinToHub } from '#main/utils/HubLogger/JoinLeave.js'; +import { t } from '#main/utils/Locale.js'; +import { paginate } from '#main/utils/Pagination.js'; +import { + calculateAverageRating, + getOrCreateWebhook, + getUserLocale, + sendToHub, + simpleEmbed, +} from '#main/utils/Utils.js'; +import { hubs } from '@prisma/client'; +import { stripIndents } from 'common-tags'; import { - ChatInputCommandInteraction, - CacheType, ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, + CacheType, ChannelSelectMenuBuilder, + ChannelSelectMenuInteraction, ChannelType, + ChatInputCommandInteraction, EmbedBuilder, ModalBuilder, + ModalSubmitInteraction, TextInputBuilder, TextInputStyle, - ModalSubmitInteraction, - ChannelSelectMenuInteraction, time, } from 'discord.js'; -import db from '../../../../utils/Db.js'; import Hub from './index.js'; -import { hubs } from '@prisma/client'; -import { colors, emojis } from '../../../../utils/Constants.js'; -import { paginate } from '../../../../utils/Pagination.js'; -import { - calculateAverageRating, - getOrCreateWebhook, - sendToHub, - simpleEmbed, -} from '../../../../utils/Utils.js'; -import { showOnboarding } from '../../../../scripts/network/onboarding.js'; -import { CustomID } from '../../../../utils/CustomID.js'; -import { RegisterInteractionHandler } from '../../../../decorators/Interaction.js'; -import { stripIndents } from 'common-tags'; -import { t } from '../../../../utils/Locale.js'; -import { logJoinToHub } from '../../../../utils/HubLogger/JoinLeave.js'; -import { connectChannel, getAllConnections } from '../../../../utils/ConnectedList.js'; export default class Browse extends Hub { async execute(interaction: ChatInputCommandInteraction): Promise { @@ -99,12 +100,11 @@ export default class Browse extends Hub { }), ); + const locale = await getUserLocale(interaction.user.id); + if (!hubList || hubList.length === 0) { await interaction.editReply({ - content: t( - { phrase: 'hub.browse.noHubs', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.browse.noHubs', locale }, { emoji: emojis.no }), }); return; } @@ -152,7 +152,7 @@ export default class Browse extends Hub { interaction: ButtonInteraction | ChannelSelectMenuInteraction, ): Promise { const customId = CustomID.parseCustomId(interaction.customId); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const hubDetails = await db.hubs.findFirst({ where: { id: customId.args[0] }, @@ -425,7 +425,7 @@ export default class Browse extends Hub { @RegisterInteractionHandler('hub_browse_modal') static async handleModals(interaction: ModalSubmitInteraction): Promise { const customId = CustomID.parseCustomId(interaction.customId); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const rating = parseInt(interaction.fields.getTextInputValue('rating')); if (isNaN(rating) || rating < 1 || rating > 5) { diff --git a/src/commands/slash/Main/hub/create.ts b/src/commands/slash/Main/hub/create.ts index 50df3e119..eefacd493 100644 --- a/src/commands/slash/Main/hub/create.ts +++ b/src/commands/slash/Main/hub/create.ts @@ -12,7 +12,7 @@ import Hub from './index.js'; import db from '../../../../utils/Db.js'; import { RegisterInteractionHandler } from '../../../../decorators/Interaction.js'; import { HubSettingsBits } from '../../../../utils/BitFields.js'; -import { checkAndFetchImgurUrl, simpleEmbed } from '../../../../utils/Utils.js'; +import { checkAndFetchImgurUrl, getUserLocale, simpleEmbed } from '../../../../utils/Utils.js'; import { LINKS, REGEX, emojis } from '../../../../utils/Constants.js'; import { t } from '../../../../utils/Locale.js'; import { CustomID } from '../../../../utils/CustomID.js'; @@ -21,11 +21,11 @@ export default class Create extends Hub { readonly cooldown = 10 * 60 * 1000; // 10 mins async execute(interaction: ChatInputCommandInteraction) { - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const isOnCooldown = await this.getRemainingCooldown(interaction); if (isOnCooldown) { - await this.sendCooldownError(interaction, isOnCooldown); + await this.sendCooldownError(interaction, isOnCooldown, locale); return; } @@ -88,14 +88,12 @@ export default class Create extends Hub { const description = interaction.fields.getTextInputValue('description'); const icon = interaction.fields.getTextInputValue('icon'); const banner = interaction.fields.getTextInputValue('banner'); + const locale = await getUserLocale(interaction.user.id); // if hubName contains "discord", "clyde" "```" then return if (REGEX.BANNED_WEBHOOK_WORDS.test(name)) { await interaction.followUp({ - content: t( - { phrase: 'hub.create.invalidName', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.create.invalidName', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -107,10 +105,7 @@ export default class Create extends Hub { if (hubs.find((hub) => hub.name === name)) { await interaction.followUp({ - content: t( - { phrase: 'hub.create.nameTaken', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.create.nameTaken', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -119,10 +114,7 @@ export default class Create extends Hub { hubs.reduce((acc, hub) => (hub.ownerId === interaction.user.id ? acc + 1 : acc), 0) >= 3 ) { await interaction.followUp({ - content: t( - { phrase: 'hub.create.maxHubs', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.create.maxHubs', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -134,14 +126,7 @@ export default class Create extends Hub { // TODO: create a gif showing how to get imgur links if (iconUrl === false || bannerUrl === false) { await interaction.followUp({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.invalidImgurUrl', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], + embeds: [simpleEmbed(t({ phrase: 'hub.invalidImgurUrl', locale }, { emoji: emojis.no }))], ephemeral: true, }); return; @@ -170,7 +155,7 @@ export default class Create extends Hub { .setColor('Green') .setDescription( t( - { phrase: 'hub.create.success', locale: interaction.user.locale }, + { phrase: 'hub.create.success', locale }, { name, support_invite: LINKS.SUPPORT_INVITE, docs_link: LINKS.DOCS }, ), ) diff --git a/src/commands/slash/Main/hub/delete.ts b/src/commands/slash/Main/hub/delete.ts index 815585b68..d1fb33d6b 100644 --- a/src/commands/slash/Main/hub/delete.ts +++ b/src/commands/slash/Main/hub/delete.ts @@ -9,7 +9,12 @@ import { import db from '../../../../utils/Db.js'; import Hub from './index.js'; import { LINKS, emojis } from '../../../../utils/Constants.js'; -import { deleteHubs, simpleEmbed, setComponentExpiry } from '../../../../utils/Utils.js'; +import { + deleteHubs, + simpleEmbed, + setComponentExpiry, + getUserLocale, +} from '../../../../utils/Utils.js'; import { CustomID } from '../../../../utils/CustomID.js'; import { RegisterInteractionHandler } from '../../../../decorators/Interaction.js'; import { t } from '../../../../utils/Locale.js'; @@ -18,22 +23,18 @@ export default class Delete extends Hub { async execute(interaction: ChatInputCommandInteraction): Promise { const hubName = interaction.options.getString('hub', true); const hubInDb = await db.hubs.findFirst({ where: { name: hubName } }); + const locale = await getUserLocale(interaction.user.id); if (interaction.user.id !== hubInDb?.ownerId) { await interaction.reply({ - content: t( - { phrase: 'hub.delete.ownerOnly', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.delete.ownerOnly', locale }, { emoji: emojis.no }), ephemeral: true, }); return; } const confirmEmbed = new EmbedBuilder() - .setDescription( - t({ phrase: 'hub.delete.confirm', locale: interaction.user.locale }, { hub: hubInDb.name }), - ) + .setDescription(t({ phrase: 'hub.delete.confirm', locale }, { hub: hubInDb.name })) .setColor('Red'); const confirmButtons = new ActionRowBuilder().addComponents( new ButtonBuilder() @@ -70,7 +71,7 @@ export default class Delete extends Hub { static override async handleComponents(interaction: ButtonInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const [userId, hubId] = customId.args; - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (interaction.user.id !== userId) { await interaction.reply({ diff --git a/src/commands/slash/Main/hub/invite.ts b/src/commands/slash/Main/hub/invite.ts index 38f9b0f6f..9f008d6df 100644 --- a/src/commands/slash/Main/hub/invite.ts +++ b/src/commands/slash/Main/hub/invite.ts @@ -4,7 +4,7 @@ import { captureException } from '@sentry/node'; import { LINKS, emojis } from '../../../../utils/Constants.js'; import db from '../../../../utils/Db.js'; import Logger from '../../../../utils/Logger.js'; -import { simpleEmbed } from '../../../../utils/Utils.js'; +import { getUserLocale, simpleEmbed } from '../../../../utils/Utils.js'; import { t } from '../../../../utils/Locale.js'; import parse from 'parse-duration'; @@ -13,6 +13,7 @@ export default class Invite extends Hub { async execute(interaction: ChatInputCommandInteraction) { const subcommand = interaction.options.getSubcommand(); + const locale = await getUserLocale(interaction.user.id); switch (subcommand) { case 'create': { @@ -33,17 +34,11 @@ export default class Invite extends Hub { }); if (!hubInDb) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.notFound_mod', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.notFound_mod', locale }, { emoji: emojis.no }), + { ephemeral: true }, + ); return; } @@ -65,7 +60,7 @@ export default class Invite extends Hub { const embed = new EmbedBuilder() .setDescription( t( - { phrase: 'hub.invite.create.success', locale: interaction.user.locale }, + { phrase: 'hub.invite.create.success', locale }, { inviteCode: createdInvite.code, docs_link: LINKS.DOCS, @@ -99,13 +94,7 @@ export default class Invite extends Hub { if (!inviteInDb) { await interaction.reply({ - content: t( - { - phrase: 'hub.invite.revoke.invalidCode', - locale: interaction.user.locale, - }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.invite.revoke.invalidCode', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -113,34 +102,25 @@ export default class Invite extends Hub { try { await db.hubInvites.delete({ where: { code } }); - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.invite.revoke.success', locale: interaction.user.locale }, - { emoji: emojis.yes, inviteCode: code }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t( + { phrase: 'hub.invite.revoke.success', locale }, + { emoji: emojis.yes, inviteCode: code }, + ), + { ephemeral: true }, + ); } catch (e) { Logger.error(e); captureException(e); - await interaction - .reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'errors.unknown', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], + await this.replyEmbed( + interaction, + t({ phrase: 'errors.unknown', locale }, { emoji: emojis.no }), + { ephemeral: true, - }) - .catch(() => null); + }, + ).catch(() => null); return; } break; @@ -159,33 +139,21 @@ export default class Invite extends Hub { }); if (!hubInDb?.private) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.invite.list.notPrivate', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.invite.list.notPrivate', locale }, { emoji: emojis.no }), + { ephemeral: true }, + ); return; } const invitesInDb = await db.hubInvites.findMany({ where: { hubId: hubInDb.id } }); if (invitesInDb.length === 0) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.invite.list.noInvites', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.invite.list.noInvites', locale }, { emoji: emojis.no }), + { ephemeral: true }, + ); return; } @@ -195,7 +163,7 @@ export default class Invite extends Hub { ); const inviteEmbed = new EmbedBuilder() - .setTitle(t({ phrase: 'hub.invite.list.title', locale: interaction.user.locale })) + .setTitle(t({ phrase: 'hub.invite.list.title', locale })) .setDescription(inviteArr.join('\n')) .setColor('Yellow') .setTimestamp(); diff --git a/src/commands/slash/Main/hub/join.ts b/src/commands/slash/Main/hub/join.ts index 3989f7409..f08c3c198 100644 --- a/src/commands/slash/Main/hub/join.ts +++ b/src/commands/slash/Main/hub/join.ts @@ -1,20 +1,20 @@ -import db from '../../../../utils/Db.js'; -import Hub from './index.js'; -import { ChannelType, ChatInputCommandInteraction } from 'discord.js'; -import { emojis } from '../../../../utils/Constants.js'; +import { showOnboarding } from '#main/scripts/network/onboarding.js'; +import { connectChannel, getAllConnections } from '#main/utils/ConnectedList.js'; +import { emojis } from '#main/utils/Constants.js'; +import db from '#main/utils/Db.js'; +import { logJoinToHub } from '#main/utils/HubLogger/JoinLeave.js'; +import { t } from '#main/utils/Locale.js'; +import { getOrCreateWebhook, getUserLocale, sendToHub, simpleEmbed } from '#main/utils/Utils.js'; import { hubs } from '@prisma/client'; -import { simpleEmbed, getOrCreateWebhook, sendToHub } from '../../../../utils/Utils.js'; -import { showOnboarding } from '../../../../scripts/network/onboarding.js'; import { stripIndents } from 'common-tags'; -import { t } from '../../../../utils/Locale.js'; -import { logJoinToHub } from '../../../../utils/HubLogger/JoinLeave.js'; -import { connectChannel, getAllConnections } from '../../../../utils/ConnectedList.js'; +import { ChannelType, ChatInputCommandInteraction } from 'discord.js'; +import Hub from './index.js'; export default class JoinSubCommand extends Hub { async execute(interaction: ChatInputCommandInteraction): Promise { if (!interaction.inCachedGuild()) return; - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); // NOTE: Change later const hubName = interaction.options.getString('hub') ?? 'InterChat Central'; diff --git a/src/commands/slash/Main/hub/joined.ts b/src/commands/slash/Main/hub/joined.ts index ef96a7d0d..dd8860bb8 100644 --- a/src/commands/slash/Main/hub/joined.ts +++ b/src/commands/slash/Main/hub/joined.ts @@ -1,10 +1,10 @@ -import Hub from './index.js'; -import db from '../../../../utils/Db.js'; import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js'; -import { paginate } from '../../../../utils/Pagination.js'; -import { simpleEmbed } from '../../../../utils/Utils.js'; -import { t } from '../../../../utils/Locale.js'; -import { colors, emojis } from '../../../../utils/Constants.js'; +import { colors, emojis } from '#main/utils/Constants.js'; +import db from '#main/utils/Db.js'; +import { t } from '#main/utils/Locale.js'; +import { paginate } from '#main/utils/Pagination.js'; +import { getUserLocale, simpleEmbed } from '#main/utils/Utils.js'; +import Hub from './index.js'; export default class Joined extends Hub { async execute(interaction: ChatInputCommandInteraction): Promise { @@ -13,15 +13,11 @@ export default class Joined extends Hub { include: { hub: true }, }); + const locale = await getUserLocale(interaction.user.id); if (connections.length === 0) { await interaction.reply({ embeds: [ - simpleEmbed( - t( - { phrase: 'hub.joined.noJoinedHubs', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), + simpleEmbed(t({ phrase: 'hub.joined.noJoinedHubs', locale }, { emoji: emojis.no })), ], }); return; @@ -43,10 +39,7 @@ export default class Joined extends Hub { // Start a new embed currentEmbed = new EmbedBuilder() .setDescription( - t( - { phrase: 'hub.joined.joinedHubs', locale: interaction.user.locale }, - { total: `${allFields.length}` }, - ), + t({ phrase: 'hub.joined.joinedHubs', locale }, { total: `${allFields.length}` }), ) .setColor(colors.interchatBlue); @@ -65,10 +58,7 @@ export default class Joined extends Hub { const embed = new EmbedBuilder() .setDescription( - t( - { phrase: 'hub.joined.joinedHubs', locale: interaction.user.locale }, - { total: `${allFields.length}` }, - ), + t({ phrase: 'hub.joined.joinedHubs', locale }, { total: `${allFields.length}` }), ) .setFields(allFields) .setColor(colors.interchatBlue); diff --git a/src/commands/slash/Main/hub/leave.ts b/src/commands/slash/Main/hub/leave.ts index 3c0fdd7b8..2f4b85c23 100644 --- a/src/commands/slash/Main/hub/leave.ts +++ b/src/commands/slash/Main/hub/leave.ts @@ -12,7 +12,7 @@ import Hub from './index.js'; import { RegisterInteractionHandler } from '../../../../decorators/Interaction.js'; import { CustomID } from '../../../../utils/CustomID.js'; import { emojis } from '../../../../utils/Constants.js'; -import { simpleEmbed, setComponentExpiry } from '../../../../utils/Utils.js'; +import { setComponentExpiry, getUserLocale } from '../../../../utils/Utils.js'; import { t } from '../../../../utils/Locale.js'; import { logGuildLeaveToHub } from '../../../../utils/HubLogger/JoinLeave.js'; import { deleteConnection } from '../../../../utils/ConnectedList.js'; @@ -28,27 +28,22 @@ export default class Leave extends Hub { include: { hub: true }, }); + const locale = await getUserLocale(interaction.user.id); if (!isChannelConnected) { - await interaction.editReply({ - embeds: [ - simpleEmbed( - t({ phrase: 'hub.leave.noHub', locale: interaction.user.locale }, { emoji: emojis.no }), - ), - ], - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.leave.noHub', locale }, { emoji: emojis.no }), + ); return; } else if (!interaction.member.permissions.has('ManageChannels', true)) { - await interaction.editReply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'errors.missingPermissions', locale: interaction.user.locale }, - { permissions: 'Manage Channels', emoji: emojis.no }, - ), - ), - ], - }); + await this.replyEmbed( + interaction, + t( + { phrase: 'errors.missingPermissions', locale }, + { permissions: 'Manage Channels', emoji: emojis.no }, + ), + ); return; } @@ -68,13 +63,13 @@ export default class Leave extends Hub { const resetConfirmEmbed = new EmbedBuilder() .setDescription( t( - { phrase: 'hub.leave.confirm', locale: interaction.user.locale }, + { phrase: 'hub.leave.confirm', locale }, { channel: `<#${channelId}>`, hub: `${isChannelConnected.hub?.name}` }, ), ) .setColor('Red') .setFooter({ - text: t({ phrase: 'hub.leave.confirmFooter', locale: interaction.user.locale }), + text: t({ phrase: 'hub.leave.confirmFooter', locale }), }); const reply = await interaction.editReply({ @@ -89,7 +84,6 @@ export default class Leave extends Hub { static override async handleComponents(interaction: MessageComponentInteraction): Promise { const customId = CustomID.parseCustomId(interaction.customId); const [channelId] = customId.args; - const { locale } = interaction.user; if (customId.suffix === 'no') { await interaction.deferUpdate(); @@ -97,6 +91,7 @@ export default class Leave extends Hub { return; } + const locale = await getUserLocale(interaction.user.id); const validConnection = await db.connectedList.findFirst({ where: { channelId } }); if (!validConnection) { await interaction.update({ diff --git a/src/commands/slash/Main/hub/manage.ts b/src/commands/slash/Main/hub/manage.ts index 9ce2b7bec..544f8bf8e 100644 --- a/src/commands/slash/Main/hub/manage.ts +++ b/src/commands/slash/Main/hub/manage.ts @@ -9,7 +9,12 @@ import db from '#main/utils/Db.js'; import { setLogChannelFor } from '#main/utils/HubLogger/Default.js'; import { removeReportsFrom, setReportRole } from '#main/utils/HubLogger/Report.js'; import { t } from '#main/utils/Locale.js'; -import { checkAndFetchImgurUrl, setComponentExpiry, simpleEmbed } from '#main/utils/Utils.js'; +import { + checkAndFetchImgurUrl, + getUserLocale, + setComponentExpiry, + simpleEmbed, +} from '#main/utils/Utils.js'; import { Prisma } from '@prisma/client'; import { ActionRowBuilder, @@ -32,7 +37,7 @@ import Hub from './index.js'; export default class Manage extends Hub { async execute(interaction: ChatInputCommandInteraction) { - // the chosen one heh + const locale = await getUserLocale(interaction.user.id); const chosenHub = interaction.options.getString('hub', true); const hubInDb = await db.hubs.findFirst({ where: { @@ -48,7 +53,7 @@ export default class Manage extends Hub { if (!hubInDb) { await this.replyEmbed( interaction, - t({ phrase: 'hub.notFound_mod', locale: interaction.user.locale }, { emoji: emojis.no }), + t({ phrase: 'hub.notFound_mod', locale }, { emoji: emojis.no }), ); return; } @@ -80,7 +85,7 @@ export default class Manage extends Hub { await interaction.reply({ embeds: [await hubEmbed(hubInDb)], - components: [actionsSelect(hubInDb.id, interaction.user.id, interaction.user.locale), button], + components: [actionsSelect(hubInDb.id, interaction.user.id, locale), button], }); // disable components after 5 minutes @@ -126,13 +131,10 @@ export default class Manage extends Hub { data: { settings: hubSettings.toggle(selected).bitfield }, // toggle the setting }); + const locale = await getUserLocale(interaction.user.id); if (!updHub) { await interaction.reply({ - embeds: [ - simpleEmbed( - t({ phrase: 'errors.unknown', locale: interaction.user.locale }, { emoji: emojis.no }), - ), - ], + embeds: [simpleEmbed(t({ phrase: 'errors.unknown', locale }, { emoji: emojis.no }))], ephemeral: true, }); return; @@ -470,7 +472,7 @@ export default class Manage extends Hub { static override async handleModals(interaction: ModalSubmitInteraction) { const customId = CustomID.parseCustomId(interaction.customId); const [hubId] = customId.args; - const locale = interaction.user.locale || 'en'; + const locale = await getUserLocale(interaction.user.id); let hubInDb = await db.hubs.findFirst({ where: { @@ -696,7 +698,7 @@ export default class Manage extends Hub { static async componentChecks(interaction: MessageComponentInteraction) { const customId = CustomID.parseCustomId(interaction.customId); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); if (customId.args[0] !== interaction.user.id) { await interaction.reply({ diff --git a/src/commands/slash/Main/hub/moderator.ts b/src/commands/slash/Main/hub/moderator.ts index 773c047c2..7f4ee4bb0 100644 --- a/src/commands/slash/Main/hub/moderator.ts +++ b/src/commands/slash/Main/hub/moderator.ts @@ -1,9 +1,9 @@ +import { emojis } from '#main/utils/Constants.js'; +import db from '#main/utils/Db.js'; +import { t } from '#main/utils/Locale.js'; +import { getUserLocale } from '#main/utils/Utils.js'; import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js'; import Hub from './index.js'; -import db from '../../../../utils/Db.js'; -import { simpleEmbed } from '../../../../utils/Utils.js'; -import { t } from '../../../../utils/Locale.js'; -import { emojis } from '../../../../utils/Constants.js'; export default class Moderator extends Hub { async execute(interaction: ChatInputCommandInteraction): Promise { @@ -18,18 +18,13 @@ export default class Moderator extends Hub { }, }); + const locale = await getUserLocale(interaction.user.id); if (!hub) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.notFound_mod', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.notFound_mod', locale }, { emoji: emojis.no }), + { ephemeral: true }, + ); return; } @@ -38,17 +33,14 @@ export default class Moderator extends Hub { const user = interaction.options.getUser('user', true); if (hub.moderators.find((mod) => mod.userId === user.id)) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.moderator.add.alreadyModerator', locale: interaction.user.locale }, - { user: user.toString(), emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t( + { phrase: 'hub.moderator.add.alreadyModerator', locale }, + { user: user.toString(), emoji: emojis.no }, + ), + { ephemeral: true }, + ); break; } @@ -60,7 +52,7 @@ export default class Moderator extends Hub { await interaction.reply({ content: t( - { phrase: 'hub.moderator.add.success', locale: interaction.user.locale }, + { phrase: 'hub.moderator.add.success', locale }, { user: user.toString(), position, emoji: emojis.yes }, ), }); @@ -73,7 +65,7 @@ export default class Moderator extends Hub { if (!hub.moderators.find((mod) => mod.userId === user.id)) { await interaction.reply({ content: t( - { phrase: 'hub.moderator.remove.notModerator', locale: interaction.user.locale }, + { phrase: 'hub.moderator.remove.notModerator', locale }, { user: user.toString(), emoji: emojis.no }, ), ephemeral: true, @@ -90,13 +82,7 @@ export default class Moderator extends Hub { (user.id === interaction.user.id && !isExecutorOwner) ) { await interaction.reply({ - content: t( - { - phrase: 'hub.moderator.remove.notOwner', - locale: interaction.user.locale, - }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'hub.moderator.remove.notOwner', locale }, { emoji: emojis.no }), ephemeral: true, }); break; @@ -111,7 +97,7 @@ export default class Moderator extends Hub { await interaction.reply( t( - { phrase: 'hub.moderator.remove.success', locale: interaction.user.locale }, + { phrase: 'hub.moderator.remove.success', locale }, { user: user.toString(), emoji: emojis.yes }, ), ); @@ -129,54 +115,30 @@ export default class Moderator extends Hub { ); if (!isExecutorMod) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'hub.moderator.update.notAllowed', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.moderator.update.notAllowed', locale }, { emoji: emojis.no }), + { ephemeral: true }, + ); break; } else if (!isUserMod) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { - phrase: 'hub.moderator.update.notModerator', - locale: interaction.user.locale, - }, - { user: user.toString() }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.moderator.update.notModerator', locale }, { user: user.toString() }), + { ephemeral: true }, + ); break; } else if ( (hub.ownerId !== interaction.user.id && user.id === interaction.user.id) || isUserMod.position === 'manager' ) { - await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { - phrase: 'hub.moderator.update.notOwner', - locale: interaction.user.locale, - }, - { emoji: emojis.no }, - ), - ), - ], - ephemeral: true, - }); + await this.replyEmbed( + interaction, + t({ phrase: 'hub.moderator.update.notOwner', locale }, { emoji: emojis.no }), + { ephemeral: true }, + ); break; } @@ -191,7 +153,7 @@ export default class Moderator extends Hub { await interaction.reply( t( - { phrase: 'hub.moderator.update.success', locale: interaction.user.locale }, + { phrase: 'hub.moderator.update.success', locale }, { user: user.toString(), position, emoji: emojis.yes }, ), ); @@ -213,10 +175,7 @@ export default class Moderator extends Hub { }`, ) .join('\n') - : t( - { phrase: 'hub.moderator.noModerators', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + : t({ phrase: 'hub.moderator.noModerators', locale }, { emoji: emojis.no }), ) .setColor('Aqua') .setTimestamp(), @@ -228,7 +187,5 @@ export default class Moderator extends Hub { default: break; } - - return; } } diff --git a/src/commands/slash/Main/hub/servers.ts b/src/commands/slash/Main/hub/servers.ts index f9bb94019..1851c055e 100644 --- a/src/commands/slash/Main/hub/servers.ts +++ b/src/commands/slash/Main/hub/servers.ts @@ -3,7 +3,7 @@ import Hub from './index.js'; import { colors, emojis } from '../../../../utils/Constants.js'; import { paginate } from '../../../../utils/Pagination.js'; import db from '../../../../utils/Db.js'; -import { resolveEval, simpleEmbed } from '../../../../utils/Utils.js'; +import { getUserLocale, resolveEval, simpleEmbed } from '../../../../utils/Utils.js'; import { t } from '../../../../utils/Locale.js'; export default class Servers extends Hub { @@ -12,7 +12,7 @@ export default class Servers extends Hub { const hubOpt = interaction.options.getString('hub', true); const serverOpt = interaction.options.getString('server'); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const hub = await db.hubs.findUnique({ where: { name: hubOpt }, diff --git a/src/commands/slash/Main/set/language.ts b/src/commands/slash/Main/set/language.ts index 0ac91a4e4..b313c73dc 100644 --- a/src/commands/slash/Main/set/language.ts +++ b/src/commands/slash/Main/set/language.ts @@ -1,6 +1,7 @@ +import { getUserLocale } from '#main/utils/Utils.js'; import { ChatInputCommandInteraction } from 'discord.js'; -import db from '../../../../utils/Db.js'; import { emojis } from '../../../../utils/Constants.js'; +import db from '../../../../utils/Db.js'; import { supportedLocaleCodes, supportedLocales, t } from '../../../../utils/Locale.js'; import Set from './index.js'; @@ -11,7 +12,7 @@ export default class SetLanguage extends Set { if (!Object.keys(supportedLocales).includes(locale)) { await interaction.reply({ content: t( - { phrase: 'errors.invalidLangCode', locale: interaction.user.locale }, + { phrase: 'errors.invalidLangCode', locale: await getUserLocale(interaction.user.id) }, { emoji: emojis.info }, ), ephemeral: true, diff --git a/src/commands/slash/Support/support/report.ts b/src/commands/slash/Support/support/report.ts index eef78a27e..ed486dfa0 100644 --- a/src/commands/slash/Support/support/report.ts +++ b/src/commands/slash/Support/support/report.ts @@ -18,6 +18,7 @@ import { LINKS, channels, colors, emojis } from '../../../../utils/Constants.js' import { CustomID } from '../../../../utils/CustomID.js'; import { RegisterInteractionHandler } from '../../../../decorators/Interaction.js'; import { t } from '../../../../utils/Locale.js'; +import { getUserLocale } from '#main/utils/Utils.js'; export default class Report extends Support { async execute(interaction: ChatInputCommandInteraction) { @@ -27,6 +28,8 @@ export default class Report extends Support { | 'bug' | 'other'; + const locale = await getUserLocale(interaction.user.id); + if (reportType === 'bug') { const bugSelect = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() @@ -47,10 +50,9 @@ export default class Report extends Support { .setValue('Other'), ), ); - const bugEmbed = new EmbedBuilder() - .setTitle(t({ phrase: 'report.bug.affected', locale: interaction.user.locale })) - .setDescription(t({ phrase: 'report.bug.description', locale: interaction.user.locale })) + .setTitle(t({ phrase: 'report.bug.affected', locale })) + .setDescription(t({ phrase: 'report.bug.description', locale })) .setColor(colors.interchatBlue); await interaction.reply({ @@ -61,16 +63,14 @@ export default class Report extends Support { } else { const modal = new ModalBuilder() - .setTitle(t({ phrase: 'report.modal.title', locale: interaction.user.locale })) + .setTitle(t({ phrase: 'report.modal.title', locale })) .setCustomId(new CustomID().setIdentifier('report_modal', reportType).toString()) .addComponents( new ActionRowBuilder().addComponents( new TextInputBuilder() .setCustomId('description') - .setLabel(t({ phrase: 'report.modal.other.label', locale: interaction.user.locale })) - .setPlaceholder( - t({ phrase: 'report.modal.other.placeholder', locale: interaction.user.locale }), - ) + .setLabel(t({ phrase: 'report.modal.other.label', locale })) + .setPlaceholder(t({ phrase: 'report.modal.other.placeholder', locale })) .setStyle(TextInputStyle.Paragraph) .setMinLength(10) .setMaxLength(950), @@ -79,10 +79,7 @@ export default class Report extends Support { if (reportType !== 'other') { const content = t( - { - phrase: 'misc.reportOptionMoved', - locale: interaction.user.locale, - }, + { phrase: 'misc.reportOptionMoved', locale }, { emoji: emojis.exclamation, support_invite: LINKS.SUPPORT_INVITE }, ); @@ -96,6 +93,8 @@ export default class Report extends Support { @RegisterInteractionHandler('report') static override async handleComponents(interaction: MessageComponentInteraction) { + const locale = await getUserLocale(interaction.user.id); + if (interaction.isStringSelectMenu()) { const modal = new ModalBuilder() .setCustomId( @@ -104,34 +103,20 @@ export default class Report extends Support { .addArgs(interaction.values.join(', ')) .toString(), ) - .setTitle(t({ phrase: 'report.bug.title', locale: interaction.user.locale })) + .setTitle(t({ phrase: 'report.bug.title', locale })) .setComponents( new ActionRowBuilder().addComponents( new TextInputBuilder() .setCustomId('summary') - .setLabel( - t({ phrase: 'report.modal.bug.input1.label', locale: interaction.user.locale }), - ) - .setPlaceholder( - t({ - phrase: 'report.modal.bug.input1.placeholder', - locale: interaction.user.locale, - }), - ) + .setLabel(t({ phrase: 'report.modal.bug.input1.label', locale })) + .setPlaceholder(t({ phrase: 'report.modal.bug.input1.placeholder', locale })) .setStyle(TextInputStyle.Short), ), new ActionRowBuilder().addComponents( new TextInputBuilder() .setCustomId('description') - .setLabel( - t({ phrase: 'report.modal.bug.input2.label', locale: interaction.user.locale }), - ) - .setPlaceholder( - t({ - phrase: 'report.modal.bug.input1.placeholder', - locale: interaction.user.locale, - }), - ) + .setLabel(t({ phrase: 'report.modal.bug.input2.label', locale })) + .setPlaceholder(t({ phrase: 'report.modal.bug.input1.placeholder', locale })) .setStyle(TextInputStyle.Paragraph) .setRequired(false) .setMinLength(17), @@ -203,9 +188,11 @@ export default class Report extends Support { break; } } + + const locale = await getUserLocale(interaction.user.id); await interaction.reply({ content: t( - { phrase: 'report.submitted', locale: interaction.user.locale }, + { phrase: 'report.submitted', locale }, { emoji: emojis.yes, support_command: '' }, ), ephemeral: true, diff --git a/src/core/BaseCommand.ts b/src/core/BaseCommand.ts index da4a98b7d..c44b44f22 100644 --- a/src/core/BaseCommand.ts +++ b/src/core/BaseCommand.ts @@ -14,19 +14,20 @@ import { time, } from 'discord.js'; import { InteractionFunction } from '#main/decorators/Interaction.js'; -import { t } from '#main/utils/Locale.js'; +import { supportedLocaleCodes, t } from '#main/utils/Locale.js'; import { emojis } from '#main/utils/Constants.js'; -import { getReplyMethod, simpleEmbed } from '#main/utils/Utils.js'; +import { getReplyMethod, getUserLocale, simpleEmbed } from '#main/utils/Utils.js'; export type CmdInteraction = ChatInputCommandInteraction | ContextMenuCommandInteraction; +export type CommandBody = + | RESTPostAPIChatInputApplicationCommandsJSONBody + | RESTPostAPIContextMenuApplicationCommandsJSONBody; export const commandsMap = new Collection(); export const interactionsMap = new Collection(); export default abstract class BaseCommand { - abstract readonly data: - | RESTPostAPIChatInputApplicationCommandsJSONBody - | RESTPostAPIContextMenuApplicationCommandsJSONBody; + abstract readonly data: CommandBody; readonly staffOnly?: boolean; readonly cooldown?: number; readonly description?: string; @@ -43,7 +44,8 @@ export default abstract class BaseCommand { const remainingCooldown = await this.getRemainingCooldown(interaction); if (remainingCooldown) { - await this.sendCooldownError(interaction, remainingCooldown); + const locale = await getUserLocale(interaction.user.id); + await this.sendCooldownError(interaction, remainingCooldown, locale); return true; } @@ -54,12 +56,13 @@ export default abstract class BaseCommand { async sendCooldownError( interaction: RepliableInteraction, remainingCooldown: number, + locale: supportedLocaleCodes, ): Promise { const waitUntil = Math.round((Date.now() + remainingCooldown) / 1000); await interaction.reply({ content: t( - { phrase: 'errors.cooldown', locale: interaction.user.locale }, + { phrase: 'errors.cooldown', locale }, { time: `${time(waitUntil, 'T')} (${time(waitUntil, 'R')})`, emoji: emojis.no }, ), ephemeral: true, diff --git a/src/decorators/Interaction.ts b/src/decorators/Interaction.ts index 18889bdbc..77ed6b12a 100644 --- a/src/decorators/Interaction.ts +++ b/src/decorators/Interaction.ts @@ -1,3 +1,4 @@ +import 'reflect-metadata'; import { interactionsMap } from '#main/utils/LoadCommands.js'; import { MessageComponentInteraction, ModalSubmitInteraction } from 'discord.js'; @@ -10,6 +11,7 @@ export function RegisterInteractionHandler(prefix: string, suffix = ''): MethodD return function(targetClass, propertyKey: string | symbol, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value as InteractionFunction; const realSuffix = suffix ? `:${suffix}` : ''; + // console.log(new targetClass.constructor(), targetClass); // NOTE: It is not possible to access other class properties for decorator methods // so don't try to access `this.` in any decorator method body diff --git a/src/managers/EventManager.ts b/src/managers/EventManager.ts index 086575f06..0a5520803 100644 --- a/src/managers/EventManager.ts +++ b/src/managers/EventManager.ts @@ -1,48 +1,53 @@ +import GatewayEvent from '#main/decorators/GatewayEvent.js'; +import getWelcomeTargets from '#main/scripts/guilds/getWelcomeTarget.js'; +import { logGuildJoin, logGuildLeave } from '#main/scripts/guilds/goals.js'; +import { getReferredMsgData, sendWelcomeMsg } from '#main/scripts/network/helpers.js'; +import { runChecks } from '#main/scripts/network/runChecks.js'; +import sendBroadcast from '#main/scripts/network/sendBroadcast.js'; +import storeMessageData from '#main/scripts/network/storeMessageData.js'; +import { addReaction, updateReactions } from '#main/scripts/reaction/actions.js'; +import { checkBlacklists } from '#main/scripts/reaction/helpers.js'; +import { HubSettingsBitField } from '#main/utils/BitFields.js'; +import { + deleteConnections, + getAllConnections, + modifyConnection, +} from '#main/utils/ConnectedList.js'; +import { channels, colors, emojis, LINKS } from '#main/utils/Constants.js'; +import { CustomID } from '#main/utils/CustomID.js'; +import db from '#main/utils/Db.js'; +import { logGuildLeaveToHub } from '#main/utils/HubLogger/JoinLeave.js'; +import { supportedLocaleCodes, t } from '#main/utils/Locale.js'; +import Logger from '#main/utils/Logger.js'; +import { check } from '#main/utils/Profanity.js'; +import { + checkIfStaff, + getAttachmentURL, + getDbUser, + getUserLocale, + handleError, + simpleEmbed, +} from '#main/utils/Utils.js'; +import { stripIndents } from 'common-tags'; import { ActionRowBuilder, ButtonBuilder, ButtonStyle, + Client, EmbedBuilder, + ForumChannel, Guild, - User, HexColorString, - Message, - MessageReaction, - PartialUser, Interaction, - Client, - ForumChannel, MediaChannel, + Message, + MessageReaction, NewsChannel, + PartialUser, TextChannel, + User, VoiceChannel, } from 'discord.js'; -import { - checkIfStaff, - getAttachmentURL, - getUserLocale, - handleError, - simpleEmbed, -} from '../utils/Utils.js'; -import db from '../utils/Db.js'; -import Logger from '../utils/Logger.js'; -import GatewayEvent from '../decorators/GatewayEvent.js'; -import sendBroadcast from '../scripts/network/sendBroadcast.js'; -import storeMessageData from '../scripts/network/storeMessageData.js'; -import getWelcomeTargets from '../scripts/guilds/getWelcomeTarget.js'; -import { t } from '../utils/Locale.js'; -import { check } from '../utils/Profanity.js'; -import { runChecks } from '../scripts/network/runChecks.js'; -import { stripIndents } from 'common-tags'; -import { logGuildJoin, logGuildLeave } from '../scripts/guilds/goals.js'; -import { channels, emojis, colors, LINKS } from '../utils/Constants.js'; -import { getReferredMsgData, sendWelcomeMsg } from '../scripts/network/helpers.js'; -import { HubSettingsBitField } from '../utils/BitFields.js'; -import { addReaction, updateReactions } from '../scripts/reaction/actions.js'; -import { checkBlacklists } from '../scripts/reaction/helpers.js'; -import { CustomID } from '../utils/CustomID.js'; -import { logGuildLeaveToHub } from '../utils/HubLogger/JoinLeave.js'; -import { deleteConnections, getAllConnections, modifyConnection } from '../utils/ConnectedList.js'; export default abstract class EventManager { @GatewayEvent('ready') @@ -104,10 +109,8 @@ export default abstract class EventManager { // if there already are reactions by others // and the user hasn't reacted yet !emojiAlreadyReacted?.includes(user.id) - ? // add user to the array - addReaction(dbReactions, user.id, reactedEmoji) - : // or update the data with a new arr containing userId - (dbReactions[reactedEmoji] = emojiAlreadyReacted); + ? addReaction(dbReactions, user.id, reactedEmoji) // add user to the array + : (dbReactions[reactedEmoji] = emojiAlreadyReacted); // or update the data with a new arr containing userI await db.originalMessages.update({ where: { messageId: originalMsg.messageId }, @@ -169,7 +172,7 @@ export default abstract class EventManager { const embed = new EmbedBuilder() .setTitle('👋 Thanks for adding me to your server!') .setDescription( - stripIndents` + stripIndents` Take your first step into the world of cross-server chatting with InterChat! 🚀 Explore public hubs, connect with multiple servers, and add a splash of excitement to your server experience. ${emojis.clipart} ### Getting Started - Simply run to see an easy to follow setup guide. @@ -256,7 +259,7 @@ export default abstract class EventManager { con.hubId === connection.hubId && con.connected && con.channelId !== message.channel.id, ); - let userData = await db.userData.findFirst({ where: { id: message.author.id } }); + let userData = await getDbUser(message.author.id); if (!userData?.viewedNetworkWelcome) { userData = await db.userData.upsert({ where: { id: message.author.id }, @@ -268,12 +271,12 @@ export default abstract class EventManager { update: { viewedNetworkWelcome: true }, }); - await sendWelcomeMsg(message, hubConnections.length.toString(), hub.name); + await sendWelcomeMsg(message, (userData.locale as supportedLocaleCodes | null) ?? 'en', { + hub: hub.name, + totalServers: hubConnections.length.toString(), + }); } - // set locale for the user - message.author.locale = getUserLocale(userData); - const attachmentURL = message.attachments.first()?.url ?? (await getAttachmentURL(message.content)); @@ -315,13 +318,13 @@ export default abstract class EventManager { try { const { commands, interactions } = interaction.client; const userData = await db.userData.findFirst({ where: { id: interaction.user.id } }); - interaction.user.locale = getUserLocale(userData); if (userData?.banMeta?.reason) { if (interaction.isRepliable()) { + const locale = await getUserLocale(userData); await interaction.reply({ content: t( - { phrase: 'errors.banned', locale: interaction.user.locale }, + { phrase: 'errors.banned', locale }, { emoji: emojis.no, reason: userData.banMeta.reason, @@ -347,15 +350,9 @@ export default abstract class EventManager { const isExpiredInteraction = customId.expiry && customId.expiry < Date.now(); if (!interactionHandler || isExpiredInteraction) { + const locale = await getUserLocale(userData); await interaction.reply({ - embeds: [ - simpleEmbed( - t( - { phrase: 'errors.notUsable', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), - ), - ], + embeds: [simpleEmbed(t({ phrase: 'errors.notUsable', locale }, { emoji: emojis.no }))], ephemeral: true, }); return; diff --git a/src/scripts/network/helpers.ts b/src/scripts/network/helpers.ts index 015bd8cf3..5a4b22362 100644 --- a/src/scripts/network/helpers.ts +++ b/src/scripts/network/helpers.ts @@ -11,7 +11,7 @@ import db from '../../utils/Db.js'; import { LINKS, REGEX, emojis } from '../../utils/Constants.js'; import { censor } from '../../utils/Profanity.js'; import { broadcastedMessages } from '@prisma/client'; -import { t } from '../../utils/Locale.js'; +import { supportedLocaleCodes, t } from '../../utils/Locale.js'; export type NetworkAPIError = { error: string }; @@ -139,7 +139,11 @@ export const generateJumpButton = ( ), ); -export const sendWelcomeMsg = async (message: Message, totalServers: string, hub: string) => { +export const sendWelcomeMsg = async ( + message: Message, + locale: supportedLocaleCodes, + opts: { totalServers: string; hub: string }, +) => { const linkButtons = new ActionRowBuilder().addComponents( new ButtonBuilder() .setStyle(ButtonStyle.Link) @@ -161,14 +165,14 @@ export const sendWelcomeMsg = async (message: Message, totalServers: string, hub await message.channel .send({ content: t( - { phrase: 'network.welcome', locale: message.author.locale ?? 'en' }, + { phrase: 'network.welcome', locale }, { user: message.author.toString(), channel: message.channel.toString(), emoji: emojis.wave_anim, rules_command: '', - hub, - totalServers, + hub: opts.hub, + totalServers: opts.totalServers, }, ), components: [linkButtons], diff --git a/src/scripts/network/onboarding.ts b/src/scripts/network/onboarding.ts index 63da6b703..37794c4dc 100644 --- a/src/scripts/network/onboarding.ts +++ b/src/scripts/network/onboarding.ts @@ -1,22 +1,20 @@ +import { LINKS, colors } from '#main/utils/Constants.js'; +import { supportedLocaleCodes, t } from '#main/utils/Locale.js'; +import { getReplyMethod, getUserLocale } from '#main/utils/Utils.js'; import { ActionRowBuilder, - ButtonStyle, - EmbedBuilder, ButtonBuilder, - ComponentType, ButtonInteraction, + ButtonStyle, Collection, + ComponentType, + EmbedBuilder, RepliableInteraction, } from 'discord.js'; -import { LINKS, colors } from '../../utils/Constants.js'; -import { supportedLocaleCodes, t } from '../../utils/Locale.js'; const onboardingInProgress = new Collection(); -const processAcceptButton = async ( - interaction: ButtonInteraction, - channelId: string, -) => { +const processAcceptButton = async (interaction: ButtonInteraction, channelId: string) => { await interaction?.deferUpdate(); onboardingInProgress.delete(channelId); // remove in-progress marker as onboarding has either been cancelled or completed return interaction?.customId === 'onboarding_:accept'; @@ -81,7 +79,7 @@ export const showOnboarding = async ( // Mark this as in-progress so server can't join twice onboardingInProgress.set(channelId, channelId); - const { locale } = interaction.user; + const locale = await getUserLocale(interaction.user.id); const embedPhrase = 'network.onboarding.embed'; const embed = new EmbedBuilder() @@ -112,10 +110,7 @@ export const showOnboarding = async ( ephemeral, }; - const reply = interaction.deferred || interaction.replied - ? await interaction.editReply(replyMsg) - : await interaction.reply(replyMsg); - + const reply = await interaction[getReplyMethod(interaction)](replyMsg); const response = await reply .awaitMessageComponent({ time: 60_000 * 2, diff --git a/src/scripts/network/runChecks.ts b/src/scripts/network/runChecks.ts index ccdc2721d..11bc99879 100644 --- a/src/scripts/network/runChecks.ts +++ b/src/scripts/network/runChecks.ts @@ -3,7 +3,7 @@ import { Message, EmbedBuilder } from 'discord.js'; import { HubSettingsBitField } from '../../utils/BitFields.js'; import { emojis, REGEX } from '../../utils/Constants.js'; import { t } from '../../utils/Locale.js'; -import { containsInviteLinks, replaceLinks } from '../../utils/Utils.js'; +import { containsInviteLinks, getUserLocale, replaceLinks } from '../../utils/Utils.js'; import { check as checkProfanity } from '../../utils/Profanity.js'; import { runAntiSpam } from './antiSpam.js'; import { analyzeImageForNSFW, isUnsafeImage } from '../../utils/NSFWDetection.js'; @@ -82,7 +82,6 @@ export const containsLinks = (message: Message, settings: HubSettingsBitField) = !REGEX.STATIC_IMAGE_URL.test(message.content) && REGEX.LINKS.test(message.content); - export const unsupportedAttachment = (message: Message) => { const attachment = message.attachments.first(); // NOTE: Even 'image/gif' was allowed before @@ -108,9 +107,9 @@ export const runChecks = async ( hubId: string, opts: { settings: HubSettingsBitField; userData: userDataCol; attachmentURL?: string | null }, ): Promise => { - const { locale } = message.author; const { hasProfanity, hasSlurs } = checkProfanity(message.content); const { settings, userData, attachmentURL } = opts; + const locale = await getUserLocale(userData); const isUserBlacklisted = userData.blacklistedFrom.some((b) => b.hubId === hubId); // banned / blacklisted @@ -128,7 +127,7 @@ export const runChecks = async ( await message.channel .send( t( - { phrase: 'network.accountTooNew', locale: message.author.locale }, + { phrase: 'network.accountTooNew', locale }, { user: message.author.toString(), emoji: emojis.no }, ), ) diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index f9e13749c..51c0767cd 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -1,11 +1,10 @@ -import Scheduler from '../services/SchedulerService.ts'; -import BaseCommand from '../core/BaseCommand.ts'; -import CooldownService from '../services/CooldownService.ts'; -import UserDbManager from '../managers/UserDbManager.ts'; -import ServerBlacklisManager from '../managers/ServerBlacklistManager.ts'; +import Scheduler from '#main/services/SchedulerService.ts'; +import BaseCommand from '#main/core/BaseCommand.ts'; +import CooldownService from '#main/services/CooldownService.ts'; +import UserDbManager from '#main/managers/UserDbManager.ts'; +import ServerBlacklisManager from '#main/managers/ServerBlacklistManager.ts'; import { ClusterClient } from 'discord-hybrid-sharding'; -import { InteractionFunction } from '../decorators/Interaction.ts'; -import { supportedLocaleCodes } from '../utils/Locale.ts'; +import { InteractionFunction } from '#main/decorators/Interaction.ts'; import { Collection, Snowflake } from 'discord.js'; type RemoveMethods = { @@ -29,8 +28,4 @@ declare module 'discord.js' { fetchGuild(guildId: Snowflake): Promise | undefined>; getScheduler(): Scheduler; } - - export interface User { - locale?: supportedLocaleCodes; - } } diff --git a/src/utils/RandomComponents.ts b/src/utils/RandomComponents.ts index 7b7b2188d..a958b5017 100644 --- a/src/utils/RandomComponents.ts +++ b/src/utils/RandomComponents.ts @@ -1,5 +1,8 @@ /* eslint-disable complexity */ -import db from './Db.js'; +import { RegisterInteractionHandler } from '#main/decorators/Interaction.js'; +import { addReaction, removeReaction, updateReactions } from '#main/scripts/reaction/actions.js'; +import { checkBlacklists } from '#main/scripts/reaction/helpers.js'; +import { stripIndents } from 'common-tags'; import { ActionRowBuilder, AnySelectMenuInteraction, @@ -9,16 +12,13 @@ import { StringSelectMenuBuilder, time, } from 'discord.js'; -import { getEmojiId, simpleEmbed, sortReactions } from './Utils.js'; import { HubSettingsBitField } from './BitFields.js'; -import { CustomID } from './CustomID.js'; -import { RegisterInteractionHandler } from '../decorators/Interaction.js'; +import { modifyConnection } from './ConnectedList.js'; import { emojis } from './Constants.js'; -import { stripIndents } from 'common-tags'; +import { CustomID } from './CustomID.js'; +import db from './Db.js'; import { t } from './Locale.js'; -import { removeReaction, addReaction, updateReactions } from '../scripts/reaction/actions.js'; -import { checkBlacklists } from '../scripts/reaction/helpers.js'; -import { modifyConnection } from './ConnectedList.js'; +import { getEmojiId, getUserLocale, simpleEmbed, sortReactions } from './Utils.js'; // skipcq: JS-0327 export abstract class RandomComponents { @@ -116,9 +116,9 @@ export abstract class RandomComponents { .setDescription( stripIndents` ## ${emojis.clipart} Reactions - + ${reactionString || 'No reactions yet!'} - + **Total Reactions:** __${totalReactions}__ `, @@ -132,22 +132,18 @@ export abstract class RandomComponents { }); } else { + const locale = await getUserLocale(interaction.user.id); + if (userBlacklisted) { await interaction.followUp({ - content: t( - { phrase: 'errors.userBlacklisted', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.userBlacklisted', locale }, { emoji: emojis.no }), ephemeral: true, }); return; } else if (serverBlacklisted) { await interaction.followUp({ - content: t( - { phrase: 'errors.userBlacklisted', locale: interaction.user.locale }, - { emoji: emojis.no }, - ), + content: t({ phrase: 'errors.userBlacklisted', locale }, { emoji: emojis.no }), ephemeral: true, }); return; @@ -176,10 +172,8 @@ export abstract class RandomComponents { } emojiAlreadyReacted.includes(interaction.user.id) - ? // If the user already reacted, remove the reaction - removeReaction(dbReactions, interaction.user.id, reactedEmoji) - : // or else add the user to the array - addReaction(dbReactions, interaction.user.id, reactedEmoji); + ? removeReaction(dbReactions, interaction.user.id, reactedEmoji) // If the user already reacted, remove the reaction + : addReaction(dbReactions, interaction.user.id, reactedEmoji); // or else add the user to the array await db.originalMessages.update({ where: { messageId: messageInDb.originalMsgId }, @@ -187,7 +181,7 @@ export abstract class RandomComponents { }); if (interaction.isStringSelectMenu()) { - // FIXME seems like emojiAlreadyReacted is getting mutated somewhere + /** FIXME: seems like `emojiAlreadyReacted` is getting mutated somewhere */ const action = emojiAlreadyReacted.includes(interaction.user.id) ? 'reacted' : 'unreacted'; interaction .followUp({ diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 190e77483..288d14f35 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -114,6 +114,15 @@ export const userVotedToday = async (id: Snowflake): Promise => { return Boolean(user?.lastVoted && user.lastVoted >= new Date(Date.now() - (60 * 60 * 24 * 1000))); }; +export const getUserLocale = async (userOrId: string | userData | null | undefined) => { + let dbUser: userData | null | undefined; + + if (typeof userOrId === 'string') dbUser = await getDbUser(userOrId); + else dbUser = userOrId; + + return (dbUser?.locale as supportedLocaleCodes | null | undefined) ?? 'en'; +}; + export const yesOrNoEmoji = (option: unknown, yesEmoji: string, noEmoji: string) => option ? yesEmoji : noEmoji; @@ -308,10 +317,11 @@ export const getReplyMethod = (interaction: RepliableInteraction | CommandIntera */ export const sendErrorEmbed = async (interaction: RepliableInteraction, errorId: string) => { const method = getReplyMethod(interaction); + const locale = await getUserLocale(interaction.user.id); // reply with an error message if the command failed return await interaction[method]({ - embeds: [simpleEmbed(genCommandErrMsg(interaction.user.locale || 'en', errorId))], + embeds: [simpleEmbed(genCommandErrMsg(locale, errorId))], ephemeral: true, }).catch(() => null); }; @@ -475,9 +485,6 @@ export const getAttachmentURL = async (string: string) => { export const fetchHub = async (id: string) => await db.hubs.findFirst({ where: { id } }); -export const getUserLocale = (user: userData | undefined | null) => - (user?.locale as supportedLocaleCodes | null | undefined) || 'en'; - export const containsInviteLinks = (str: string) => { const inviteLinks = ['discord.gg', 'discord.com/invite', 'dsc.gg']; return inviteLinks.some((link) => str.includes(link)); diff --git a/src/utils/db/prismaCacheExtension.ts b/src/utils/db/prismaCacheExtension.ts index c1e82b894..c93ef2041 100644 --- a/src/utils/db/prismaCacheExtension.ts +++ b/src/utils/db/prismaCacheExtension.ts @@ -6,7 +6,6 @@ import { } from '@prisma/client/runtime/library'; import db from '../Db.js'; import { cacheData, getCacheKey, invalidateCacheForModel } from './cacheUtils.js'; -import { DynamicQueryExtensionCb, InternalArgs, DefaultArgs } from '@prisma/client/runtime/library'; type ActionT = | 'findUnique'