diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/config/features.ts | 5 | ||||
-rw-r--r-- | src/commands/config/settings.ts | 168 | ||||
-rw-r--r-- | src/commands/dev/__template.ts | 7 | ||||
-rw-r--r-- | src/commands/dev/setLevel.ts | 6 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClientUtil.ts | 6 | ||||
-rw-r--r-- | src/lib/models/Guild.ts | 79 | ||||
-rw-r--r-- | src/listeners/client/interactionCreate.ts | 15 | ||||
-rw-r--r-- | src/listeners/commands/commandError.ts | 2 | ||||
-rw-r--r-- | src/listeners/message/automodCreate.ts | 9 | ||||
-rw-r--r-- | src/listeners/message/level.ts | 2 |
10 files changed, 203 insertions, 96 deletions
diff --git a/src/commands/config/features.ts b/src/commands/config/features.ts index 31facfc..9a5fa5b 100644 --- a/src/commands/config/features.ts +++ b/src/commands/config/features.ts @@ -1,7 +1,6 @@ import { BushCommand, BushMessage, BushSlashMessage, GuildFeatures, guildFeaturesArr, guildFeaturesObj } from '@lib'; import { Message, MessageActionRow, MessageEmbed, MessageSelectMenu, SelectMenuInteraction } from 'discord.js'; -//todo: fix this so that it doesn't just select one feature but instead toggles it export default class FeaturesCommand extends BushCommand { public constructor() { super('features', { @@ -36,7 +35,7 @@ export default class FeaturesCommand extends BushCommand { }); collector.on('collect', async (interaction: SelectMenuInteraction) => { - if (interaction.user.id == message.author.id || client.config.owners.includes(interaction.user.id)) { + if (interaction.user.id === message.author.id || client.config.owners.includes(interaction.user.id)) { if (!message.guild) throw new Error('message.guild is null'); const [selected]: GuildFeatures[] = interaction.values as GuildFeatures[]; @@ -84,7 +83,7 @@ export default class FeaturesCommand extends BushCommand { .setPlaceholder('Select A Feature to Toggle') .setMaxValues(1) .setMinValues(1) - .setCustomId('featureCommand_selectFeature') + .setCustomId('command_selectFeature') .setDisabled(disable) ); } diff --git a/src/commands/config/settings.ts b/src/commands/config/settings.ts index 0b71629..003e118 100644 --- a/src/commands/config/settings.ts +++ b/src/commands/config/settings.ts @@ -1,56 +1,114 @@ -// import { BushCommand, BushMessage, BushSlashMessage, guildSettings } from '@lib'; +import { BushCommand, BushMessage, BushSlashMessage, guildSettings } from '@lib'; +import { + Message, + MessageActionRow, + MessageButton, + MessageComponentInteraction, + MessageEmbed, + MessageOptions, + MessageSelectMenu +} from 'discord.js'; -// export default class SettingsCommand extends BushCommand { -// public constructor() { -// super('settings', { -// aliases: ['settings', 'settings', 'configure', 'config'], -// category: 'config', -// description: { -// 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: 'action', -// customType: ['add', 'remove', 'toggle'], -// prompt: { -// 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: 'setting', -// customType: Object.keys(guildSettings), -// prompt: { -// start: 'What would you like to set your second argument to be?', -// retry: '{error} Pick a valid argument.', -// optional: true -// } -// } -// ], -// slash: true, -// slashOptions: [ -// { -// name: 'required_argument', -// description: 'What would you like to set your first argument to be?', -// type: 'STRING', -// required: true -// }, -// { -// name: 'optional_argument', -// description: 'What would you like to set your second argument to be?', -// type: 'STRING', -// required: false -// } -// ], -// channel: 'guild', -// clientPermissions: ['SEND_MESSAGES'], -// userPermissions: ['SEND_MESSAGES'] -// }); -// } -// public override async exec(message: BushMessage | BushSlashMessage): Promise<unknown> { -// return await message.util.reply(`${util.emojis.error} Do not use the template command.`); -// } -// } +export default class SettingsCommand extends BushCommand { + public constructor() { + super('settings', { + aliases: ['settings', 'setting', 'configure', 'config'], + category: 'config', + description: { + content: 'Configure server options.', + usage: 'settings', + examples: ['settings'] + }, + slash: true, + channel: 'guild', + clientPermissions: ['SEND_MESSAGES'], + userPermissions: ['SEND_MESSAGES', 'MANAGE_GUILD'], + ownerOnly: true + }); + } + + 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 messageOptions = await this.generateMessageOptions(message); + const msg = (await message.util.reply(messageOptions)) as Message; + const collector = msg.createMessageComponentCollector({ + channel: message.channel ?? undefined, + guild: message.guild, + message: message as Message, + time: 300_000 + }); + + collector.on('collect', async (interaction: MessageComponentInteraction) => { + if (interaction.user.id === message.author.id || client.config.owners.includes(interaction.user.id)) { + if (!message.guild) throw new Error('message.guild is null'); + switch (interaction.customId) { + case 'command_settingsSel': { + if (!interaction.isSelectMenu()) return; + + return interaction.update( + await this.generateMessageOptions(message, interaction.values[0] as keyof typeof guildSettings) + ); + } + } + } else { + return await interaction?.deferUpdate().catch(() => undefined); + } + }); + } + + public async generateMessageOptions( + message: BushMessage | BushSlashMessage, + feature?: keyof typeof guildSettings + ): Promise<MessageOptions> { + if (!message.guild) throw new Error('message.guild is null'); + const settingsEmbed = new MessageEmbed().setTitle(`${message.guild!.name}'s Settings`).setColor(util.colors.default); + if (!feature) { + const settingsArr = Object.keys(guildSettings) as (keyof typeof guildSettings)[]; + const desc = settingsArr.map((s) => `**${guildSettings[s].name}**`).join('\n'); + settingsEmbed.setDescription(desc); + + const selMenu = new MessageActionRow().addComponents( + new MessageSelectMenu() + .addOptions( + ...settingsArr.map((s) => ({ + label: guildSettings[s].name, + value: s, + description: guildSettings[s].description + })) + ) + .setPlaceholder('Select A Setting to View') + .setMaxValues(1) + .setMinValues(1) + .setCustomId('command_settingsSel') + ); + return { embeds: [settingsEmbed], components: [selMenu] }; + } else { + const components = new MessageActionRow().addComponents( + new MessageButton().setStyle('PRIMARY').setCustomId('command_settingsBack').setLabel('Back') + ); + settingsEmbed.setDescription(guildSettings[feature].description); + switch (guildSettings[feature].type as 'string' | 'channel' | 'channel-array' | 'role' | 'role-array') { + case 'string': { + settingsEmbed.addField(guildSettings[feature].name, (await message.guild.getSetting(feature)).toString()); + settingsEmbed.setFooter( + `Run "${await message.guild.getSetting('prefix')}settings set ${feature} <value>" to set this setting.` + ); + return { embeds: [settingsEmbed], components: [components] }; + } + case 'channel': { + break; + } + case 'channel-array': { + break; + } + case 'role': { + break; + } + case 'role-array': { + break; + } + } + return {}; + } + } +} diff --git a/src/commands/dev/__template.ts b/src/commands/dev/__template.ts index be4f7a7..4cf407c 100644 --- a/src/commands/dev/__template.ts +++ b/src/commands/dev/__template.ts @@ -53,7 +53,12 @@ export default class TemplateCommand extends BushCommand { userPermissions: ['SEND_MESSAGES'] }); } - public override async exec(message: BushMessage | BushSlashMessage): Promise<unknown> { + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { required_argument: string; optional_argumen: string } + ): Promise<unknown> { return await message.util.reply(`${util.emojis.error} Do not use the template command.`); + args; } } diff --git a/src/commands/dev/setLevel.ts b/src/commands/dev/setLevel.ts index e69b9df..777ef60 100644 --- a/src/commands/dev/setLevel.ts +++ b/src/commands/dev/setLevel.ts @@ -55,15 +55,17 @@ export default class SetLevelCommand extends BushCommand { ): Promise<unknown> { if (!message.author.isOwner()) return await message.util.reply(`${util.emojis.error} Only my developers can run this command.`); + if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be run in a guild.`); + if (!user.id) throw new Error('user.id is null'); const [levelEntry] = await Level.findOrBuild({ where: { user: user.id, - guild: message.guild!.id + guild: message.guild.id }, defaults: { user: user.id, - guild: message.guild!.id + guild: message.guild.id } }); await levelEntry.update({ xp: Level.convertLevelToXp(level) }); diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts index da98dac..ef51b63 100644 --- a/src/lib/extensions/discord-akairo/BushClientUtil.ts +++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts @@ -1012,11 +1012,7 @@ export class BushClientUtil extends ClientUtil { * @param surroundChar2 - The character placed in the end of the element. Defaults to `surroundChar1`. */ public surroundArray(array: string[], surroundChar1: string, surroundChar2?: string): string[] { - const newArray: string[] = []; - array.forEach((a) => { - newArray.push(`${surroundChar1}${a}${surroundChar2 ?? surroundChar1}`); - }); - return newArray; + return array.map((a) => `${surroundChar1}${a}${surroundChar2 ?? surroundChar1}`); } public parseDuration(content: string, remove = true): { duration: number; contentWithoutTime: string | null } { diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts index 614bf15..66deddb 100644 --- a/src/lib/models/Guild.ts +++ b/src/lib/models/Guild.ts @@ -18,6 +18,7 @@ export interface GuildModel { autoModPhases: string[]; enabledFeatures: GuildFeatures[]; joinRoles: Snowflake[]; + automodLogChannel: Snowflake; } export interface GuildModelCreationAttributes { @@ -34,16 +35,58 @@ export interface GuildModelCreationAttributes { autoModPhases?: string[]; enabledFeatures?: GuildFeatures[]; joinRoles?: Snowflake[]; + automodLogChannel?: Snowflake; } export const guildSettings = { - prefix: { type: 'string' }, - autoPublishChannels: { type: 'channel-array' }, - welcomeChannel: { type: 'channel-array' }, - muteRole: { type: 'role' }, - punishmentEnding: { type: 'string' }, - lockdownChannels: { type: 'channel-array' }, - joinRoles: { type: 'role-array' } + prefix: { + name: 'Prefix', + description: 'description goes here', + type: 'string', + configurable: true + }, + autoPublishChannels: { + name: 'Auto Publish Channels', + description: 'description goes here', + type: 'channel-array', + configurable: true + }, + welcomeChannel: { + name: 'Welcome Channel', + description: 'description goes here', + type: 'channel-array', + configurable: true + }, + muteRole: { + name: 'Mute Role', + description: 'description goes here', + type: 'role', + configurable: true + }, + punishmentEnding: { + name: 'Punishment Ending', + description: 'description goes here', + type: 'string', + configurable: true + }, + lockdownChannels: { + name: 'Lockdown Channels', + description: 'description goes here', + type: 'channel-array', + configurable: false // not implemented yet + }, + joinRoles: { + name: 'Join Roles', + description: 'description goes here', + type: 'role-array', + configurable: true + }, + automodLogChannel: { + name: 'Automod Log Channel', + description: 'description goes here', + type: 'channel', + configurable: true + } }; export const guildFeaturesObj = { @@ -53,11 +96,11 @@ export const guildFeaturesObj = { }, autoPublish: { name: 'Auto Publish', - description: 'Auto publishes all messages in configured announcement channels.' + description: 'Publishes messages in configured announcement channels.' }, autoThread: { name: 'Auto Thread', - description: 'Automatically creates a new thread for every message in configured channels.' + description: 'Creates a new thread for messages in configured channels.' }, blacklistedFile: { name: 'Blacklisted File', @@ -73,7 +116,7 @@ export const guildFeaturesObj = { }, stickyRoles: { name: 'Sticky Roles', - description: "Stores users' roles when they leave the server and returns them when they rejoin." + description: 'Restores past roles to a user when they rejoin.' } }; @@ -211,6 +254,16 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i throw new Error(NEVER_USED); } + /** + * The channel to send automod logs to. + */ + public get automodLogChannel(): Snowflake { + throw new Error(NEVER_USED); + } + public set automodLogChannel(_: Snowflake) { + throw new Error(NEVER_USED); + } + public static initModel(sequelize: Sequelize, client: BushClient): void { Guild.init( { @@ -242,7 +295,11 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i lockdownChannels: jsonArrayInit('lockdownChannels'), autoModPhases: jsonArrayInit('autoModPhases'), enabledFeatures: jsonArrayInit('enabledFeatures'), - joinRoles: jsonArrayInit('joinRoles') + joinRoles: jsonArrayInit('joinRoles'), + automodLogChannel: { + type: DataTypes.STRING, + allowNull: true + } }, { sequelize: sequelize } ); diff --git a/src/listeners/client/interactionCreate.ts b/src/listeners/client/interactionCreate.ts index b4cc353..d2bc6b5 100644 --- a/src/listeners/client/interactionCreate.ts +++ b/src/listeners/client/interactionCreate.ts @@ -25,10 +25,10 @@ export default class InteractionCreateListener extends BushListener { ); return; } else if (interaction.isButton()) { - if (interaction.customId.startsWith('paginate_')) return; + if (interaction.customId.startsWith('paginate_') || interaction.customId.startsWith('command_')) return; return await interaction.reply({ content: 'Buttons go brrr', ephemeral: true }); } else if (interaction.isSelectMenu()) { - if (interaction.customId.startsWith('featureCommand_')) return; + if (interaction.customId.startsWith('command_')) return; return await interaction.reply({ content: `You selected ${ Array.isArray(interaction.values) @@ -37,15 +37,6 @@ export default class InteractionCreateListener extends BushListener { }.`, ephemeral: true }); - } /* else if (interaction.isContextMenu()) { - if (interaction.commandName === 'View Raw') { - await interaction.deferReply({ ephemeral: true }); - const embed = await ViewRawCommand.getRawData(interaction.options.getMessage('message') as BushMessage, { - json: false, - js: false - }); - return await interaction.editReply({ embeds: [embed] }); - } - } */ + } } } diff --git a/src/listeners/commands/commandError.ts b/src/listeners/commands/commandError.ts index f43e17d..a3618e7 100644 --- a/src/listeners/commands/commandError.ts +++ b/src/listeners/commands/commandError.ts @@ -96,7 +96,7 @@ export default class CommandErrorListener extends BushListener { } const inspectOptions = { showHidden: false, - depth: 5, + depth: 9, colors: false, customInspect: true, showProxy: false, diff --git a/src/listeners/message/automodCreate.ts b/src/listeners/message/automodCreate.ts index f78efec..4165043 100644 --- a/src/listeners/message/automodCreate.ts +++ b/src/listeners/message/automodCreate.ts @@ -97,16 +97,15 @@ export default class AutomodMessageCreateListener extends BushListener { : highestOffence === 2 ? util.colors.orange : util.colors.red; + // TODO: remove hard coded value void (message.guild.channels.cache.get('783088333055066212') as TextChannel).send({ embeds: [ new MessageEmbed() .setTitle(`[Severity ${highestOffence}] Automod Action Performed`) .setDescription( - `**User:** ${message.author.tag} (${message.author.tag})\n**Sent From**: <#${ - message.channel.id - }> [Jump to context](${message.url})\n**Blacklisted Words:** ${util - .surroundArray(Object.keys(offences), '`') - .join(', ')}` + `**User:** ${message.author} (${message.author.tag})\n**Sent From**: <#${message.channel.id}> [Jump to context](${ + message.url + })\n**Blacklisted Words:** ${util.surroundArray(Object.keys(offences), '`').join(', ')}` ) .addField('Message Content', `${await util.codeblock(message.content, 1024)}`) .setColor(color) diff --git a/src/listeners/message/level.ts b/src/listeners/message/level.ts index 33e7b08..83d9e3b 100644 --- a/src/listeners/message/level.ts +++ b/src/listeners/message/level.ts @@ -35,7 +35,7 @@ export default class LevelListener extends BushListener { }); if (success) void client.logger.verbose( - `levelMessageListener`, + `levelMessage`, `Gave <<${xpToGive}>> XP to <<${message.author.tag}>> in <<${message.guild}>>.` ); this.#levelCooldowns.add(`${message.guild.id}-${message.author.id}`); |