aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commands/config/features.ts5
-rw-r--r--src/commands/config/settings.ts168
-rw-r--r--src/commands/dev/__template.ts7
-rw-r--r--src/commands/dev/setLevel.ts6
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts6
-rw-r--r--src/lib/models/Guild.ts79
-rw-r--r--src/listeners/client/interactionCreate.ts15
-rw-r--r--src/listeners/commands/commandError.ts2
-rw-r--r--src/listeners/message/automodCreate.ts9
-rw-r--r--src/listeners/message/level.ts2
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}`);