aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/nodejs.yml2
-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.ts355
-rw-r--r--src/commands/dev/say.ts13
-rw-r--r--src/commands/dev/test.ts154
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts6
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts20
-rw-r--r--src/lib/extensions/discord-akairo/BushCommand.ts21
-rw-r--r--src/lib/models/Guild.ts14
-rw-r--r--src/listeners/client/interactionCreate.ts2
-rw-r--r--src/listeners/commands/commandBlocked.ts2
-rw-r--r--src/listeners/commands/commandError.ts2
-rw-r--r--src/listeners/commands/commandMissingPermissions.ts2
-rw-r--r--src/listeners/commands/commandStarted.ts2
-rw-r--r--src/listeners/commands/slashBlocked.ts2
-rw-r--r--src/listeners/commands/slashCommandError.ts2
-rw-r--r--src/listeners/commands/slashMissingPermissions.ts2
-rw-r--r--src/listeners/commands/slashStarted.ts2
-rw-r--r--src/listeners/guild/syncUnban.ts2
-rw-r--r--src/listeners/message/automodCreate.ts16
-rw-r--r--src/listeners/message/automodUpdate.ts17
-rw-r--r--src/listeners/message/level.ts9
-rw-r--r--yarn.lock22
23 files changed, 397 insertions, 286 deletions
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index 7fc5058..483ee6f 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -71,7 +71,7 @@ jobs:
yarn format
git commit -am "Automatically format code" || true
- name: Push changes
- uses: ad-m/github-push-action@master
+ uses: NotEnoughUpdates/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
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)]);
+ }
+}
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index 8496d2a..3caae38 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -3,13 +3,15 @@ import { AkairoClient } from 'discord-akairo';
import {
Guild,
Intents,
+ InteractionReplyOptions,
Message,
MessageEditOptions,
MessageOptions,
MessagePayload,
ReplyMessageOptions,
Snowflake,
- Structures
+ Structures,
+ WebhookEditMessageOptions
} from 'discord.js';
import * as path from 'path';
import { exit } from 'process';
@@ -57,6 +59,8 @@ import { BushTaskHandler } from './BushTaskHandler';
export type BushReplyMessageType = string | MessagePayload | ReplyMessageOptions;
export type BushEditMessageType = string | MessageEditOptions | MessagePayload;
+export type BushSlashSendMessageType = string | MessagePayload | InteractionReplyOptions
+export type BushSlashEditMessageType = string | MessagePayload | WebhookEditMessageOptions
export type BushSendMessageType = string | MessagePayload | MessageOptions;
export type BushThreadMemberResolvable = BushThreadMember | BushUserResolvable;
export type BushUserResolvable = BushUser | Snowflake | BushMessage | BushGuildMember | BushThreadMember;
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index 306e049..3a50480 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -31,12 +31,11 @@ import {
MessageEditOptions,
MessageEmbed,
MessageOptions,
- MessagePayload,
+
Snowflake,
TextChannel,
User,
- Util,
- WebhookEditMessageOptions
+ Util
} from 'discord.js';
import got from 'got';
import humanizeDuration from 'humanize-duration';
@@ -44,7 +43,7 @@ import { promisify } from 'util';
import { ActivePunishment, ActivePunishmentType } from '../../models/ActivePunishment';
import { BushNewsChannel } from '../discord.js/BushNewsChannel';
import { BushTextChannel } from '../discord.js/BushTextChannel';
-import { BushUserResolvable } from './BushClient';
+import { BushSlashEditMessageType, BushSlashSendMessageType, BushUserResolvable } from './BushClient';
interface hastebinRes {
key: string;
@@ -458,9 +457,9 @@ export class BushClientUtil extends ClientUtil {
let hasteOut = '';
const tildes = '```';
const formattingLength = 2 * tildes.length + language.length + 2 * '\n'.length;
- if (code.length + formattingLength > length) hasteOut = 'Too large to display. Hastebin: ' + (await this.haste(code));
+ if (code.length + formattingLength >= length) hasteOut = 'Too large to display. Hastebin: ' + (await this.haste(code));
- const code2 = code.length > length ? code.substring(0, length - (hasteOut.length + '\n'.length + formattingLength)) : code;
+ const code2 = hasteOut ? code.substring(0, length - (hasteOut.length + '\n'.length + formattingLength)) : code;
return (
tildes + language + '\n' + Util.cleanCodeBlockContent(code2) + '\n' + tildes + (hasteOut.length ? '\n' + hasteOut : '')
);
@@ -468,9 +467,9 @@ export class BushClientUtil extends ClientUtil {
public async slashRespond(
interaction: CommandInteraction,
- responseOptions: string | MessagePayload | WebhookEditMessageOptions
+ responseOptions: BushSlashSendMessageType|BushSlashEditMessageType
): Promise<Message | APIMessage> {
- let newResponseOptions: string | MessagePayload | WebhookEditMessageOptions = {};
+ let newResponseOptions: BushSlashSendMessageType|BushSlashEditMessageType = {};
if (typeof responseOptions === 'string') {
newResponseOptions.content = responseOptions;
} else {
@@ -751,4 +750,9 @@ export class BushClientUtil extends ClientUtil {
/* eslint-disable @typescript-eslint/no-unused-vars */
public async lockdownChannel(options: { channel: BushTextChannel | BushNewsChannel; moderator: BushUserResolvable }) {}
/* eslint-enable @typescript-eslint/no-unused-vars */
+
+ public async automod(message: BushMessage) {
+ const autoModPhases = await message.guild.getSetting('autoModPhases');
+ if (autoModPhases.includes(message.content.toString()) && message.deletable) message.delete()
+ }
}
diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts
index 6cf981b..0127a59 100644
--- a/src/lib/extensions/discord-akairo/BushCommand.ts
+++ b/src/lib/extensions/discord-akairo/BushCommand.ts
@@ -44,6 +44,10 @@ type BushArgumentType =
| 'newsChannels'
| 'storeChannel'
| 'storeChannels'
+ | 'stageChannel'
+ | 'stageChannels'
+ | 'threadChannel'
+ | 'threadChannels'
| 'role'
| 'roles'
| 'emoji'
@@ -63,17 +67,19 @@ type BushArgumentType =
| 'command'
| 'inhibitor'
| 'listener'
- | 'duration'
- | (string | string[])[]
- | RegExp
- | string;
+ | 'duration';
-export interface BushArgumentOptions extends ArgumentOptions {
- type?: BushArgumentType | ArgumentTypeCaster;
+interface BaseBushArgumentOptions extends ArgumentOptions {
id: string;
description?: string;
prompt?: ArgumentPromptOptions;
}
+export interface BushArgumentOptions extends BaseBushArgumentOptions {
+ type?: BushArgumentType;
+}
+export interface CustomBushArgumentOptions extends BaseBushArgumentOptions {
+ type?: ArgumentTypeCaster | (string | string[])[] | RegExp | string;
+}
export interface BushCommandOptions extends CommandOptions {
hidden?: boolean;
@@ -84,7 +90,7 @@ export interface BushCommandOptions extends CommandOptions {
usage: string | string[];
examples: string | string[];
};
- args?: BushArgumentOptions[] | ArgumentGenerator;
+ args?: BushArgumentOptions[] | CustomBushArgumentOptions[] | ArgumentGenerator;
category: string;
completelyHide?: boolean;
}
@@ -110,6 +116,7 @@ export class BushCommand extends Command {
public constructor(id: string, options?: BushCommandOptions) {
super(id, options);
+ options.category;
this.options = options;
this.hidden = options.hidden || false;
this.restrictedChannels = options.restrictedChannels;
diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts
index f8ebe46..3972259 100644
--- a/src/lib/models/Guild.ts
+++ b/src/lib/models/Guild.ts
@@ -14,6 +14,7 @@ export interface GuildModel {
punishmentEnding: string;
disabledCommands: string[];
lockdownChannels: Snowflake[];
+ autoModPhases: string[]
}
export interface GuildModelCreationAttributes {
@@ -27,6 +28,7 @@ export interface GuildModelCreationAttributes {
punishmentEnding?: string;
disabledCommands?: string[];
lockdownChannels?: Snowflake[];
+ autoModPhases?: string[]
}
export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> implements GuildModel {
@@ -40,6 +42,7 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i
punishmentEnding: string;
disabledCommands: string[];
lockdownChannels: Snowflake[];
+ autoModPhases: string[]
static initModel(sequelize: Sequelize, client: BushClient): void {
Guild.init(
@@ -119,6 +122,17 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i
},
allowNull: false,
defaultValue: '[]'
+ },
+ autoModPhases: {
+ type: DataTypes.TEXT,
+ get: function () {
+ return JSON.parse(this.getDataValue('autoModPhases') as unknown as string);
+ },
+ set: function (val: string[]) {
+ return this.setDataValue('autoModPhases', JSON.stringify(val) as unknown as string[]);
+ },
+ allowNull: false,
+ defaultValue: '[]'
}
},
{ sequelize: sequelize }
diff --git a/src/listeners/client/interactionCreate.ts b/src/listeners/client/interactionCreate.ts
index 0e77fea..0503f2e 100644
--- a/src/listeners/client/interactionCreate.ts
+++ b/src/listeners/client/interactionCreate.ts
@@ -10,7 +10,7 @@ export default class InteractionCreateListener extends BushListener {
});
}
- async exec([interaction]: ClientEvents['interactionCreate']): Promise<unknown> {
+ async exec(...[interaction]: ClientEvents['interactionCreate']): Promise<unknown> {
if (!interaction) return;
if (interaction.isCommand()) {
this.client.console.info(
diff --git a/src/listeners/commands/commandBlocked.ts b/src/listeners/commands/commandBlocked.ts
index c02f21c..e75610b 100644
--- a/src/listeners/commands/commandBlocked.ts
+++ b/src/listeners/commands/commandBlocked.ts
@@ -8,7 +8,7 @@ export default class CommandBlockedListener extends BushListener {
});
}
- public async exec([message, command, reason]: BushCommandHandlerEvents['commandBlocked']): Promise<unknown> {
+ public async exec(...[message, command, reason]: BushCommandHandlerEvents['commandBlocked']): Promise<unknown> {
this.client.console.info(
'CommandBlocked',
`<<${message.author.tag}>> tried to run <<${message.util.parsed.command}>> but was blocked because <<${reason}>>.`,
diff --git a/src/listeners/commands/commandError.ts b/src/listeners/commands/commandError.ts
index 1aaefad..6de764c 100644
--- a/src/listeners/commands/commandError.ts
+++ b/src/listeners/commands/commandError.ts
@@ -10,7 +10,7 @@ export default class CommandErrorListener extends BushListener {
});
}
- public async exec([error, message, command]: BushCommandHandlerEvents['error']): Promise<void> {
+ public async exec(...[error, message, command]: BushCommandHandlerEvents['error']): Promise<void> {
const errorNo = Math.floor(Math.random() * 6969696969) + 69; // hehe funny number
const errorEmbed: MessageEmbed = new MessageEmbed()
.setTitle(`Error # \`${errorNo}\`: An error occurred`)
diff --git a/src/listeners/commands/commandMissingPermissions.ts b/src/listeners/commands/commandMissingPermissions.ts
index 765bc72..e06f8f8 100644
--- a/src/listeners/commands/commandMissingPermissions.ts
+++ b/src/listeners/commands/commandMissingPermissions.ts
@@ -9,7 +9,7 @@ export default class CommandMissingPermissionsListener extends BushListener {
});
}
- public async exec([message, command, type, missing]: BushCommandHandlerEvents['missingPermissions']): Promise<void> {
+ public async exec(...[message, command, type, missing]: BushCommandHandlerEvents['missingPermissions']): Promise<void> {
const niceMissing = [];
missing.forEach((missing) => {
if (this.client.consts.mappings.permissions[missing]) {
diff --git a/src/listeners/commands/commandStarted.ts b/src/listeners/commands/commandStarted.ts
index dcc1d83..421da02 100644
--- a/src/listeners/commands/commandStarted.ts
+++ b/src/listeners/commands/commandStarted.ts
@@ -8,7 +8,7 @@ export default class CommandStartedListener extends BushListener {
category: 'commands'
});
}
- exec([message, command]: BushCommandHandlerEvents['commandStarted']): void {
+ exec(...[message, command]: BushCommandHandlerEvents['commandStarted']): void {
this.client.logger.info(
'Command',
`The <<${command.id}>> command was used by <<${message.author.tag}>> in ${
diff --git a/src/listeners/commands/slashBlocked.ts b/src/listeners/commands/slashBlocked.ts
index ecbe863..e59235e 100644
--- a/src/listeners/commands/slashBlocked.ts
+++ b/src/listeners/commands/slashBlocked.ts
@@ -9,7 +9,7 @@ export default class SlashBlockedListener extends BushListener {
});
}
- public async exec([message, command, reason]: BushCommandHandlerEvents['slashBlocked']): Promise<unknown> {
+ public async exec(...[message, command, reason]: BushCommandHandlerEvents['slashBlocked']): Promise<unknown> {
this.client.console.info(
'SlashBlocked',
`<<${message.author.tag}>> tried to run <<${message.util.parsed.command}>> but was blocked because <<${reason}>>.`,
diff --git a/src/listeners/commands/slashCommandError.ts b/src/listeners/commands/slashCommandError.ts
index 4eaf293..03ba899 100644
--- a/src/listeners/commands/slashCommandError.ts
+++ b/src/listeners/commands/slashCommandError.ts
@@ -10,7 +10,7 @@ export default class SlashCommandErrorListener extends BushListener {
category: 'commands'
});
}
- async exec([error, message, command]: BushCommandHandlerEvents['slashError']): Promise<void> {
+ async exec(...[error, message, command]: BushCommandHandlerEvents['slashError']): Promise<void> {
const errorNo = Math.floor(Math.random() * 6969696969) + 69; // hehe funny number
const errorEmbed: MessageEmbed = new MessageEmbed()
.setTitle(`Slash Error # \`${errorNo}\`: An error occurred`)
diff --git a/src/listeners/commands/slashMissingPermissions.ts b/src/listeners/commands/slashMissingPermissions.ts
index 45966bb..a41dd8f 100644
--- a/src/listeners/commands/slashMissingPermissions.ts
+++ b/src/listeners/commands/slashMissingPermissions.ts
@@ -9,7 +9,7 @@ export default class SlashMissingPermissionsListener extends BushListener {
});
}
- public async exec([message, command, type, missing]: BushCommandHandlerEvents['slashMissingPermissions']): Promise<void> {
+ public async exec(...[message, command, type, missing]: BushCommandHandlerEvents['slashMissingPermissions']): Promise<void> {
const niceMissing = [];
missing.forEach((missing) => {
if (this.client.consts.mappings.permissions[missing]) {
diff --git a/src/listeners/commands/slashStarted.ts b/src/listeners/commands/slashStarted.ts
index f49f5dd..2a89b03 100644
--- a/src/listeners/commands/slashStarted.ts
+++ b/src/listeners/commands/slashStarted.ts
@@ -8,7 +8,7 @@ export default class SlashStartedListener extends BushListener {
category: 'commands'
});
}
- async exec([message, command]: BushCommandHandlerEvents['slashStarted']): Promise<unknown> {
+ async exec(...[message, command]: BushCommandHandlerEvents['slashStarted']): Promise<unknown> {
return await this.client.logger.info(
'SlashCommand',
`The <<${command.id}>> command was used by <<${message.author.tag}>> in ${
diff --git a/src/listeners/guild/syncUnban.ts b/src/listeners/guild/syncUnban.ts
index c9ba0cb..389aae6 100644
--- a/src/listeners/guild/syncUnban.ts
+++ b/src/listeners/guild/syncUnban.ts
@@ -9,7 +9,7 @@ export default class SyncUnbanListener extends BushListener {
});
}
- public async exec([ban]: ClientEvents['guildBanRemove']): Promise<void> {
+ public async exec(...[ban]: ClientEvents['guildBanRemove']): Promise<void> {
const bans = await ActivePunishment.findAll({
where: {
user: ban.user,
diff --git a/src/listeners/message/automodCreate.ts b/src/listeners/message/automodCreate.ts
new file mode 100644
index 0000000..f1c4ccd
--- /dev/null
+++ b/src/listeners/message/automodCreate.ts
@@ -0,0 +1,16 @@
+import { BushListener, BushMessage } from '@lib';
+import { ClientEvents } from 'discord.js';
+
+export default class AutomodMessageCreateListener extends BushListener {
+ public constructor() {
+ super('automodCreate', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ async exec(...[message]: ClientEvents['messageCreate']): Promise<void> {
+ return await this.client.util.automod(message as BushMessage)
+ }
+}
diff --git a/src/listeners/message/automodUpdate.ts b/src/listeners/message/automodUpdate.ts
new file mode 100644
index 0000000..37e00bf
--- /dev/null
+++ b/src/listeners/message/automodUpdate.ts
@@ -0,0 +1,17 @@
+import { BushListener, BushMessage } from '@lib';
+import { ClientEvents, Message } from 'discord.js';
+
+export default class AutomodMessageUpdateListener extends BushListener {
+ public constructor() {
+ super('automodUpdate', {
+ emitter: 'client',
+ event: 'messageUpdate',
+ category: 'message'
+ });
+ }
+
+ async exec(...[message]: ClientEvents['messageUpdate']): Promise<void> {
+ const fullMessage = message.partial ? await message.fetch() : (message as Message);
+ return await this.client.util.automod(fullMessage as BushMessage);
+ }
+}
diff --git a/src/listeners/message/level.ts b/src/listeners/message/level.ts
index b06fdd2..1ff098e 100644
--- a/src/listeners/message/level.ts
+++ b/src/listeners/message/level.ts
@@ -1,5 +1,5 @@
-import { BushListener, Level } from '@lib';
-import { Message, MessageType } from 'discord.js';
+import { BushCommandHandlerEvents, BushListener, Level } from '@lib';
+import { MessageType } from 'discord.js';
export default class LevelListener extends BushListener {
private levelCooldowns: Set<string> = new Set();
@@ -7,10 +7,11 @@ export default class LevelListener extends BushListener {
public constructor() {
super('level', {
emitter: 'commandHandler',
- event: 'messageInvalid' // Using messageInvalid here so commands don't give xp
+ event: 'messageInvalid', // Using messageInvalid here so commands don't give xp
+ category: 'message'
});
}
- async exec(message: Message): Promise<void> {
+ async exec(...[message]: BushCommandHandlerEvents['messageInvalid']): Promise<void> {
if (message.author.bot) return;
if (!message.author) return;
if (!message.guild) return;
diff --git a/yarn.lock b/yarn.lock
index dd518d7..5fbf178 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -329,16 +329,16 @@ __metadata:
linkType: hard
"@types/node@npm:*":
- version: 16.4.1
- resolution: "@types/node@npm:16.4.1"
- checksum: 6cff78c802a1efecc900506a468a9bdaa321c7132a05e87552ab710f3d3a5cd230308317634f94b8db4833c66c72a765b28670d5ccf8c7c5a7363fcce32d1b1e
+ version: 16.4.2
+ resolution: "@types/node@npm:16.4.2"
+ checksum: d9b02aeb2b9633a8f0e18bd9d322a3ff6c937715b96ad1c80b5f941c46a3f97f2419ffabdb44a3c9305e7b82579aef852f0adfa2e755b7ab32d4334a4ca070c7
languageName: node
linkType: hard
"@types/node@npm:^14.14.22":
- version: 14.17.5
- resolution: "@types/node@npm:14.17.5"
- checksum: 8fba22a8df7bcea75039f08e00fcff8e331f6d367739a9631d3457bc3e8e5ddfdd60e1a5d685d9420312e9ed7cf2f2146d37224ec9f7d578fe8dd32ce3821e62
+ version: 14.17.6
+ resolution: "@types/node@npm:14.17.6"
+ checksum: 19b11f3c49689d1ffd2b7b534a49ab7daca18ce702cce9d9b5d28d60e79de94367339217f602053d0353170a9e02f7ad2d5cd796200977dc176d6d7ba376cf09
languageName: node
linkType: hard
@@ -1328,8 +1328,8 @@ __metadata:
discord-akairo@NotEnoughUpdates/discord-akairo:
version: 8.2.2
- resolution: "discord-akairo@https://github.com/NotEnoughUpdates/discord-akairo.git#commit=f31c8e8b27e1ca8c918cf10e720d36ba31fdd7dc"
- checksum: 193b6ca28637f542a1ee10090e3b54a83c36fdd188f746eb86881dee94b8b5d85c74a544c6febba274e49898f504ea84e224fa82ac41e60b06a98c8744c1258e
+ resolution: "discord-akairo@https://github.com/NotEnoughUpdates/discord-akairo.git#commit=6713144bb47502a1b721635ae98bdbfe19c9cb6a"
+ checksum: 2908b36cc03ff001ac0d6752e0d8050d25a43e74aaa9b455ed04088ee13293be9563a77c9cc944c94114cd35bdb4597c68a5b3b30fb2538ea224a01fa2f49e55
languageName: node
linkType: hard
@@ -3917,9 +3917,9 @@ resolve@^1.19.0:
linkType: hard
"tiny-typed-emitter@npm:^2.0.3":
- version: 2.0.3
- resolution: "tiny-typed-emitter@npm:2.0.3"
- checksum: 687387c9c395748e5c9c01e7ffea45d06ea2aaf0f1a7aac3e3552f8a116109b356400223bf97569ad3b9377caa8de26e375bad23823119a8b029293cfe8c2e3a
+ version: 2.1.0
+ resolution: "tiny-typed-emitter@npm:2.1.0"
+ checksum: 709bca410054e08df4dc29d5ea0916328bb2900d60245c6a743068ea223887d9fd2c945b6070eb20336275a557a36c2808e5c87d2ed4b60633458632be4a3e10
languageName: node
linkType: hard