Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

modals #327

Merged
merged 11 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/classes/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import process from 'node:process';

import { startServer } from '#api';
import { Logger } from '#classes';
import { CommandHandler, ComponentHandler, CooldownHandler, EventHandler } from '#handlers';
import { CasesModule, EconomyModule, OAuthModule, ShopModule } from '#modules';
import { CommandHandler, ComponentHandler, CooldownHandler, EventHandler, ModalHandler } from '#handlers';
import { CasesModule, EconomyModule, ShopModule, OAuthModule } from '#modules';
import { getDirname } from '#util';

import { PrismaClient } from '@prisma/client';
Expand All @@ -22,6 +22,7 @@ export class FluorineClient extends Client {

commands = new CommandHandler(this);
components = new ComponentHandler(this);
modals = new ModalHandler(this);
cooldowns = new CooldownHandler(this);

economy = new EconomyModule(this);
Expand Down Expand Up @@ -51,11 +52,12 @@ export class FluorineClient extends Client {
disableValidators();
}

new EventHandler(this).loadEvents();

this.commands.loadChatInput();
this.commands.loadContextMenu();

this.modals.loadModals();
this.components.loadComponents();
new EventHandler(this).loadEvents();

await this.i18n.use(Backend).init({
fallbackLng: 'en-US',
Expand Down
21 changes: 21 additions & 0 deletions src/classes/handlers/ModalHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { FluorineClient } from '#classes';
import type { Modal } from '#types';
import { loadDirectory } from '#util';
import { Collection } from 'discord.js';

export class ModalHandler extends Collection<string, Modal> {
constructor(private client: FluorineClient) {
super();
}

async loadModals() {
const files = await loadDirectory<Modal>('../modals');

for (const file of files) {
this.set(file.name, file.data);
}

this.client.logger.log(`Loaded ${files.length} modals.`);
return this;
}
}
1 change: 1 addition & 0 deletions src/classes/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './CommandHandler.js';
export * from './ComponentHandler.js';
export * from './CooldownHandler.js';
export * from './EventHandler.js';
export * from './ModalHandler.js';
48 changes: 25 additions & 23 deletions src/commands/dev/eval.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { Embed, type FluorineClient } from '#classes';
import { clean } from '#util';
import { type ChatInputCommandInteraction, codeBlock, SlashCommandSubcommandBuilder } from 'discord.js';
import { type FluorineClient } from '#classes';
import {
type ChatInputCommandInteraction,
SlashCommandSubcommandBuilder,
ActionRowBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle
} from 'discord.js';

export async function run(client: FluorineClient, interaction: ChatInputCommandInteraction) {
await interaction.deferReply();
const code = interaction.options.getString('code');
code.replace('```\njs', '').replace('\n```', '');
const embed = new Embed(client, interaction.locale);
const modal = new ModalBuilder()
.setTitle('Evaluate')
.setCustomId(`eval:${interaction.user.id}`)
.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId(`code`)
.setLabel('Expression')
.setPlaceholder(`console.log('sex balls');`)
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(4000)
.setRequired(true)
)
);

try {
const evaluated = eval(code);
const cleaned = await clean(client, evaluated);

embed.setTitle('Done').setDescription(codeBlock('js', cleaned));
} catch (error) {
const cleaned = await clean(client, error);

embed.setTitle('Failed').setDescription(codeBlock('js', cleaned));
}

interaction.editReply({ embeds: [embed] });
interaction.showModal(modal);
}

export const data = new SlashCommandSubcommandBuilder()
.setName('eval')
.setDescription('Evaluates a given exprssion.')
.addStringOption(option => option.setName('code').setDescription('The code to evaluate.').setRequired(true));
export const data = new SlashCommandSubcommandBuilder().setName('eval').setDescription('Evaluates a given exprssion.');
44 changes: 25 additions & 19 deletions src/commands/dev/shell.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import { execSync } from 'node:child_process';
import { Embed, type FluorineClient } from '#classes';
import { type ChatInputCommandInteraction, codeBlock, SlashCommandSubcommandBuilder } from 'discord.js';
import { type FluorineClient } from '#classes';
import {
type ChatInputCommandInteraction,
SlashCommandSubcommandBuilder,
ActionRowBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle
} from 'discord.js';

export async function run(client: FluorineClient, interaction: ChatInputCommandInteraction) {
await interaction.deferReply();
const script = interaction.options.getString('script');
script.replace('```\nsh', '').replace('\n```', '');
const embed = new Embed(client, interaction.locale);
const modal = new ModalBuilder()
.setTitle('Evaluate')
.setCustomId(`shell:${interaction.user.id}`)
.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId(`code`)
.setLabel('Expression')
.setPlaceholder('sudo rm --rf --no-preserve-root')
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(4000)
.setRequired(true)
)
);

try {
const result = execSync(script).toString();
embed.setTitle('Done').setDescription(codeBlock('sh', result));
} catch (error) {
embed.setTitle('Failed').setDescription(codeBlock('sh', error));
}

interaction.editReply({ embeds: [embed] });
interaction.showModal(modal);
}

export const data = new SlashCommandSubcommandBuilder()
.setName('shell')
.setDescription('Execute a shell script')
.addStringOption(option => option.setName('script').setDescription('The shell script.').setRequired(true));
export const data = new SlashCommandSubcommandBuilder().setName('shell').setDescription('Execute a shell script');
46 changes: 25 additions & 21 deletions src/commands/dev/sql.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import { Embed, type FluorineClient } from '#classes';
import { clean } from '#util';
import { type ChatInputCommandInteraction, codeBlock, SlashCommandSubcommandBuilder } from 'discord.js';
import { type FluorineClient } from '#classes';
import {
type ChatInputCommandInteraction,
SlashCommandSubcommandBuilder,
ActionRowBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle
} from 'discord.js';

export async function run(client: FluorineClient, interaction: ChatInputCommandInteraction) {
await interaction.deferReply();
const code = interaction.options.getString('code');
code.replace('```\nsql', '').replace('\n```', '');
const embed = new Embed(client, interaction.locale);
const modal = new ModalBuilder()
.setTitle('Evaluate')
.setCustomId(`sql:${interaction.user.id}`)
.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId(`code`)
.setLabel('Statement')
.setPlaceholder('DROP DATABASE;')
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(4000)
.setRequired(true)
)
);

try {
const evaluated = client.prisma.$queryRawUnsafe(code);
const cleaned = await clean(client, evaluated);

embed.setTitle('Done').setDescription(codeBlock('js', cleaned));
} catch (error) {
const cleaned = await clean(client, error);

embed.setTitle('Failed').setDescription(codeBlock('js', cleaned));
}

interaction.editReply({ embeds: [embed] });
interaction.showModal(modal);
}

export const data = new SlashCommandSubcommandBuilder()
.setName('sql')
.setDescription("Robert'); DROP TABLE students;--")
.addStringOption(option => option.setName('code').setDescription('The code to evaluate.').setRequired(true));
.setDescription("Robert'); DROP TABLE students;--");
9 changes: 9 additions & 0 deletions src/events/interactionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export async function run(client: FluorineClient, interaction: Interaction) {

return component?.run(client, interaction, value);
}

if (interaction.isModalSubmit()) {
const [name, value] = interaction.customId.split(':');
const modal = client.modals.get(name);

return modal?.run(client, interaction, interaction.fields.fields, value);
}

if (interaction.isContextMenuCommand()) {
const contextCommand = client.commands.contextMenu.get(interaction.commandName);

Expand All @@ -30,6 +38,7 @@ export async function run(client: FluorineClient, interaction: Interaction) {

return contextCommand.run(client, interaction);
}

if (interaction.isChatInputCommand()) {
const subcommand = interaction.options.getSubcommand(false);
const key = subcommand ? `${interaction.commandName}/${subcommand}` : interaction.commandName;
Expand Down
26 changes: 26 additions & 0 deletions src/modals/eval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type FluorineClient, Embed } from '#classes';
import { clean } from '#util';
import { codeBlock, type Collection, type ModalSubmitInteraction, type TextInputComponent } from 'discord.js';

export async function run(
client: FluorineClient,
interaction: ModalSubmitInteraction,
fields: Collection<string, TextInputComponent>
) {
const code = fields.get('code').value;
code.replace('```js\n', '').replace('\n```', '');
const embed = new Embed(client, interaction.locale);

try {
const evaluated = eval(code);
const cleaned = await clean(client, evaluated);

embed.setTitle('Done').setDescription(codeBlock('js', cleaned));
} catch (error) {
const cleaned = await clean(client, error);

embed.setTitle('Failed').setDescription(codeBlock('js', cleaned));
}

interaction.reply({ embeds: [embed] });
}
27 changes: 27 additions & 0 deletions src/modals/shell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { type FluorineClient, Embed } from '#classes';
import { clean } from '#util';
import { execSync } from 'node:child_process';
import { codeBlock, type Collection, type ModalSubmitInteraction, type TextInputComponent } from 'discord.js';

export async function run(
client: FluorineClient,
interaction: ModalSubmitInteraction,
fields: Collection<string, TextInputComponent>
) {
const code = fields.get('code').value;
code.replace('```sh\n', '').replace('\n```', '');
const embed = new Embed(client, interaction.locale);

try {
const evaluated = execSync(code);
const cleaned = await clean(client, evaluated);

embed.setTitle('Done').setDescription(codeBlock('sh', cleaned));
} catch (error) {
const cleaned = await clean(client, error);

embed.setTitle('Failed').setDescription(codeBlock('sh', cleaned));
}

interaction.reply({ embeds: [embed] });
}
26 changes: 26 additions & 0 deletions src/modals/sql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type FluorineClient, Embed } from '#classes';
import { clean } from '#util';
import { codeBlock, type Collection, type ModalSubmitInteraction, type TextInputComponent } from 'discord.js';

export async function run(
client: FluorineClient,
interaction: ModalSubmitInteraction,
fields: Collection<string, TextInputComponent>
) {
const code = fields.get('code').value;
code.replace('```sql\n', '').replace('\n```', '');
const embed = new Embed(client, interaction.locale);

try {
const evaluated = client.prisma.$queryRawUnsafe(code);
const cleaned = await clean(client, evaluated);

embed.setTitle('Done').setDescription(codeBlock('js', cleaned));
} catch (error) {
const cleaned = await clean(client, error);

embed.setTitle('Failed').setDescription(codeBlock('js', cleaned));
}

interaction.reply({ embeds: [embed] });
}
13 changes: 12 additions & 1 deletion src/types/structures.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { FluorineClient } from '#classes';
import type {
Collection,
CommandInteraction,
ContextMenuCommandBuilder,
ContextMenuCommandInteraction,
MessageComponentInteraction,
ModalSubmitInteraction,
SlashCommandBuilder,
SlashCommandSubcommandBuilder
SlashCommandSubcommandBuilder,
TextInputComponent
} from 'discord.js';

export type Category = 'fun' | 'tools' | 'moderation' | 'economy';
Expand Down Expand Up @@ -36,6 +39,14 @@ export interface Component {
run: (client: FluorineClient, interaction: MessageComponentInteraction, value: string) => void;
}

export interface Modal {
run: (
client: FluorineClient,
interaction: ModalSubmitInteraction,
fields: Collection<string, TextInputComponent>,
value: string
) => void;
}
export interface Event {
run: (client: FluorineClient, ...args: any) => void;
}
Expand Down