Skip to content

Commit

Permalink
feat(guards): interactions locale extractor (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bartholomé committed Aug 9, 2022
1 parent 1a4fc1a commit f284e5c
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 53 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ You can also find useful documentations:
<summary>Click here to expand the roadmap</summary>

#### Todo
- [ ] fix backup path fs for docker (with __dirname)
- [ ] finish full localization of built-in commands

#### Discord
- [ ] Custom events
Expand Down
7 changes: 5 additions & 2 deletions cli/generators/templates/command.ts.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Client } from "discordx"
import { Category } from "@discordx/utilities"
import { CommandInteraction } from "discord.js"
import { } from "discord.js"

import { Discord, Slash, SlashOption } from "@decorators"
import { Guard } from "@guards"
Expand All @@ -13,7 +13,10 @@ export default class {{pascalCase name}}Command {
'Here goes the command description!'
})
@Guard()
{{camelCase name}}(interaction: CommandInteraction): void {
{{camelCase name}}(
interaction: CommandInteraction
{ localize }: InteractionData
): void {

interaction.reply('{{camelCase name}} command invoked!')
}
Expand Down
15 changes: 8 additions & 7 deletions src/commands/Admin/prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Guard, UserPermissions } from "@guards"
import { Guild } from "@entities"
import { resolveGuild, simpleSuccessEmbed } from "@utils/functions"
import { Database } from "@services"
import { getLocaleFromInteraction, L } from "@i18n"

import { generalConfig } from '@config'
import { UnknownReplyError } from "@errors"
Expand All @@ -29,23 +28,25 @@ export default class PrefixCommand {
)
async prefix(
@SlashOption('prefix', { required: false, type: ApplicationCommandOptionType.String }) prefix: string | undefined,
interaction: CommandInteraction
interaction: CommandInteraction,
{ localize }: InteractionData
) {



const guild = resolveGuild(interaction),
guildData = await this.db.getRepo(Guild).findOne({ id: guild?.id || '' })

if (guildData) {

guildData.prefix = prefix || null
this.db.getRepo(Guild).persistAndFlush(guildData)

const locale = getLocaleFromInteraction(interaction)

simpleSuccessEmbed(
interaction,
L[locale]['COMMANDS']['PREFIX']['CHANGED']({
localize['COMMANDS']['PREFIX']['CHANGED']({
prefix: prefix || generalConfig.simpleCommandsPrefix
}))
})
)
}
else {
throw new UnknownReplyError(interaction)
Expand Down
33 changes: 14 additions & 19 deletions src/commands/General/help.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Client, MetadataStorage, SelectMenuComponent } from "discordx"
import { Category } from "@discordx/utilities"
import { CommandInteraction, Formatters, ActionRowBuilder, EmbedBuilder, SelectMenuBuilder, APISelectMenuOption, SelectMenuInteraction } from "discord.js"
import { Formatters, ActionRowBuilder, EmbedBuilder, SelectMenuBuilder, APISelectMenuOption, CommandInteraction, SelectMenuInteraction } from "discord.js"

import { Discord, Slash } from "@decorators"
import { Guard } from "@guards"
import { chunkArray, getColor, validString } from "@utils/functions"
import { getLocaleFromInteraction, L, Locales } from "@i18n"
import { L, Locales } from "@i18n"

@Discord()
@Category('General')
Expand All @@ -20,14 +19,14 @@ export default class HelpCommand {
@Slash('help', { description:
'Get global help about the bot and its commands'
})
help(interaction: CommandInteraction, client: Client): void {

const locale = getLocaleFromInteraction(interaction)
help(interaction: CommandInteraction, client: Client, { sanitizedLocale }: InteractionData): void {

const embed = this.getEmbed({ client, interaction, locale });
console.debug(1, sanitizedLocale)

const embed = this.getEmbed({ client, interaction, locale: sanitizedLocale });

let components: any[] = [];
components.push(this.getSelectDropdown("categories", locale).toJSON())
components.push(this.getSelectDropdown("categories", sanitizedLocale).toJSON())

interaction.followUp({
embeds: [embed],
Expand All @@ -36,15 +35,13 @@ export default class HelpCommand {
}

@SelectMenuComponent('help-category-selector')
async selectCategory(interaction: SelectMenuInteraction, client: Client) {

const locale = getLocaleFromInteraction(interaction)
async selectCategory(interaction: SelectMenuInteraction, client: Client, { sanitizedLocale }: InteractionData) {

const category = interaction.values[0]

const embed = await this.getEmbed({ client, interaction, locale, category })
const embed = await this.getEmbed({ client, interaction, category, locale: sanitizedLocale })
let components: any[] = [];
components.push(this.getSelectDropdown("categories", locale).toJSON())
components.push(this.getSelectDropdown("categories", sanitizedLocale).toJSON())

interaction.update({
embeds: [embed],
Expand All @@ -53,12 +50,12 @@ export default class HelpCommand {
}


private getEmbed({ client, interaction, locale, category = '', pageNumber = 0 }: {
private getEmbed({ client, interaction, category = '', pageNumber = 0, locale }: {
client: Client,
interaction: CommandInteraction | SelectMenuInteraction,
locale: Locales,
category?: string,
pageNumber?: number
locale: Locales
}): EmbedBuilder {

const commands = this._categories.get(category)
Expand All @@ -77,10 +74,8 @@ export default class HelpCommand {

for (const category of this._categories) {
embed.addFields([{
name: category[0],
value: category[1]
.map(command => command.name)
.join(', ')
name: category[0],
value: category[1].map(command => command.name).join(', ')
}])
}

Expand Down
12 changes: 4 additions & 8 deletions src/commands/General/invite.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Client } from "discordx"
import { Category } from "@discordx/utilities"
import { CommandInteraction, EmbedBuilder } from "discord.js"

import { Discord, Slash, SlashOption } from "@decorators"
import { Discord, Slash } from "@decorators"
import { Guard } from "@guards"
import { getColor } from "@utils/functions"
import { getLocaleFromInteraction, L } from "@i18n"
import { generalConfig } from "@config"

@Discord()
Expand All @@ -16,13 +14,11 @@ export default class InviteCommand {
'A simple invite command!'
})
@Guard()
invite(interaction: CommandInteraction): void {

const locale = getLocaleFromInteraction(interaction)
invite(interaction: CommandInteraction, { localize }: InteractionData): void {

const embed = new EmbedBuilder()
.setTitle(L[locale].COMMANDS.INVITE.TITLE())
.setDescription(L[locale].COMMANDS.INVITE.DESCRIPTION({link: generalConfig.inviteLink}))
.setTitle(localize.COMMANDS.INVITE.TITLE())
.setDescription(localize.COMMANDS.INVITE.DESCRIPTION({link: generalConfig.inviteLink}))
.setColor(getColor('primary'))
.setFooter({ text : 'Powered by DiscBot Team ❤'})

Expand Down
3 changes: 2 additions & 1 deletion src/commands/General/ping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export default class PingCommand {
})
async ping(
interaction: CommandInteraction,
client: Client
client: Client,
{ localize }: InteractionData
) {

const msg = (await interaction.followUp({ content: "Pinging...", fetchReply: true })) as Message
Expand Down
9 changes: 3 additions & 6 deletions src/commands/General/stats.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Client } from "discordx"
import { Category } from "@discordx/utilities"
import { CommandInteraction, EmbedBuilder, User } from "discord.js"
import { injectable } from "tsyringe"
Expand All @@ -9,7 +8,6 @@ import {

import { Discord, Slash, SlashOption } from "@decorators"
import { Stats } from "@services"
import { getLocaleFromInteraction, L } from "@i18n"
import { getColor } from "@utils/functions"

const statsResolver: StatsResolverType = [
Expand Down Expand Up @@ -57,19 +55,18 @@ export default class StatsCommand {
})
async statsHandler(
@SlashOption('days') days: number,
interaction: CommandInteraction
interaction: CommandInteraction,
{ localize }: InteractionData
) {

const embeds: EmbedBuilder[] = []

const locale = getLocaleFromInteraction(interaction)

for (const stat of statsResolver) {

const stats = await stat.data(this.stats, days),
link = await this.generateLink(
stats,
L[locale]['COMMANDS']['STATS']['HEADERS'][stat.name as keyof typeof L[(typeof locale)]['COMMANDS']['STATS']['HEADERS']]()),
localize['COMMANDS']['STATS']['HEADERS'][stat.name as keyof typeof localize['COMMANDS']['STATS']['HEADERS']]()),
embed = this.getEmbed(interaction.user, link)

embeds.push(embed)
Expand Down
10 changes: 5 additions & 5 deletions src/commands/Owner/maintenance.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { CommandInteraction } from "discord.js"

import { Slash, Discord, SlashOption, Guard } from "@decorators"
import { setMaintenance, simpleSuccessEmbed } from "@utils/functions"
import { getLocaleFromInteraction, L } from "@i18n"
import { Disabled } from "@guards"
import { CommandInteraction } from "discord.js"

@Discord()
export default class MaintenanceCommand {
Expand All @@ -16,15 +15,16 @@ export default class MaintenanceCommand {
)
async maintenance(
@SlashOption('state') state: boolean,
interaction: CommandInteraction
interaction: CommandInteraction,
{ localize }: InteractionData
) {

await setMaintenance(state)

const locale = getLocaleFromInteraction(interaction)
simpleSuccessEmbed(
interaction,
L[locale]['COMMANDS']['MAINTENANCE']['SUCCESS']({
localize['COMMANDS']['MAINTENANCE']['SUCCESS']({
state: state ? 'on' : 'off'
})
)
Expand Down
5 changes: 3 additions & 2 deletions src/events/interactionCreate.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MessageComponentInteraction, CommandInteraction as DCommandInteraction } from 'discord.js'
import { Client, ArgsOf } from 'discordx'
import { injectable } from 'tsyringe'

Expand All @@ -6,7 +7,7 @@ import { Maintenance } from '@guards'
import { Guild, User } from '@entities'
import { On, Guard, Discord } from '@decorators'
import { syncUser } from '@utils/functions'
import { CommandInteraction, MessageComponentInteraction } from 'discord.js'
import { getLocaleFromInteraction, L } from '@i18n'

@Discord()
@injectable()
Expand All @@ -29,7 +30,7 @@ export default class InteractionCreateEvent {
// defer the reply
if(
interaction instanceof MessageComponentInteraction ||
interaction instanceof CommandInteraction
interaction instanceof DCommandInteraction
) await interaction.deferReply();

// insert user in db if not exists
Expand Down
2 changes: 1 addition & 1 deletion src/guards/disabled.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GuardFunction, SimpleCommandMessage } from 'discordx'
import { CommandInteraction, ContextMenuCommandInteraction } from 'discord.js'
import { ContextMenuCommandInteraction, CommandInteraction } from 'discord.js'

import { getLocaleFromInteraction, L } from '@i18n'
import { resolveUser, replyToInteraction } from '@utils/functions'
Expand Down
36 changes: 36 additions & 0 deletions src/guards/extractLocale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { GuardFunction, SimpleCommandMessage } from 'discordx'
import { ContextMenuCommandInteraction, CommandInteraction as DCommandInteraction, Interaction, MessageContextMenuCommandInteraction, UserContextMenuCommandInteraction, CommandInteraction, SelectMenuInteraction, ButtonInteraction } from 'discord.js'

import { getLocaleFromInteraction, L } from '@i18n'
import { resolveUser, replyToInteraction } from '@utils/functions'

import { generalConfig } from '@config'

/**
* Extract locale from any interaction and pass it as guard data
*/
export const Disabled: GuardFunction<Interaction> = async (interaction, client, next, guardData) => {

if (
interaction instanceof SimpleCommandMessage
|| interaction instanceof CommandInteraction
|| interaction instanceof ContextMenuCommandInteraction
|| interaction instanceof SelectMenuInteraction
|| interaction instanceof ButtonInteraction
) {

const sanitizedLocale = getLocaleFromInteraction(interaction as AllInteractions)

const interactionData: InteractionData = {
sanitizedLocale: sanitizedLocale,
localize: L[sanitizedLocale]
}

guardData = {
...guardData,
...interactionData
}
}

await next()
}
2 changes: 1 addition & 1 deletion src/utils/classes/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './BaseError'
export * from './BaseController'
export * from './BaseController'
7 changes: 6 additions & 1 deletion src/utils/types/interactions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ type AllInteractions = EmittedInteractions | OnTheFlyInteractions

type InteractionsConstants = 'CHAT_INPUT_COMMAND_INTERACTION' | 'SIMPLE_COMMAND_MESSAGE' | 'CONTEXT_MENU_INTERACTION' | 'BUTTON_INTERACTION' | 'SELECT_MENU_INTERACTION' | 'MODAL_SUBMIT_INTERACTION'

type CommandCategory = import('discordx').DApplicationCommand & import('@discordx/utilities').ICategory
type CommandCategory = import('discordx').DApplicationCommand & import('@discordx/utilities').ICategory

type InteractionData = {
sanitizedLocale: import('src/i18n').Locales
localize: import('src/i18n/i18n-types').TranslationFunctions
}

0 comments on commit f284e5c

Please # to comment.