diff options
Diffstat (limited to 'src/commands')
-rw-r--r-- | src/commands/_fake-command/ironmoon.ts (renamed from src/commands/_fake-command/test.ts) | 14 | ||||
-rw-r--r-- | src/commands/dev/eval.ts | 355 | ||||
-rw-r--r-- | src/commands/dev/say.ts | 13 | ||||
-rw-r--r-- | src/commands/dev/test.ts | 154 |
4 files changed, 292 insertions, 244 deletions
diff --git a/src/commands/_fake-command/test.ts b/src/commands/_fake-command/ironmoon.ts index 8eeca9e..500b384 100644 --- a/src/commands/_fake-command/test.ts +++ b/src/commands/_fake-command/ironmoon.ts @@ -1,17 +1,19 @@ import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; -export default class TestCommand extends BushCommand { +export default class IronmoonCommand extends BushCommand { public constructor() { - super('test', { + super('ironmoon', { category: 'fake-commands', description: { content: '', examples: '', usage: '' }, - condition: (message: BushMessage) => { - if (message.content.toLowerCase().includes('ironmoon')) return true; - else return false; - }, completelyHide: true }); } + public condition(message: BushMessage): boolean { + return false; + if (message.content.toLowerCase().includes('ironmoon')) return true; + else return false; + } + public async exec(message: BushMessage | BushSlashMessage): Promise<unknown> { return await message.util.reply('Your message included the word ironmoon.'); } diff --git a/src/commands/dev/eval.ts b/src/commands/dev/eval.ts index f8ba7e1..af6219b 100644 --- a/src/commands/dev/eval.ts +++ b/src/commands/dev/eval.ts @@ -1,118 +1,74 @@ import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; import { exec } from 'child_process'; -import { Constants } from 'discord-akairo'; -import { CommandInteraction, MessageEmbed, MessageEmbedOptions, Util } from 'discord.js'; +import { MessageEmbed as _MessageEmbed, Util } from 'discord.js'; import { transpile } from 'typescript'; -import { inspect, promisify } from 'util'; +import { inspect, InspectOptions, promisify } from 'util'; -const clean = (text) => { - if (typeof text === 'string') { - return Util.cleanCodeBlockContent(text); - } else return text; +const mapCredential = (old: string) => { + const mapping = { + ['token']: 'Main Token', + ['devToken']: 'Dev Token', + ['betaToken']: 'Beta Token', + ['hypixelApiKey']: 'Hypixel Api Key' + }; + return mapping[old] || old; +}; +const redact = (text: string) => { + for (const credentialName in client.config.credentials) { + const credential = client.config.credentials[credentialName]; + const replacement = mapCredential(credentialName); + const escapeRegex = /[.*+?^${}()|[\]\\]/g; + text = text.replace(new RegExp(credential.toString().replace(escapeRegex, '\\$&'), 'g'), `[${replacement} Omitted]`); + text = text.replace( + new RegExp([...credential.toString()].reverse().join('').replace(escapeRegex, '\\$&'), 'g'), + `[${replacement} Omitted]` + ); + } + return text; +}; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const inspectCleanRedactCodeblock = async (input: any, language: 'ts' | 'js', inspectOptions?: InspectOptions) => { + input = typeof input !== 'string' && inspectOptions !== undefined ? inspect(input, inspectOptions) : input; + input = Util.cleanCodeBlockContent(input); + input = redact(input); + return client.util.codeblock(input, 1024, language); }; export default class EvalCommand extends BushCommand { public constructor() { super('eval', { - aliases: ['eval', 'ev'], + aliases: ['eval', 'ev', 'evaluate'], category: 'dev', description: { content: 'Evaluate code.', - usage: 'eval [--depth #] <code> [--sudo] [--silent] [--delete] [--proto] [--hidden] [--ts]', - examples: ['eval message.guild.name', 'eval this.client.ownerID'] + usage: 'eval <code> [--depth #] [--sudo] [--silent] [--delete] [--proto] [--hidden] [--ts]', + examples: ['eval message.channel.delete()'] }, args: [ - { - id: 'sel_depth', - match: Constants.ArgumentMatches.OPTION, - type: Constants.ArgumentTypes.NUMBER, - flag: '--depth', - default: 0 - }, - { - id: 'sudo', - match: Constants.ArgumentMatches.FLAG, - flag: '--sudo' - }, - { - id: 'delete_msg', - match: Constants.ArgumentMatches.FLAG, - flag: '--delete' - }, - { - id: 'silent', - match: Constants.ArgumentMatches.FLAG, - flag: '--silent' - }, - { - id: 'typescript', - match: Constants.ArgumentMatches.FLAG, - flag: '--ts' - }, - { - id: 'hidden', - match: Constants.ArgumentMatches.FLAG, - flag: '--hidden' - }, - { - id: 'show_proto', - match: Constants.ArgumentMatches.FLAG, - flag: '--proto' - }, + { id: 'sel_depth', match: 'option', type: 'integer', flag: '--depth', default: 0 }, + { id: 'sudo', match: 'flag', flag: '--sudo' }, + { id: 'delete_msg', match: 'flag', flag: '--delete' }, + { id: 'silent', match: 'flag', flag: '--silent' }, + { id: 'typescript', match: 'flag', flag: '--ts' }, + { id: 'hidden', match: 'flag', flag: '--hidden' }, + { id: 'show_proto', match: 'flag', flag: '--proto' }, { id: 'code', - match: Constants.ArgumentMatches.REST, - type: Constants.ArgumentTypes.STRING, - prompt: { - start: 'What would you like to eval?', - retry: '{error} Invalid code to eval.' - } + match: 'rest', + type: 'string', + prompt: { start: 'What would you like to eval?', retry: '{error} Invalid code to eval.' } } ], slash: true, slashOptions: [ - { - name: 'code', - description: 'The code you would like to evaluate.', - type: 'STRING', - required: true - }, - { - name: 'sel_depth', - description: 'How deep to display the output.', - type: 'INTEGER', - required: false - }, - { - name: 'sudo', - description: 'Whether or not to override checks.', - type: 'BOOLEAN', - required: false - }, - { - name: 'silent', - description: 'Whether or not to make the response silent', - type: 'BOOLEAN', - required: false - }, - { - name: 'typescript', - description: 'Whether or not to compile the code from typescript.', - type: 'BOOLEAN', - required: false - }, - { - name: 'hidden', - description: 'Whether or not to show hidden items.', - type: 'BOOLEAN', - required: false - }, - { - name: 'show_proto', - description: 'Show prototype.', - type: 'BOOLEAN', - required: false - } + { name: 'code', description: 'The code you would like to evaluate.', type: 'STRING', required: true }, + { name: 'sel_depth', description: 'How deep to display the output.', type: 'INTEGER', required: false }, + { name: 'sudo', description: 'Whether or not to override checks.', type: 'BOOLEAN', required: false }, + { name: 'silent', description: 'Whether or not to make the response silent', type: 'BOOLEAN', required: false }, + { name: 'typescript', description: 'Whether or not the code is typescript.', type: 'BOOLEAN', required: false }, + { name: 'hidden', description: 'Whether or not to show hidden items.', type: 'BOOLEAN', required: false }, + { name: 'show_proto', description: 'Show prototype.', type: 'BOOLEAN', required: false } ], ownerOnly: true }); @@ -136,153 +92,98 @@ export default class EvalCommand extends BushCommand { if (message.util.isSlash) { await (message as BushSlashMessage).interaction.defer({ ephemeral: args.silent }); } - const code: { js?: string | null; ts?: string | null; lang?: 'js' | 'ts' } = {}; - args.code = args.code.replace(/[“”]/g, '"'); - args.code = args.code.replace(/```*(?:js|ts)?/g, ''); - if (args.typescript) { - code.ts = args.code; - code.js = transpile(args.code); - code.lang = 'ts'; - } else { - code.ts = null; - code.js = args.code; - code.lang = 'js'; - } + args.code = args.code.replace(/[“”]/g, '"').replace(/```*(?:js|ts)?/g, ''); - const embed: MessageEmbed = new MessageEmbed(); - const bad_phrases: string[] = ['delete', 'destroy']; + const code = { + ts: args.typescript ? args.code : null, + js: args.typescript ? transpile(args.code) : args.code, + lang: args.typescript ? 'ts' : 'js' + }; - function ae(old: string) { - const mapping = { - ['token']: 'Main Token', - ['devToken']: 'Dev Token', - ['betaToken']: 'Beta Token', - ['hypixelApiKey']: 'Hypixel Api Key' - }; - return mapping[old] || old; - } + const embed = new _MessageEmbed(); + const badPhrases = ['delete', 'destroy']; - if (bad_phrases.some((p) => code[code.lang].includes(p)) && !args.sudo) { + if (badPhrases.some((p) => code[code.lang].includes(p)) && !args.sudo) { return await message.util.send(`${this.client.util.emojis.error} This eval was blocked by smooth brain protection™.`); } - const embeds: (MessageEmbed | MessageEmbedOptions)[] = [new MessageEmbed()]; - embeds.some((embed) => embed); - try { - let output; - /* eslint-disable @typescript-eslint/no-unused-vars */ - const sh = promisify(exec), - me = message.member, - member = message.member, - bot = this.client, - guild = message.guild, - channel = message.channel, - config = this.client.config, - members = message.guild?.members, - roles = message.guild?.roles, - client = this.client, - { ActivePunishment, Global, Guild, Level, ModLog, StickyRole } = await import('@lib'), - { - ButtonInteraction, - Collector, - CommandInteraction, - Interaction, - Message, - MessageActionRow, - MessageAttachment, - MessageButton, - MessageCollector, - InteractionCollector, - MessageEmbed, - MessageSelectMenu, - ReactionCollector, - Util, - Collection - } = await import('discord.js'), - { Canvas } = await import('node-canvas'); - /* eslint-enable @typescript-eslint/no-unused-vars */ - if (code[code.lang].replace(/ /g, '').includes('9+10' || '10+9')) { - output = 21; - } else { - output = eval(code.js); - output = await output; - } - let proto, outputProto; - if (args.show_proto) { - proto = Object.getPrototypeOf(output); - outputProto = clean(inspect(proto, { depth: 1, getters: true, showHidden: true })); - } - if (typeof output !== 'string') - output = inspect(output, { depth: args.sel_depth || 0, showHidden: args.hidden, getters: true, showProxy: true }); - for (const credentialName in this.client.config.credentials) { - const credential = this.client.config.credentials[credentialName]; - const newCredential = ae(credentialName); - output = output.replace( - new RegExp(credential.toString().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), - `[${newCredential} Omitted]` - ); - output = output.replace( - new RegExp( - [...credential.toString()] - .reverse() - .join('') - .replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), - 'g' - ), - `[${newCredential} Omitted]` - ); - } + /* eslint-disable @typescript-eslint/no-unused-vars */ + const sh = promisify(exec), + me = message.member, + member = message.member, + bot = this.client, + guild = message.guild, + channel = message.channel, + config = this.client.config, + members = message.guild?.members, + roles = message.guild?.roles, + client = this.client, + emojis = this.client.util.emojis, + colors = this.client.util.colors, + util = this.client.util, + { ActivePunishment, Global, Guild, Level, ModLog, StickyRole } = await import('@lib'), + { + ButtonInteraction, + Collector, + CommandInteraction, + Interaction, + Message, + MessageActionRow, + MessageAttachment, + MessageButton, + MessageCollector, + InteractionCollector, + MessageEmbed, + MessageSelectMenu, + ReactionCollector, + Util, + Collection + } = await import('discord.js'), + { Canvas } = await import('node-canvas'); + /* eslint-enable @typescript-eslint/no-unused-vars */ - output = clean(output); - const inputJS = clean(code.js); + const inputJS = await inspectCleanRedactCodeblock(code.js, 'js'); + const inputTS = code.lang === 'ts' ? await inspectCleanRedactCodeblock(code.ts, 'ts') : undefined; + try { + const rawOutput = code[code.lang].replace(/ /g, '').includes('9+10' || '10+9') ? '21' : await eval(code.js); + const output = await inspectCleanRedactCodeblock(rawOutput, 'js', { + depth: args.sel_depth || 0, + showHidden: args.hidden, + getters: true, + showProxy: true + }); + const proto = args.show_proto + ? await inspectCleanRedactCodeblock(Object.getPrototypeOf(rawOutput), 'js', { + depth: 1, + getters: true, + showHidden: true + }) + : undefined; - embed - .setTitle(`${this.client.util.emojis.successFull} Evaled code successfully`) - .setColor(this.client.util.colors.success) - .setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true })) - .setTimestamp(); - if (code.lang === 'ts') { - const inputTS = clean(code.ts); - embed - .addField('📥 Input (typescript)', await this.client.util.codeblock(inputTS, 1024, 'ts')) - .addField('📥 Input (transpiled javascript)', await this.client.util.codeblock(inputJS, 1024, 'js')); - } else { - embed.addField('📥 Input', await this.client.util.codeblock(inputJS, 1024, 'js')); - } - embed.addField('📤 Output', await this.client.util.codeblock(output, 1024, 'js')); - if (args.show_proto) embed.addField('⚙️ Proto', await this.client.util.codeblock(outputProto, 1024, 'js')); + embed.setTitle(`${emojis.successFull} Evaluated code successfully`).setColor(colors.success); + if (inputTS) embed.addField('📥 Input (typescript)', inputTS).addField('📥 Input (transpiled javascript)', inputJS); + else embed.addField('📥 Input', inputJS); + embed.addField('📤 Output', output); + if (proto) embed.addField('⚙️ Proto', proto); } catch (e) { - const inputJS = clean(code.js); - embed - .setTitle(`${this.client.util.emojis.errorFull} Code was not able to be evaled.`) - .setColor(this.client.util.colors.error) - .setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true })) - .setTimestamp(); - if (code.lang === 'ts') { - const inputTS = clean(code.ts); - embed - .addField('📥 Input (typescript)', await this.client.util.codeblock(inputTS, 1024, 'ts')) - .addField('📥 Input (transpiled javascript)', await this.client.util.codeblock(inputJS, 1024, 'js')); - } else { - embed.addField('📥 Input', await this.client.util.codeblock(inputJS, 1024, 'js')); - } - embed.addField('📤 Output', await this.client.util.codeblock(e?.stack || e, 1024, 'js')); + embed.setTitle(`${emojis.errorFull} Code was not able to be evaluated.`).setColor(colors.error); + if (inputTS) embed.addField('📥 Input (typescript)', inputTS).addField('📥 Input (transpiled javascript)', inputJS); + else embed.addField('📥 Input', inputJS); + embed.addField('📤 Output', await inspectCleanRedactCodeblock(e?.stack || e, 'js')); } - if (!args.silent && !message.util.isSlash) { - await message.util.reply({ embeds: [embed], ephemeral: args.silent }); - } else if (message.util.isSlash) { - await (message.interaction as CommandInteraction).editReply({ embeds: [embed] }); + + embed.setTimestamp().setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true })); + + if (!args.silent || message.util.isSlash) { + await message.util.reply({ embeds: [embed] }); } else { try { await message.author.send({ embeds: [embed] }); - if (!args.deleteMSG) await (message as BushMessage).react(this.client.util.emojis.successFull); + if (!args.deleteMSG) await (message as BushMessage).react(emojis.successFull); } catch { - if (!args.deleteMSG) await (message as BushMessage).react(this.client.util.emojis.errorFull); + if (!args.deleteMSG) await (message as BushMessage).react(emojis.errorFull); } } - - if (args.deleteMSG && (message as BushMessage).deletable) { - await (message as BushMessage).delete(); - } + if (args.deleteMSG && (message as BushMessage).deletable) await (message as BushMessage).delete(); } } diff --git a/src/commands/dev/say.ts b/src/commands/dev/say.ts index 9dc2632..9f16e9c 100644 --- a/src/commands/dev/say.ts +++ b/src/commands/dev/say.ts @@ -16,19 +16,10 @@ export default class SayCommand extends BushCommand { id: 'say', type: 'string', match: 'rest', - prompt: { - start: 'What would you like the bot to say?', - retry: '{error} Choose something valid to say.' - } - } - ], - slashOptions: [ - { - name: 'content', - description: 'What would you like the bot to say?', - type: 'STRING' + prompt: { start: 'What would you like the bot to say?', retry: '{error} Choose something valid to say.' } } ], + slashOptions: [{ name: 'content', description: 'What would you like the bot to say?', type: 'STRING' }], ownerOnly: true, clientPermissions: ['SEND_MESSAGES'], slash: true diff --git a/src/commands/dev/test.ts b/src/commands/dev/test.ts new file mode 100644 index 0000000..49a3133 --- /dev/null +++ b/src/commands/dev/test.ts @@ -0,0 +1,154 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { BushCommand, BushMessage } from '@lib'; +import { Constants } from 'discord-akairo'; +import { Constants as jsConstants, MessageActionRow, MessageButton, MessageEmbed } from 'discord.js'; + +export default class TestCommand extends BushCommand { + public constructor() { + super('test', { + aliases: ['test'], + category: 'dev', + description: { + content: 'A command to stuff.', + usage: 'test [feature]', + examples: ['test lots of buttons', 'test buttons'] + }, + clientPermissions: ['SEND_MESSAGES'], + userPermissions: ['SEND_MESSAGES'], + args: [ + { + id: 'feature', + type: Constants.ArgumentTypes.STRING, + match: Constants.ArgumentMatches.REST, + prompt: { + start: 'start prompt', + retry: 'retry prompt', + optional: true + } + } + ] + }); + } + + // eslint-disable-next-line require-await + public async exec(message: BushMessage, args: { feature: string }): Promise<unknown> { + const responses = [ + 'Yes master.', + 'Test it your self bitch, I am hungry.', + 'Give me a break.', + 'I am not your slave.', + 'I have done as you wished, now please feed me.', + `Someone help me I am trapped in ${message.author.username}'s basement.` + ]; + if (!message.author.isOwner()) { + return await message.util.reply(responses[Math.floor(Math.random() * responses.length)]); + } + + const s = jsConstants.MessageButtonStyles; + if (['button', 'buttons'].includes(args?.feature?.toLowerCase())) { + const ButtonRow = new MessageActionRow().addComponents( + new MessageButton({ style: s.PRIMARY, customId: 'primaryButton', label: 'Primary' }), + new MessageButton({ style: s.SECONDARY, customId: 'secondaryButton', label: 'Secondary' }), + new MessageButton({ style: s.SUCCESS, customId: 'success', label: 'Success' }), + new MessageButton({ style: s.DANGER, customId: 'danger', label: 'Danger' }), + new MessageButton({ style: s.LINK, label: 'Link', url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' }) + ); + return await message.util.reply({ content: 'buttons', components: [ButtonRow] }); + } else if (['embed', 'button embed'].includes(args?.feature?.toLowerCase())) { + const embed = new MessageEmbed() + .addField('Field Name', 'Field Content') + .setAuthor('Author', 'https://www.w3schools.com/w3css/img_snowtops.jpg', 'https://google.com/') + .setColor(message.member.displayColor) + .setDescription('Description') + .setFooter('Footer', message.author.avatarURL()) + .setURL('https://duckduckgo.com/') + .setTimestamp() + .setImage('https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png') + .setThumbnail( + 'https://images.unsplash.com/photo-1501183007986-d0d080b147f9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2134&q=80' + ) + .setTitle('Title'); + + const buttonRow = new MessageActionRow().addComponents( + new MessageButton({ style: jsConstants.MessageButtonStyles.LINK, label: 'Link', url: 'https://www.google.com/' }) + ); + return await message.util.reply({ content: 'Test', embeds: [embed], components: [buttonRow] }); + } else if (['lots of buttons'].includes(args?.feature?.toLowerCase())) { + const ButtonRows: MessageActionRow[] = []; + for (let a = 1; a <= 5; a++) { + const row = new MessageActionRow(); + for (let b = 1; b <= 5; b++) { + const id = (a + 5 * (b - 1)).toString(); + const button = new MessageButton({ style: jsConstants.MessageButtonStyles.SECONDARY, customId: id, label: id }); + row.addComponents(button); + } + ButtonRows.push(row); + } + return await message.util.reply({ content: 'buttons', components: ButtonRows }); + } else if (['paginate'].includes(args?.feature?.toLowerCase())) { + const embeds = []; + for (let i = 1; i <= 5; i++) { + embeds.push(new MessageEmbed().setDescription(i.toString())); + } + return await this.client.util.buttonPaginate(message, embeds); + } else if (['lots of embeds'].includes(args?.feature?.toLowerCase())) { + const description = 'This is a description.'; + const author = { name: 'This is a author', iconURL: message.author.avatarURL({ dynamic: true }) }; + const footer = { text: 'This is a footer', iconURL: message.author.avatarURL({ dynamic: true }) }; + const fields = []; + for (let i = 0; i < 25; i++) { + fields.push({ name: 'Field ' + i, value: 'Field Value ' + i }); + } + const c = this.client.util.colors; + const o = { description, author, footer, fields }; + + const embeds = [ + new MessageEmbed({ ...o, ...{ title: 'Embed Title 0', color: c.red } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 1', color: c.orange } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 2', color: c.gold } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 3', color: c.yellow } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 4', color: c.green } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 5', color: c.darkGreen } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 6', color: c.aqua } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 7', color: c.blue } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 8', color: c.purple } }).setTimestamp(), + new MessageEmbed({ ...o, ...{ title: 'Embed Title 9', color: c.pink } }).setTimestamp() + ]; + + const ButtonRows: MessageActionRow[] = []; + for (let a = 1; a <= 5; a++) { + const row = new MessageActionRow(); + for (let b = 1; b <= 5; b++) { + const id = (a + 5 * (b - 1)).toString(); + const button = new MessageButton({ style: jsConstants.MessageButtonStyles.SECONDARY, customId: id, label: id }); + row.addComponents(button); + } + ButtonRows.push(row); + } + return await message.util.reply({ content: 'this is content', components: ButtonRows, embeds }); + } else if (['delete slash commands'].includes(args?.feature?.toLowerCase())) { + // let guildCommandCount = 0; + // this.client.guilds.cache.forEach(guild => + // guild.commands.fetch().then(commands => { + // commands.forEach(async command => { + // await command.delete(); + // guildCommandCount++; + // }); + // }) + // ); + const guildCommands = await message.guild.commands.fetch(); + guildCommands.forEach(async (command) => await command.delete()); + const globalCommands = await this.client.application.commands.fetch(); + globalCommands.forEach(async (command) => await command.delete()); + + return await message.util.reply( + `${this.client.util.emojis.success} Removed **${/* guildCommandCount */ guildCommands.size}** guild commands and **${ + globalCommands.size + }** global commands.` + ); + } else if (['drop down', 'drop downs', 'select menu', 'select menus'].includes(args?.feature?.toLowerCase())) { + + } + return await message.util.reply(responses[Math.floor(Math.random() * responses.length)]); + } +} |