diff options
-rw-r--r-- | .vscode/settings.json | 2 | ||||
-rw-r--r-- | src/commands/config/levelRoles.ts | 122 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushClientEvents.d.ts | 3 | ||||
-rw-r--r-- | src/lib/models/Guild.ts | 59 | ||||
-rw-r--r-- | src/listeners/custom/bushLevelUpdate.ts | 47 | ||||
-rw-r--r-- | src/listeners/message/autoThread.ts | 2 | ||||
-rw-r--r-- | src/listeners/message/level.ts | 12 |
7 files changed, 165 insertions, 82 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 144c4ca..b6ceb69 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,7 +32,7 @@ "prettier.withNodeModules": true, "prettier.useEditorConfig": false, "eslint.nodePath": ".yarn/sdks", - "typescript.tsdk": "node_modules\\typescript\\lib", + "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "better-comments.highlightPlainText": true, "better-comments.multilineComments": true, diff --git a/src/commands/config/levelRoles.ts b/src/commands/config/levelRoles.ts index f947d85..36dc50c 100644 --- a/src/commands/config/levelRoles.ts +++ b/src/commands/config/levelRoles.ts @@ -1,61 +1,65 @@ -// import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; +import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; -// export default class LevelRolesCommand extends BushCommand { -// public constructor() { -// super('levelRole', { -// aliases: ['level-role', 'level-roles', 'lr'], -// category: 'config', -// description: { -// content: 'Command description.', -// usage: 'level-role <role> <level>', -// examples: ['level-role 1 2'] -// }, -// args: [ -// { -// id: 'role', -// type: 'role', -// prompt: { -// start: 'What would you like to set your first argument to be?', -// retry: '{error} Pick a valid argument.', -// optional: false -// } -// }, -// { -// id: 'level', -// type: 'integer', -// prompt: { -// start: 'What would you like to set your second argument to be?', -// retry: '{error} Pick a valid argument.', -// optional: false -// } -// } -// ], -// slash: true, -// slashOptions: [ -// { -// name: 'role', -// description: 'What would you like to set your first argument to be?', -// type: 'STRING', -// required: true -// }, -// { -// name: 'level', -// description: 'What would you like to set your second argument to be?', -// type: 'STRING', -// required: true -// } -// ], -// channel: 'guild', -// clientPermissions: ['SEND_MESSAGES'], -// userPermissions: ['SEND_MESSAGES', 'MANAGE_GUILD', 'MANAGE_ROLES'] -// }); -// } +export default class LevelRolesCommand extends BushCommand { + public constructor() { + super('levelRole', { + aliases: ['level-role', 'level-roles', 'lr'], + category: 'config', + description: { + content: 'Configure roles to be assigned to users upon reaching certain levels.', + usage: ['level-role add <level> <role>', 'level-role remove <level>'], + examples: ['level-role 1 2'] + }, + args: [ + { + id: 'action', + customType: ['add', 'remove'] + }, + { + id: 'role', + type: 'role', + prompt: { + start: 'What would you like to set your first argument to be?', + retry: '{error} Pick a valid argument.', + optional: false + } + }, + { + id: 'level', + type: 'integer', + prompt: { + start: 'What would you like to set your second argument to be?', + retry: '{error} Pick a valid argument.', + optional: false + } + } + ], + slash: true, + slashOptions: [ + { + name: 'role', + description: 'What would you like to set your first argument to be?', + type: 'STRING', + required: true + }, + { + name: 'level', + description: 'What would you like to set your second argument to be?', + type: 'STRING', + required: true + } + ], + channel: 'guild', + clientPermissions: ['SEND_MESSAGES'], + userPermissions: ['SEND_MESSAGES', 'MANAGE_GUILD', 'MANAGE_ROLES'] + }); + } -// public override async exec( -// message: BushMessage | BushSlashMessage, -// args: { required_argument: string; optional_argument: string } -// ): Promise<unknown> { -// return await message.util.reply(`${util.emojis.error} Do not use the template command.`); -// args; -// } -// } + public override async exec( + message: BushMessage | BushSlashMessage, + args: { required_argument: string; optional_argument: string } + ): Promise<unknown> { + return await message.util.reply(`${util.emojis.error} Do not use the template command.`); + args; + } +} diff --git a/src/lib/extensions/discord.js/BushClientEvents.d.ts b/src/lib/extensions/discord.js/BushClientEvents.d.ts index 2c9de89..d8f1146 100644 --- a/src/lib/extensions/discord.js/BushClientEvents.d.ts +++ b/src/lib/extensions/discord.js/BushClientEvents.d.ts @@ -237,7 +237,8 @@ export interface BushClientEvents extends ClientEvents { member: BushGuildMember, oldLevel: number, newLevel: number, - currentXp: number + currentXp: number, + message: BushMessage & { guild: BushGuild } ]; } diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts index ab18d05..47b4af9 100644 --- a/src/lib/models/Guild.ts +++ b/src/lib/models/Guild.ts @@ -4,7 +4,14 @@ import { BushClient } from '../extensions/discord-akairo/BushClient'; import { BaseModel } from './BaseModel'; import { jsonArrayInit, jsonParseGet, jsonParseSet, NEVER_USED } from './__helpers'; -export const guildSettingsObj = { +export const guildSettingsObj: { + [x in GuildSettings]: { + name: string; + description: string; + type: 'string' | 'custom' | 'channel' | 'role' | 'user' | 'channel-array' | 'role-array' | 'user-array'; + configurable: boolean; + }; +} = { prefix: { name: 'Prefix', description: 'The phrase required to trigger text commands in this server.', @@ -73,12 +80,32 @@ export const guildSettingsObj = { }, levelRoles: { name: 'Level Roles', - description: 'What roles get given at certain levels.', + description: 'What roles get given to users when they reach certain levels.', type: 'custom', configurable: false + }, + levelUpChannel: { + name: 'Level Up Channel', + description: 'The channel to send level up messages in instead of last channel.', + type: 'channel', + configurable: true } }; -export type GuildSettings = keyof typeof guildSettingsObj; + +export type GuildSettings = + | 'prefix' + | 'autoPublishChannels' + | 'welcomeChannel' + | 'muteRole' + | 'punishmentEnding' + | 'lockdownChannels' + | 'joinRoles' + | 'bypassChannelBlacklist' + | 'logChannels' + | 'autoModPhases' + | 'noXpChannels' + | 'levelRoles' + | 'levelUpChannel'; export const settingsArr = Object.keys(guildSettingsObj).filter( (s) => guildSettingsObj[s as GuildSettings].configurable ) as GuildSettings[]; @@ -119,6 +146,10 @@ export const guildFeaturesObj = { modsCanPunishMods: { name: 'Mods Can Punish Mods', description: 'Allow moderators to punish other moderators.' + }, + sendLevelUpMessages: { + name: 'Send Level Up Messages', + description: 'Send a message when a user levels up.' } }; @@ -163,6 +194,7 @@ export interface GuildModel { bypassChannelBlacklist: Snowflake[]; noXpChannels: Snowflake[]; levelRoles: { [level: number]: Snowflake }; + levelUpChannel: Snowflake; } export interface GuildModelCreationAttributes { @@ -183,6 +215,7 @@ export interface GuildModelCreationAttributes { bypassChannelBlacklist?: Snowflake[]; noXpChannels?: Snowflake[]; levelRoles?: { [level: number]: Snowflake }; + levelUpChannel?: Snowflake; } export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> implements GuildModel { @@ -336,6 +369,9 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i throw new Error(NEVER_USED); } + /** + * Channels where users will not earn xp for leveling. + */ public get noXpChannels(): Snowflake[] { throw new Error(NEVER_USED); } @@ -343,6 +379,9 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i throw new Error(NEVER_USED); } + /** + * What roles get given to users when they reach certain levels. + */ public get levelRoles(): { [level: number]: Snowflake } { throw new Error(NEVER_USED); } @@ -350,6 +389,16 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i throw new Error(NEVER_USED); } + /** + * The channel to send level up messages in instead of last channel. + */ + public get levelUpChannel(): Snowflake { + throw new Error(NEVER_USED); + } + public set levelUpChannel(_: Snowflake) { + throw new Error(NEVER_USED); + } + public static initModel(sequelize: Sequelize, client: BushClient): void { Guild.init( { @@ -415,6 +464,10 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i }, allowNull: false, defaultValue: '{}' + }, + levelUpChannel: { + type: DataTypes.STRING, + allowNull: true } }, { sequelize: sequelize } diff --git a/src/listeners/custom/bushLevelUpdate.ts b/src/listeners/custom/bushLevelUpdate.ts index 0e24309..9339a4e 100644 --- a/src/listeners/custom/bushLevelUpdate.ts +++ b/src/listeners/custom/bushLevelUpdate.ts @@ -1,17 +1,34 @@ -// import { BushListener } from '../../lib'; -// import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents'; +import { Formatters, TextChannel } from 'discord.js'; +import { BushListener } from '../../lib'; +import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents'; -// export default class BushLevelUpdateListener extends BushListener { -// public constructor() { -// super('bushLevelUpdate', { -// emitter: 'client', -// event: 'bushLevelUpdate', -// category: 'custom' -// }); -// } +export default class BushLevelUpdateListener extends BushListener { + public constructor() { + super('bushLevelUpdate', { + emitter: 'client', + event: 'bushLevelUpdate', + category: 'custom' + }); + } -// // eslint-disable-next-line @typescript-eslint/no-unused-vars -// public override async exec(...[member, oldLevel, newLevel, currentXp]: BushClientEvents['bushLevelUpdate']) { -// // -// } -// } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public override async exec(...[member, oldLevel, newLevel, currentXp, message]: BushClientEvents['bushLevelUpdate']) { + if (await message.guild.hasFeature('sendLevelUpMessages')) { + void (async () => { + const channel = ((await message.guild.channels + .fetch((await message.guild.getSetting('levelUpChannel')) ?? message.channelId) + .catch(() => null)) ?? message.channel) as TextChannel; + + const success = await channel + .send( + `${Formatters.bold(util.sanitizeWtlAndControl(member.user.tag))} leveled up to level ${Formatters.bold( + `${newLevel}` + )}.` + ) + .catch(() => null); + + if (!success) await client.console.warn('bushLevelUpdate', `Could not send level up message in ${message.guild}`); + })(); + } + } +} diff --git a/src/listeners/message/autoThread.ts b/src/listeners/message/autoThread.ts index a254337..8db3979 100644 --- a/src/listeners/message/autoThread.ts +++ b/src/listeners/message/autoThread.ts @@ -37,7 +37,7 @@ export default class autoThreadListener extends BushListener { // todo: make these configurable etc... if (message.guild.id !== '516977525906341928') return; // mb if (message.channel.id !== '714332750156660756') return; // neu-support-1 - if (!(message.channel as BushTextChannel).permissionsFor(message.guild.me!).has('USE_PUBLIC_THREADS')) return; + if (!(message.channel as BushTextChannel).permissionsFor(message.guild.me!).has('CREATE_PUBLIC_THREADS')) return; const thread = await message.startThread({ name: `Support - ${message.author.username}#${message.author.discriminator}`, autoArchiveDuration: 60, diff --git a/src/listeners/message/level.ts b/src/listeners/message/level.ts index 16f616f..f263ff2 100644 --- a/src/listeners/message/level.ts +++ b/src/listeners/message/level.ts @@ -1,4 +1,4 @@ -import { BushCommandHandlerEvents, BushListener, Level } from '@lib'; +import { BushCommandHandlerEvents, BushGuild, BushListener, BushMessage, Level } from '@lib'; import { MessageType } from 'discord.js'; export default class LevelListener extends BushListener { @@ -36,7 +36,15 @@ export default class LevelListener extends BushListener { return false; }); const newLevel = Level.convertXpToLevel(user.xp); - if (previousLevel !== newLevel) client.emit('bushLevelUpdate', message.member!, previousLevel, newLevel, user.xp); + if (previousLevel !== newLevel) + client.emit( + 'bushLevelUpdate', + message.member!, + previousLevel, + newLevel, + user.xp, + message as BushMessage & { guild: BushGuild } + ); if (success) void client.logger.verbose(`level`, `Gave <<${xpToGive}>> XP to <<${message.author.tag}>> in <<${message.guild}>>.`); this.#levelCooldowns.add(`${message.guild.id}-${message.author.id}`); |