diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arguments/contentWithDuration.ts | 6 | ||||
-rw-r--r-- | src/arguments/discordEmoji.ts | 9 | ||||
-rw-r--r-- | src/arguments/duration.ts | 4 | ||||
-rw-r--r-- | src/arguments/snowflake.ts | 8 | ||||
-rw-r--r-- | src/commands/config/features.ts | 29 | ||||
-rw-r--r-- | src/commands/config/settings.ts | 25 | ||||
-rw-r--r-- | src/commands/utilities/steal.ts | 50 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClient.ts | 6 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushCommand.ts | 11 | ||||
-rw-r--r-- | src/lib/models/Guild.ts | 34 | ||||
-rw-r--r-- | src/lib/utils/BushConstants.ts | 15 |
11 files changed, 155 insertions, 42 deletions
diff --git a/src/arguments/contentWithDuration.ts b/src/arguments/contentWithDuration.ts index 314b761..38b3fa4 100644 --- a/src/arguments/contentWithDuration.ts +++ b/src/arguments/contentWithDuration.ts @@ -1,8 +1,8 @@ -import { BushArgumentTypeCaster, BushMessage } from '@lib'; +import { BushArgumentTypeCaster } from '@lib'; export const contentWithDurationTypeCaster: BushArgumentTypeCaster = async ( - _message: BushMessage, - phrase: string + _, + phrase ): Promise<{ duration: number; contentWithoutTime: string | null }> => { return client.util.parseDuration(phrase); }; diff --git a/src/arguments/discordEmoji.ts b/src/arguments/discordEmoji.ts new file mode 100644 index 0000000..47e734d --- /dev/null +++ b/src/arguments/discordEmoji.ts @@ -0,0 +1,9 @@ +import { Snowflake } from 'discord-api-types'; +import { BushArgumentTypeCaster } from '../lib'; + +export const discordEmojiTypeCaster: BushArgumentTypeCaster = (_, phrase): { name: string; id: Snowflake } | null => { + if (!phrase) return null; + const validEmoji: RegExpExecArray | null = client.consts.regex.discordEmoji.exec(phrase); + if (!validEmoji || !validEmoji.groups) return null; + return { name: validEmoji.groups.name, id: validEmoji.groups.id }; +}; diff --git a/src/arguments/duration.ts b/src/arguments/duration.ts index ce181e8..6e76034 100644 --- a/src/arguments/duration.ts +++ b/src/arguments/duration.ts @@ -1,5 +1,5 @@ -import { BushArgumentTypeCaster, BushMessage } from '@lib'; +import { BushArgumentTypeCaster } from '@lib'; -export const durationTypeCaster: BushArgumentTypeCaster = (_message: BushMessage, phrase): number => { +export const durationTypeCaster: BushArgumentTypeCaster = (_, phrase): number => { return client.util.parseDuration(phrase).duration; }; diff --git a/src/arguments/snowflake.ts b/src/arguments/snowflake.ts new file mode 100644 index 0000000..0e6136f --- /dev/null +++ b/src/arguments/snowflake.ts @@ -0,0 +1,8 @@ +import { Snowflake } from 'discord.js'; +import { BushArgumentTypeCaster } from '../lib'; + +export const snowflakeTypeCaster: BushArgumentTypeCaster = (_, phrase): Snowflake | null => { + if (!phrase) return null; + if (client.consts.regex.snowflake.test(phrase)) return phrase; + return null; +}; diff --git a/src/commands/config/features.ts b/src/commands/config/features.ts new file mode 100644 index 0000000..0547bd0 --- /dev/null +++ b/src/commands/config/features.ts @@ -0,0 +1,29 @@ +// import { BushCommand, BushMessage, BushSlashMessage, guildFeatures } from '@lib'; +// import { MessageEmbed } from 'discord.js'; + +// export default class FeaturesCommand extends BushCommand { +// public constructor() { +// super('features', { +// aliases: ['features'], +// category: 'config', +// description: { +// content: 'Toggle features the server.', +// usage: 'features', +// examples: ['features'] +// }, +// slash: true, +// channel: 'guild', +// clientPermissions: ['SEND_MESSAGES', 'EMBED_LINKS'], +// userPermissions: ['SEND_MESSAGES', 'MANAGE_GUILD'] +// }); +// } +// public override async exec(message: BushMessage | BushSlashMessage): Promise<unknown> { +// if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`); +// const featureEmbed = new MessageEmbed().setTitle(`${message.guild.name}'s Features`).setColor(util.colors.default); +// const featureList: string[] = []; +// const enabledFeatures = message.guild.getSetting('enabledFeatures'); +// guildFeatures.forEach(feature => { +// featureList.push(`${}`) +// }) +// } +// } diff --git a/src/commands/config/settings.ts b/src/commands/config/settings.ts index f474804..0b71629 100644 --- a/src/commands/config/settings.ts +++ b/src/commands/config/settings.ts @@ -1,28 +1,28 @@ -// import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; +// import { BushCommand, BushMessage, BushSlashMessage, guildSettings } from '@lib'; // export default class SettingsCommand extends BushCommand { // public constructor() { // super('settings', { -// aliases: ['settings'], +// aliases: ['settings', 'settings', 'configure', 'config'], // category: 'config', // description: { -// content: 'Configure options for ', -// usage: 'template <requiredArg> [optionalArg]', +// content: 'Configure server options. Hint this is easier to use with the slash command.', +// usage: 'config <\'add\'|\'remove\'|\'toggle\'> <setting>', // examples: ['template 1 2'] // }, // args: [ // { -// id: 'required_argument', -// type: 'string', +// id: 'action', +// customType: ['add', 'remove', 'toggle'], // prompt: { -// start: 'What would you like to set your first argument to be?', -// retry: '{error} Pick a valid argument.', +// start: 'What action would you like to perform, it can be `add`, `remove`, or `toggle`.', +// retry: '{error} Choose a either `add`, `remove`, or `toggle`.', // optional: false // } // }, // { -// id: 'optional_argument', -// type: 'string', +// id: 'setting', +// customType: Object.keys(guildSettings), // prompt: { // start: 'What would you like to set your second argument to be?', // retry: '{error} Pick a valid argument.', @@ -30,7 +30,7 @@ // } // } // ], -// slash: false, //set this to true +// slash: true, // slashOptions: [ // { // name: 'required_argument', @@ -45,10 +45,7 @@ // required: false // } // ], -// superUserOnly: true, -// ownerOnly: true, // channel: 'guild', -// hidden: true, // clientPermissions: ['SEND_MESSAGES'], // userPermissions: ['SEND_MESSAGES'] // }); diff --git a/src/commands/utilities/steal.ts b/src/commands/utilities/steal.ts index 92abcb2..01c39ea 100644 --- a/src/commands/utilities/steal.ts +++ b/src/commands/utilities/steal.ts @@ -1,5 +1,5 @@ import { BushCommand, BushMessage } from '@lib'; -import { Emoji } from 'discord.js'; +import { Snowflake } from 'discord-api-types'; export default class StealCommand extends BushCommand { public constructor() { @@ -8,20 +8,22 @@ export default class StealCommand extends BushCommand { category: 'utilities', description: { content: 'Steal an emoji from another server and add it to your own.', - usage: 'steal <emoji/url> [--name name]', - examples: ['steal <:omegaclown:782630946435366942> --name ironm00n'] + usage: 'steal <emoji/emoji id/url> [name]', + examples: ['steal <:omegaclown:782630946435366942> ironm00n'] }, args: [ { - id: 'emoji', - customType: util.arg.union('emoji', 'url'), + id: 'emojiOrName', + customType: util.arg.union('discordEmoji', 'snowflake', 'url'), prompt: { start: 'What emoji would you like to steal?', - retry: '{error} Pick a valid emoji.', + retry: '{error} Pick a valid emoji, emoji id, or image url.', optional: true } }, - { id: 'name', match: 'option', flag: '--name', default: 'stolen_emoji' } + { + id: 'name2' + } ], slash: false, channel: 'guild', @@ -29,22 +31,38 @@ export default class StealCommand extends BushCommand { userPermissions: ['SEND_MESSAGES', 'MANAGE_EMOJIS_AND_STICKERS'] }); } - public override async exec(message: BushMessage, args: { emoji?: URL | Emoji; name: string }): Promise<unknown> { - if ((!args || !args.emoji) && !message.attachments.size) + public override async exec( + message: BushMessage, + args?: { emojiOrName?: { name: string; id: Snowflake } | Snowflake | URL | string; name2: string } + ): Promise<unknown> { + if ((!args || !args.emojiOrName) && !message.attachments.size) return await message.util.reply(`${util.emojis.error} You must provide an emoji to steal.`); + const image = - message.attachments.size && message.attachments.first()!.contentType?.includes('image/') + message.attachments.size && message.attachments.first()?.contentType?.includes('image/') ? message.attachments.first()!.url - : args?.emoji instanceof Emoji - ? `https://cdn.discordapp.com/emojis/${args.emoji.id}` - : args?.emoji instanceof URL - ? args.emoji.href + : args?.emojiOrName instanceof URL + ? args.emojiOrName.href + : typeof args?.emojiOrName === 'object' + ? `https://cdn.discordapp.com/emojis/${args.emojiOrName.id}` + : client.consts.regex.snowflake.test(args?.emojiOrName ?? '') + ? `https://cdn.discordapp.com/emojis/${args!.emojiOrName}` : undefined; - if (!image) return await message.util.reply(`${util.emojis.error} You must provide an emoji to steal.`); + if (image === undefined) return await message.util.reply(`${util.emojis.error} You must provide an emoji to steal.`); + if (message.attachments.size && typeof args?.emojiOrName !== 'string') + return await message.util.reply(`${util.emojis.error} You cannot attach an image and provide an argument.`); + + const emojiName = message.attachments.size + ? (args?.emojiOrName as string) ?? 'stolen_emoji' + : args?.emojiOrName instanceof URL + ? args?.name2 ?? 'stolen_emoji' + : typeof args?.emojiOrName === 'object' + ? args?.name2 ?? args.emojiOrName.name ?? 'stolen_emoji' + : 'stolen_emoji'; const creationSuccess = await message - .guild!.emojis.create(image, args.name, { + .guild!.emojis.create(image, emojiName, { reason: `Stolen by ${message.author.tag} (${message.author.id})` }) .catch((e: Error) => e); diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index 3feae96..ee92ded 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -21,8 +21,10 @@ import { exit } from 'process'; import readline from 'readline'; import { Sequelize } from 'sequelize'; import { contentWithDurationTypeCaster } from '../../../arguments/contentWithDuration'; +import { discordEmojiTypeCaster } from '../../../arguments/discordEmoji'; import { durationTypeCaster } from '../../../arguments/duration'; import { permissionTypeCaster } from '../../../arguments/permission'; +import { snowflakeTypeCaster } from '../../../arguments/snowflake'; import { UpdateCacheTask } from '../../../tasks/updateCache'; import { ActivePunishment } from '../../models/ActivePunishment'; import { Global } from '../../models/Global'; @@ -250,7 +252,9 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re this.commandHandler.resolver.addTypes({ duration: durationTypeCaster, contentWithDuration: contentWithDurationTypeCaster, - permission: permissionTypeCaster + permission: permissionTypeCaster, + snowflake: snowflakeTypeCaster, + discordEmoji: discordEmojiTypeCaster }); // loads all the handlers const loaders = { diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts index 0eaa5e0..7ecb679 100644 --- a/src/lib/extensions/discord-akairo/BushCommand.ts +++ b/src/lib/extensions/discord-akairo/BushCommand.ts @@ -6,7 +6,7 @@ import { BushClient } from './BushClient'; import { BushCommandHandler } from './BushCommandHandler'; import { BushSlashMessage } from './BushSlashMessage'; -export type BushArgumentType = +export type BaseBushArgumentType = | 'string' | 'lowercase' | 'uppercase' @@ -61,7 +61,12 @@ export type BushArgumentType = | 'listener' | 'duration' | 'contentWithDuration' - | 'permission'; + | 'permission' + | 'snowflake' + | 'discordEmoji'; + +export type BushArgumentType = BaseBushArgumentType | RegExp; + interface BaseBushArgumentOptions extends Omit<ArgumentOptions, 'type'> { id: string; description?: string; @@ -116,7 +121,7 @@ export interface BushArgumentOptions extends BaseBushArgumentOptions { * - `contentWithDuration` tries to parse duration in milliseconds and returns the remaining content with the duration * removed */ - type?: BushArgumentType; + type?: BushArgumentType | BaseBushArgumentType[]; } export interface CustomBushArgumentOptions extends BaseBushArgumentOptions { /** diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts index 3473ea4..dfba90c 100644 --- a/src/lib/models/Guild.ts +++ b/src/lib/models/Guild.ts @@ -15,6 +15,7 @@ export interface GuildModel { disabledCommands: string[]; lockdownChannels: Snowflake[]; autoModPhases: string[]; + enabledFeatures: string[]; } export interface GuildModelCreationAttributes { @@ -29,8 +30,20 @@ export interface GuildModelCreationAttributes { disabledCommands?: string[]; lockdownChannels?: Snowflake[]; autoModPhases?: string[]; + enabledFeatures?: string[]; } +export const guildSettings = { + prefix: { type: 'string' }, + autoPublishChannels: { type: 'channel-array' }, + welcomeChannel: { type: 'channel-array' }, + muteRole: { type: 'role' }, + punishmentEnding: { type: 'string' }, + lockdownChannels: { type: 'channel-array' } +}; + +export const guildFeatures = ['automodEnabled', 'supportThreads', 'stickyRoles']; + const NEVER_USED = 'This should never be executed'; export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> implements GuildModel { @@ -144,6 +157,16 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i throw new Error(NEVER_USED); } + /** + * The features enabled in a guild + */ + public get enabledFeatures(): string[] { + throw new Error(NEVER_USED); + } + public set enabledFeatures(_: string[]) { + throw new Error(NEVER_USED); + } + public static initModel(sequelize: Sequelize, client: BushClient): void { Guild.init( { @@ -233,6 +256,17 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i }, allowNull: false, defaultValue: '[]' + }, + enabledFeatures: { + type: DataTypes.TEXT, + get: function () { + return JSON.parse(this.getDataValue('enabledFeatures') as unknown as string); + }, + set: function (val: string[]) { + return this.setDataValue('enabledFeatures', JSON.stringify(val) as unknown as string[]); + }, + allowNull: false, + defaultValue: '[]' } }, { sequelize: sequelize } diff --git a/src/lib/utils/BushConstants.ts b/src/lib/utils/BushConstants.ts index 68393c4..bcc34ae 100644 --- a/src/lib/utils/BushConstants.ts +++ b/src/lib/utils/BushConstants.ts @@ -21,12 +21,13 @@ interface bushColors { black: '#000000'; orange: '#E86100'; } + export class BushConstants { public static emojis = { - success: '<:checkmark:837109864101707807>', + success: '<:success:837109864101707807>', warn: '<:warn:848726900876247050>', error: '<:error:837123021016924261>', - successFull: '<:checkmark_full:850118767576088646>', + successFull: '<:success_full:850118767576088646>', warnFull: '<:warn_full:850118767391539312>', errorFull: '<:error_full:850118767295201350>', mad: '<:mad:783046135392239626>', @@ -36,7 +37,9 @@ export class BushConstants { offlineCircle: '<:offline:787550565382750239>', dndCircle: '<:dnd:787550487633330176>', idleCircle: '<:idle:787550520956551218>', - onlineCircle: '<:online:787550449435803658>' + onlineCircle: '<:online:787550449435803658>', + cross: '<:cross:878319362539421777>', + check: '' }; public static colors: bushColors = { @@ -99,6 +102,12 @@ export class BushConstants { } }; + public static regex = { + snowflake: /\d{15,21}/im, + // eslint-disable-next-line no-useless-escape + discordEmoji: /<a?:(?<name>[a-zA-Z0-9\_]+):(?<id>\d{15,21})>/im + }; + /** A bunch of mappings */ public static mappings = { guilds: { |