diff options
author | IRONM00N <64110067+IRONM00N@users.noreply.github.com> | 2021-08-17 12:31:09 -0400 |
---|---|---|
committer | IRONM00N <64110067+IRONM00N@users.noreply.github.com> | 2021-08-17 12:31:09 -0400 |
commit | d40527d0a2d9f209905750258f71bedff1cdf089 (patch) | |
tree | e017fd844c2135bfc85228d00ef2617d24ce0a3f | |
parent | d431ad00754f3f250103deedea495b9bcee73fc0 (diff) | |
download | tanzanite-d40527d0a2d9f209905750258f71bedff1cdf089.tar.gz tanzanite-d40527d0a2d9f209905750258f71bedff1cdf089.tar.bz2 tanzanite-d40527d0a2d9f209905750258f71bedff1cdf089.zip |
turned on ts strict option
88 files changed, 513 insertions, 381 deletions
diff --git a/package.json b/package.json index 413889d..3e35241 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@types/node-fetch": "^2", "@types/tinycolor2": "^1", "@types/uuid": "^8.3.0", + "@types/validator": "^13.6.3", "@typescript-eslint/eslint-plugin": "^4.14.1", "@typescript-eslint/parser": "^4.14.1", "esbuild": "^0.12.11", @@ -122,7 +123,8 @@ "no-throw-literal": "off", "@typescript-eslint/no-throw-literal": "warn", "@typescript-eslint/prefer-nullish-coalescing": "warn", - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off" } }, "prettier": { diff --git a/src/arguments/contentWithDuration.ts b/src/arguments/contentWithDuration.ts index 99b251f..314b761 100644 --- a/src/arguments/contentWithDuration.ts +++ b/src/arguments/contentWithDuration.ts @@ -3,6 +3,6 @@ import { BushArgumentTypeCaster, BushMessage } from '@lib'; export const contentWithDurationTypeCaster: BushArgumentTypeCaster = async ( _message: BushMessage, phrase: string -): Promise<{ duration: number; contentWithoutTime: string }> => { +): Promise<{ duration: number; contentWithoutTime: string | null }> => { return client.util.parseDuration(phrase); }; diff --git a/src/arguments/permission.ts b/src/arguments/permission.ts index dc90f3a..8ad0102 100644 --- a/src/arguments/permission.ts +++ b/src/arguments/permission.ts @@ -4,7 +4,7 @@ import { BushArgumentTypeCaster } from '../lib/extensions/discord-akairo/BushArg export const permissionTypeCaster: BushArgumentTypeCaster = (_, phrase) => { if (!phrase) return null; phrase = phrase.toUpperCase().replace(/ /g, '_'); - if (!Permissions.FLAGS[phrase]) { + if (!Permissions.FLAGS[phrase as keyof typeof Permissions.FLAGS]) { return null; } else { return phrase; diff --git a/src/commands/admin/channelPermissions.ts b/src/commands/admin/channelPermissions.ts index a13f07a..83230f7 100644 --- a/src/commands/admin/channelPermissions.ts +++ b/src/commands/admin/channelPermissions.ts @@ -1,4 +1,4 @@ -import { GuildChannel, GuildMember, MessageEmbed, Role } from 'discord.js'; +import { GuildMember, MessageEmbed, Role } from 'discord.js'; import { BushCommand, BushMessage } from '../../lib'; export default class ChannelPermissionsCommand extends BushCommand { @@ -63,7 +63,7 @@ export default class ChannelPermissionsCommand extends BushCommand { } ): Promise<unknown> { const failedChannels = []; - for (const channel of message.guild.channels.cache.values()) { + for (const channel of message.guild!.channels.cache.values()) { try { if (channel.isThread()) return; if (channel.permissionsLocked) return; @@ -78,7 +78,7 @@ export default class ChannelPermissionsCommand extends BushCommand { failedChannels.push(channel); } } - const failure = failedChannels.map((e: GuildChannel) => `<#${e.id}>`).join(' '); + const failure = failedChannels.map((e) => `<#${e.id}>`).join(' '); if (failure.length > 2000) { const paginate: MessageEmbed[] = []; for (let i = 0; i < failure.length; i += 2000) { diff --git a/src/commands/config/autoPublishChannel.ts b/src/commands/config/autoPublishChannel.ts index 3381dc2..f058402 100644 --- a/src/commands/config/autoPublishChannel.ts +++ b/src/commands/config/autoPublishChannel.ts @@ -29,7 +29,7 @@ export default class AutoPublishChannelCommand extends BushCommand { name: 'channel', description: 'What channel would you like me to send welcome messages in?', type: 'CHANNEL', - required: false + required: true } ], channel: 'guild', @@ -39,13 +39,13 @@ export default class AutoPublishChannelCommand extends BushCommand { } public override async exec(message: BushMessage, { channel }: { channel: Channel }): Promise<unknown> { - const autoPublishChannels = await message.guild.getSetting('autoPublishChannels'); + const autoPublishChannels = await message.guild!.getSetting('autoPublishChannels'); const newValue = util.addOrRemoveFromArray( autoPublishChannels.includes(channel.id) ? 'remove' : 'add', autoPublishChannels, channel.id ); - await message.guild.setSetting('autoPublishChannels', newValue); + await message.guild!.setSetting('autoPublishChannels', newValue); return await message.util.reply({ content: `${util.emojis.success} Successfully ${ autoPublishChannels.includes(channel.id) ? 'disabled' : 'enabled' diff --git a/src/commands/config/blacklist.ts b/src/commands/config/blacklist.ts index 864081c..57c3015 100644 --- a/src/commands/config/blacklist.ts +++ b/src/commands/config/blacklist.ts @@ -75,9 +75,12 @@ export default class BlacklistCommand extends BushCommand { const targetID = target.id; if (global) { - if (action === 'toggle') { - const blacklistedUsers = (await Global.findByPk(client.config.environment)).blacklistedUsers; - const blacklistedChannels = (await Global.findByPk(client.config.environment)).blacklistedChannels; + if ((action as 'blacklist' | 'unblacklist' | 'toggle') === 'toggle') { + const globalDB = + (await Global.findByPk(client.config.environment)) ?? + (await Global.create({ environment: client.config.environment })); + const blacklistedUsers = globalDB.blacklistedUsers; + const blacklistedChannels = globalDB.blacklistedChannels; action = blacklistedUsers.includes(targetID) || blacklistedChannels.includes(targetID) ? 'unblacklist' : 'blacklist'; } const success = await util @@ -99,9 +102,11 @@ export default class BlacklistCommand extends BushCommand { }); // guild disable } else { + if (!message.guild) + return await message.util.reply(`${util.emojis.error} You have to be in a guild to disable commands.`); const blacklistedChannels = (await message.guild.getSetting('blacklistedChannels')) ?? []; const blacklistedUsers = (await message.guild.getSetting('blacklistedUsers')) ?? []; - if (action === 'toggle') { + if ((action as 'blacklist' | 'unblacklist' | 'toggle') === 'toggle') { action = blacklistedChannels.includes(targetID) ?? blacklistedUsers.includes(targetID) ? 'unblacklist' : 'blacklist'; } const newValue = util.addOrRemoveFromArray( diff --git a/src/commands/config/disable.ts b/src/commands/config/disable.ts index a9318a5..bc6ed47 100644 --- a/src/commands/config/disable.ts +++ b/src/commands/config/disable.ts @@ -69,8 +69,11 @@ export default class DisableCommand extends BushCommand { const commandID = (args.command as BushCommand).id; if (global) { - if (action === 'toggle') { - const disabledCommands = (await Global.findByPk(client.config.environment)).disabledCommands; + if ((action as 'disable' | 'enable' | 'toggle') === 'toggle') { + const disabledCommands = ( + (await Global.findByPk(client.config.environment)) ?? + (await Global.create({ environment: client.config.environment })) + ).disabledCommands; action = disabledCommands.includes(commandID) ? 'disable' : 'enable'; } const success = await util @@ -95,12 +98,12 @@ export default class DisableCommand extends BushCommand { // guild disable } else { - const disabledCommands = await message.guild.getSetting('disabledCommands'); - if (action === 'toggle') { + const disabledCommands = await message.guild!.getSetting('disabledCommands'); + if ((action as 'disable' | 'enable' | 'toggle') === 'toggle') { action = disabledCommands.includes(commandID) ? 'disable' : 'enable'; } const newValue = util.addOrRemoveFromArray(action === 'disable' ? 'remove' : 'add', disabledCommands, commandID); - const success = await message.guild.setSetting('disabledCommands', newValue).catch(() => false); + const success = await message.guild!.setSetting('disabledCommands', newValue).catch(() => false); if (!success) return await message.util.reply({ content: `${util.emojis.error} There was an error **${action.substr( diff --git a/src/commands/config/muteRole.ts b/src/commands/config/muteRole.ts index dee5322..c7a6e75 100644 --- a/src/commands/config/muteRole.ts +++ b/src/commands/config/muteRole.ts @@ -38,7 +38,7 @@ export default class MuteRoleCommand extends BushCommand { } override async exec(message: BushMessage | BushSlashMessage, args: { role: Role }): Promise<void> { - await message.guild.setSetting('muteRole', args.role.id); + await message.guild!.setSetting('muteRole', args.role.id); await message.util.send({ content: `${util.emojis.success} Changed the server's mute role to <@&${args.role.id}>.`, allowedMentions: AllowedMentions.none() diff --git a/src/commands/config/prefix.ts b/src/commands/config/prefix.ts index 9f80633..9d707e0 100644 --- a/src/commands/config/prefix.ts +++ b/src/commands/config/prefix.ts @@ -37,8 +37,8 @@ export default class PrefixCommand extends BushCommand { } override async exec(message: BushMessage | BushSlashMessage, args: { prefix?: string }): Promise<unknown> { - const oldPrefix = await message.guild.getSetting('prefix'); - await message.guild.setSetting('prefix', args.prefix ?? client.config.prefix); + const oldPrefix = await message.guild!.getSetting('prefix'); + await message.guild!.setSetting('prefix', args.prefix ?? client.config.prefix); if (args.prefix) { return await message.util.send({ content: `${util.emojis.success} changed the server's prefix ${oldPrefix ? `from \`${oldPrefix}\`` : ''} to \`${ diff --git a/src/commands/config/punishmentFooter.ts b/src/commands/config/punishmentFooter.ts index d8daf77..d07ce4f 100644 --- a/src/commands/config/punishmentFooter.ts +++ b/src/commands/config/punishmentFooter.ts @@ -39,7 +39,7 @@ export default class PunishmentFooterCommand extends BushCommand { } override async exec(message: BushMessage | BushSlashMessage, args: { ending: string }): Promise<unknown> { - await message.guild.setSetting('punishmentEnding', args.ending || null); + await message.guild!.setSetting('punishmentEnding', args.ending || ''); if (args.ending) return await message.util.send({ content: `${util.emojis.success} Changed the server's punishment footer to \n\`\`\`${Util.cleanCodeBlockContent( diff --git a/src/commands/config/welcomeChannel.ts b/src/commands/config/welcomeChannel.ts index a662802..fc56607 100644 --- a/src/commands/config/welcomeChannel.ts +++ b/src/commands/config/welcomeChannel.ts @@ -37,8 +37,8 @@ export default class WelcomeChannelCommand extends BushCommand { }); } public override async exec(message: BushMessage | BushSlashMessage, args: { channel: Channel }): Promise<unknown> { - const oldChannel = await message.guild.getSetting('welcomeChannel'); - await message.guild.setSetting('welcomeChannel', args.channel.id ?? undefined); + const oldChannel = await message.guild!.getSetting('welcomeChannel'); + await message.guild!.setSetting('welcomeChannel', args.channel.id ?? undefined); if (args.channel) { return await message.util.send( `${util.emojis.success} changed the server's welcome channel ${oldChannel ? `from <#${oldChannel}>` : ''} to <#${ diff --git a/src/commands/dev/eval.ts b/src/commands/dev/eval.ts index 5b44db2..10360cf 100644 --- a/src/commands/dev/eval.ts +++ b/src/commands/dev/eval.ts @@ -70,7 +70,7 @@ export default class EvalCommand extends BushCommand { } args.code = args.code.replace(/[“”]/g, '"').replace(/```*(?:js|ts)?/g, ''); - const code = { + const code: { ts: string | null; js: string; lang: 'ts' | 'js' } = { ts: args.typescript ? args.code : null, js: args.typescript ? transpile(args.code) : args.code, lang: args.typescript ? 'ts' : 'js' @@ -79,7 +79,7 @@ export default class EvalCommand extends BushCommand { const embed = new _MessageEmbed(); const badPhrases = ['delete', 'destroy']; - if (badPhrases.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(`${util.emojis.error} This eval was blocked by smooth brain protection™.`); } @@ -119,7 +119,7 @@ export default class EvalCommand extends BushCommand { const inputJS = await util.inspectCleanRedactCodeblock(code.js, 'js'); const inputTS = code.lang === 'ts' ? await util.inspectCleanRedactCodeblock(code.ts, 'ts') : undefined; try { - const rawOutput = code[code.lang].replace(/ /g, '').includes('9+10' || '10+9') ? '21' : await eval(code.js); + const rawOutput = code[code.lang]!.replace(/ /g, '').includes('9+10' || '10+9') ? '21' : await eval(code.js); const output = await util.inspectCleanRedactCodeblock(rawOutput, 'js', { depth: args.sel_depth ?? 0, showHidden: args.hidden, @@ -148,7 +148,7 @@ export default class EvalCommand extends BushCommand { embed.addField('📤 Output', await util.inspectCleanRedactCodeblock(e?.stack || e, 'js')); } - embed.setTimestamp().setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true })); + embed.setTimestamp().setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true }) ?? undefined); if (!args.silent || message.util.isSlash) { await message.util.reply({ embeds: [embed] }); diff --git a/src/commands/dev/reload.ts b/src/commands/dev/reload.ts index 4f11a81..91cabfb 100644 --- a/src/commands/dev/reload.ts +++ b/src/commands/dev/reload.ts @@ -44,7 +44,7 @@ export default class ReloadCommand extends BushCommand { client.inhibitorHandler.reloadAll(); return message.util.send(`🔁 Successfully reloaded! (${new Date().getTime() - s.getTime()}ms)`); } catch (e) { - if (output) void client.logger.error('reloadCommand', output); + if (output!) void client.logger.error('reloadCommand', output); return message.util.send(`An error occurred while reloading:\n${await util.codeblock(e?.stack || e, 2048 - 34, 'js')}`); } } diff --git a/src/commands/dev/say.ts b/src/commands/dev/say.ts index f0a7cbf..1c797ea 100644 --- a/src/commands/dev/say.ts +++ b/src/commands/dev/say.ts @@ -42,6 +42,6 @@ export default class SayCommand extends BushCommand { }); } await message.interaction.reply({ content: 'Attempting to send message.', ephemeral: true }); - return message.channel.send({ content, allowedMentions: AllowedMentions.none() }); + return message.channel!.send({ content, allowedMentions: AllowedMentions.none() }); } } diff --git a/src/commands/dev/setLevel.ts b/src/commands/dev/setLevel.ts index 97527fa..e69b9df 100644 --- a/src/commands/dev/setLevel.ts +++ b/src/commands/dev/setLevel.ts @@ -44,7 +44,8 @@ export default class SetLevelCommand extends BushCommand { } ], ownerOnly: true, - slash: true + slash: true, + channel: 'guild' }); } @@ -58,11 +59,11 @@ export default class SetLevelCommand extends BushCommand { 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/commands/dev/sh.ts b/src/commands/dev/sh.ts index 7f048c0..025a308 100644 --- a/src/commands/dev/sh.ts +++ b/src/commands/dev/sh.ts @@ -5,7 +5,7 @@ import { MessageEmbed, Util } from 'discord.js'; import { promisify } from 'util'; const sh = promisify(exec); -const clean = (text) => { +const clean = (text: string | any) => { chalk.toString; if (typeof text === 'string') { return (text = Util.cleanCodeBlockContent(text)); @@ -43,7 +43,7 @@ export default class ShCommand extends BushCommand { const embed = new MessageEmbed() .setColor(util.colors.gray) - .setFooter(message.author.tag, message.author.avatarURL({ dynamic: true })) + .setFooter(message.author.tag, message.author.avatarURL({ dynamic: true }) ?? undefined) .setTimestamp() .setTitle('Shell Command') .addField('📥 Input', await util.codeblock(input, 1024, 'sh')) diff --git a/src/commands/dev/superUser.ts b/src/commands/dev/superUser.ts index 5178684..957e2b7 100644 --- a/src/commands/dev/superUser.ts +++ b/src/commands/dev/superUser.ts @@ -49,7 +49,7 @@ export default class SuperUserCommand extends BushCommand { `${util.emojis.error} I fucked up here is args ${await util.inspectCleanRedactCodeblock(args, 'ts')}` ); - const superUsers = (await Global.findByPk(client.config.environment)).superUsers; + const superUsers: string[] = (await Global.findByPk(client.config.environment))?.superUsers ?? []; let success; if (args.action === 'add') { if (superUsers.includes(args.user.id)) { diff --git a/src/commands/dev/test.ts b/src/commands/dev/test.ts index 60e93c4..151e4a1 100644 --- a/src/commands/dev/test.ts +++ b/src/commands/dev/test.ts @@ -56,9 +56,9 @@ export default class TestCommand extends BushCommand { 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) + .setColor(message.member?.displayColor ?? util.colors.default) .setDescription('Description') - .setFooter('Footer', message.author.avatarURL()) + .setFooter('Footer', message.author.avatarURL() ?? undefined) .setURL('https://duckduckgo.com/') .setTimestamp() .setImage('https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png') @@ -91,14 +91,15 @@ export default class TestCommand extends BushCommand { return await 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 _avatar = message.author.avatarURL({ dynamic: true }) ?? undefined; + const author = { name: 'This is a author', iconURL: _avatar }; + const footer = { text: 'This is a footer', iconURL: _avatar }; const fields = []; for (let i = 0; i < 25; i++) { fields.push({ name: 'Field ' + i, value: 'Field Value ' + i }); } const c = util.colors; - const o = { description, author, footer, fields }; + const o = { description, author, footer, fields }!; const embeds = [ new MessageEmbed({ ...o, ...{ title: 'Embed Title 0', color: c.red } }).setTimestamp(), @@ -134,10 +135,11 @@ export default class TestCommand extends BushCommand { // }); // }) // ); + if (!message.guild) return await message.util.reply(`${util.emojis.error} This test can only be run in a guild.`); const guildCommands = await message.guild.commands.fetch(); // eslint-disable-next-line @typescript-eslint/no-misused-promises guildCommands.forEach(async (command) => await command.delete()); - const globalCommands = await client.application.commands.fetch(); + const globalCommands = await client.application!.commands.fetch(); // eslint-disable-next-line @typescript-eslint/no-misused-promises globalCommands.forEach(async (command) => await command.delete()); diff --git a/src/commands/fun/minesweeper.ts b/src/commands/fun/minesweeper.ts index 2bec1e9..57909a2 100644 --- a/src/commands/fun/minesweeper.ts +++ b/src/commands/fun/minesweeper.ts @@ -118,6 +118,6 @@ export default class MinesweeperCommand extends BushCommand { returnType: 'emoji' }); const matrix = minesweeper.start(); - return await message.util.reply(matrix.toString()); + return await message.util.reply(matrix?.toString() ?? `${util.emojis.error} Something went wrong.`); } } diff --git a/src/commands/info/avatar.ts b/src/commands/info/avatar.ts index 37d2256..7100afa 100644 --- a/src/commands/info/avatar.ts +++ b/src/commands/info/avatar.ts @@ -42,7 +42,9 @@ export default class AvatarCommand extends BushCommand { .setTimestamp() .setColor(util.colors.default) .setTitle(`${user.tag}'s Avatar`) - .setImage(user.avatarURL({ size: 2048, format: 'png', dynamic: true })); + .setImage( + user.avatarURL({ size: 2048, format: 'png', dynamic: true }) ?? 'https://cdn.discordapp.com/embed/avatars/0.png' + ); await message.util.reply({ embeds: [embed] }); } } diff --git a/src/commands/info/botInfo.ts b/src/commands/info/botInfo.ts index c89c356..37a63ce 100644 --- a/src/commands/info/botInfo.ts +++ b/src/commands/info/botInfo.ts @@ -24,7 +24,7 @@ export default class BotInfoCommand extends BushCommand { repoUrl = repoUrl.substring(0, repoUrl.length - 4); const embed = new MessageEmbed() .setTitle('Bot Info:') - .addField('**Uptime**', util.humanizeDuration(client.uptime), true) + .addField('**Uptime**', util.humanizeDuration(client.uptime!), true) .addField('**Servers**', client.guilds.cache.size.toLocaleString(), true) .addField('**Users**', client.users.cache.size.toLocaleString(), true) .addField('**Discord.js Version**', discordJSVersion, true) diff --git a/src/commands/info/color.ts b/src/commands/info/color.ts index 93dd439..350c23d 100644 --- a/src/commands/info/color.ts +++ b/src/commands/info/color.ts @@ -1,11 +1,11 @@ import { AllowedMentions, BushCommand, BushGuildMember, BushMessage, BushRole, BushSlashMessage } from '@lib'; import { Argument } from 'discord-akairo'; -import { MessageEmbed, Role } from 'discord.js'; +import { Message, MessageEmbed, Role } from 'discord.js'; import { Constructor } from 'tinycolor2'; // eslint-disable-next-line @typescript-eslint/no-var-requires const tinycolor: Constructor = require('tinycolor2'); // this is the only way I got it to work consistently -const isValidTinyColor = (_message: BushMessage, phase: string) => { +const isValidTinyColor = (_message: Message, phase: string) => { // if the phase is a number it converts it to hex incase it could be representing a color in decimal const newPhase = Number.isNaN(phase) ? phase : `#${Number(phase).toString(16)}`; return tinycolor(newPhase).isValid() ? newPhase : null; diff --git a/src/commands/info/guildInfo.ts b/src/commands/info/guildInfo.ts index 2cdf3d5..431b8bd 100644 --- a/src/commands/info/guildInfo.ts +++ b/src/commands/info/guildInfo.ts @@ -58,12 +58,16 @@ export default class GuildInfoCommand extends BushCommand { const guild: Guild | GuildPreview = (args?.guild as Guild | GuildPreview) || (message.guild as Guild); const emojis: string[] = []; const guildAbout: string[] = []; - const guildSecurity = []; + const guildStats: string[] = []; + const guildSecurity: string[] = []; const verifiedGuilds = Object.values(client.consts.mappings.guilds); if (verifiedGuilds.includes(guild.id)) emojis.push(client.consts.mappings.otherEmojis.BUSH_VERIFIED); if (!isPreview && guild instanceof Guild) { - if (guild.premiumTier) emojis.push(client.consts.mappings.otherEmojis['BOOST_' + guild.premiumTier]); + if (guild.premiumTier) + emojis.push( + client.consts.mappings.otherEmojis[('BOOST_' + guild.premiumTier) as keyof typeof client.consts.mappings.otherEmojis] + ); await guild.fetch(); const channelTypes = [ `${client.consts.mappings.otherEmojis.TEXT} ${guild.channels.cache @@ -91,7 +95,7 @@ export default class GuildInfoCommand extends BushCommand { .size.toLocaleString()}` ]; - const guildRegions = []; + const guildRegions: string[] = []; guild.channels.cache.forEach((channel) => { if (!channel.type.includes('VOICE')) return; else if (!guildRegions.includes((channel as BaseGuildVoiceChannel).rtcRegion ?? 'automatic')) { @@ -102,16 +106,16 @@ export default class GuildInfoCommand extends BushCommand { guildAbout.push( `**Owner:** ${guild.members.cache.get(guild.ownerId)?.user.tag}`, `**Created** ${guild.createdAt.toLocaleString()} (${util.dateDelta(guild.createdAt)})`, - `**Members:** ${guild.memberCount.toLocaleString() ?? 0}`, - `**Online:** ${guild.approximatePresenceCount?.toLocaleString() ?? 0}`, - `**Channels:** ${guild.channels.cache.size?.toLocaleString() ?? 0} (${channelTypes.join(', ')})`, - `**Emojis:** ${guild.emojis.cache.size?.toLocaleString() ?? 0}`, - `**Stickers:** ${guild.stickers.cache.size?.toLocaleString() ?? 0}`, - `**Regions:** ${guildRegions.map((region) => client.consts.mappings.regions[region] || region).join(', ')}` + `**Members:** ${guild.memberCount.toLocaleString() ?? 0} (${util.emojis.onlineCircle} ${ + guild.approximatePresenceCount?.toLocaleString() ?? 0 + }, ${util.emojis.offlineCircle} ${(guild.memberCount - (guild.approximatePresenceCount ?? 0)).toLocaleString() ?? 0})`, + `**Regions:** ${guildRegions + .map((region) => client.consts.mappings.regions[region as keyof typeof client.consts.mappings.regions] || region) + .join(', ')}` ); if (guild.premiumSubscriptionCount) guildAbout.push( - `**Boosts:** Level ${guild.premiumTier == 'NONE' ? '0' : guild.premiumTier[5]} with ${ + `**Boosts:** Level ${guild.premiumTier == 'NONE' ? 0 : guild.premiumTier[5]} with ${ guild.premiumSubscriptionCount ?? 0 } boosts` ); @@ -123,6 +127,28 @@ export default class GuildInfoCommand extends BushCommand { ); } + if (guild.icon) guildAbout.push(`**Icon:** [link](${guild.iconURL({ dynamic: true, size: 4096, format: 'png' })})`); + if (guild.banner) guildAbout.push(`**Banner:** [link](${guild.bannerURL({ size: 4096, format: 'png' })})`); + if (guild.splash) guildAbout.push(`**Splash:** [link](${guild.splashURL({ size: 4096, format: 'png' })})`); + + guildStats.push( + `**Channels:** ${guild.channels.cache.size.toLocaleString()} / 500 (${channelTypes.join(', ')})`, + // subtract 1 for @everyone role + `**Roles:** ${((guild.roles.cache.size ?? 0) - 1).toLocaleString()} / 250`, + `**Emojis:** ${guild.emojis.cache.size?.toLocaleString() ?? 0} / ${ + guild.premiumTier === 'TIER_3' + ? 500 + : guild.premiumTier === 'TIER_2' + ? 300 + : guild.premiumTier === 'TIER_1' + ? 100 + : 50 + }`, + `**Stickers:** ${guild.stickers.cache.size?.toLocaleString() ?? 0} / ${ + guild.premiumTier === 'TIER_3' ? 60 : guild.premiumTier === 'TIER_2' ? 30 : guild.premiumTier === 'TIER_1' ? 15 : 0 + }` + ); + guildSecurity.push( `**Verification Level**: ${guild.verificationLevel.toLowerCase().replace(/_/g, ' ')}`, `**Explicit Content Filter:** ${guild.explicitContentFilter.toLowerCase().replace(/_/g, ' ')}`, @@ -135,14 +161,17 @@ export default class GuildInfoCommand extends BushCommand { ); } else { guildAbout.push( - `**Members:** ${guild.approximateMemberCount?.toLocaleString()}`, - `**Online:** ${guild.approximatePresenceCount?.toLocaleString()}`, + `**Members:** ${guild.approximateMemberCount?.toLocaleString() ?? 0} (${util.emojis.onlineCircle} ${ + guild.approximatePresenceCount?.toLocaleString() ?? 0 + }, ${util.emojis.offlineCircle} ${( + (guild.approximateMemberCount ?? 0) - (guild.approximatePresenceCount ?? 0) + ).toLocaleString()})`, `**Emojis:** ${(guild as GuildPreview).emojis.size?.toLocaleString() ?? 0}` // `**Stickers:** ${(guild as GuildPreview).stickers.size}` ); } - const guildFeatures = guild.features.sort((a, b) => { + const guildFeatures = guild.features.sort((a, b): number => { const aWeight = client.consts.mappings.features[a]?.weight; const bWeight = client.consts.mappings.features[b]?.weight; @@ -153,6 +182,7 @@ export default class GuildInfoCommand extends BushCommand { } else if (bWeight == undefined) { return -1; } + return 0; }); if (guildFeatures.length) { guildFeatures.forEach((feature) => { @@ -174,6 +204,7 @@ export default class GuildInfoCommand extends BushCommand { .setTitle(guild.name) .setColor(util.colors.default) .addField('» About', guildAbout.join('\n')); + if (guildStats) guildInfoEmbed.addField('» Stats', guildStats.join('\n')); const guildIcon = guild.iconURL({ size: 2048, format: 'png', dynamic: true }); if (guildIcon) { guildInfoEmbed.setThumbnail(guildIcon); diff --git a/src/commands/info/help.ts b/src/commands/info/help.ts index 691051c..97811da 100644 --- a/src/commands/info/help.ts +++ b/src/commands/info/help.ts @@ -47,7 +47,7 @@ export default class HelpCommand extends BushCommand { message: BushMessage | BushSlashMessage, args: { command: BushCommand | string; showHidden?: boolean } ): Promise<unknown> { - const prefix = client.config.isDevelopment ? 'dev ' : message.util.parsed.prefix; + const prefix = client.config.isDevelopment ? 'dev ' : message.util.parsed?.prefix ?? client.config.prefix; const row = new MessageActionRow(); if (!client.config.isDevelopment && !client.guilds.cache.some((guild) => guild.ownerId === message.author.id)) { @@ -55,11 +55,13 @@ export default class HelpCommand extends BushCommand { new MessageButton({ style: 'LINK', label: 'Invite Me', - url: `https://discord.com/api/oauth2/authorize?client_id=${client.user.id}&permissions=2147483647&scope=bot%20applications.commands` + url: `https://discord.com/api/oauth2/authorize?client_id=${ + client.user!.id + }&permissions=2147483647&scope=bot%20applications.commands` }) ); } - if (!client.guilds.cache.get(client.config.supportGuild.id).members.cache.has(message.author.id)) { + if (!client.guilds.cache.get(client.config.supportGuild.id)?.members.cache.has(message.author.id)) { row.addComponents( new MessageButton({ style: 'LINK', @@ -80,7 +82,7 @@ export default class HelpCommand extends BushCommand { const isSuperUser = client.isSuperUser(message.author); const command = args.command ? typeof args.command === 'string' - ? client.commandHandler.modules.get(args.command) || null + ? client.commandHandler.modules.get(args.command) ?? null : args.command : null; if (!isOwner) args.showHidden = false; @@ -98,7 +100,8 @@ export default class HelpCommand extends BushCommand { if (command.superUserOnly && !isSuperUser) { return false; } - return !(command.restrictedGuilds?.includes(message.guild.id) === false && !args.showHidden); + // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain + return !(command.restrictedGuilds?.includes(message.guild?.id!) === false && !args.showHidden); }); const categoryNice = category.id .replace(/(\b\w)/gi, (lc): string => lc.toUpperCase()) diff --git a/src/commands/info/icon.ts b/src/commands/info/icon.ts index 582494c..677fdaf 100644 --- a/src/commands/info/icon.ts +++ b/src/commands/info/icon.ts @@ -22,13 +22,13 @@ export default class IconCommand extends BushCommand { .setTimestamp() .setColor(util.colors.default) .setImage( - message.guild?.iconURL({ + message.guild!.iconURL({ size: 2048, dynamic: true, format: 'png' - }) + })! ) - .setTitle(message.guild.name); + .setTitle(message.guild!.name); await message.util.reply({ embeds: [embed] }); } } diff --git a/src/commands/info/invite.ts b/src/commands/info/invite.ts index 384c59e..615e767 100644 --- a/src/commands/info/invite.ts +++ b/src/commands/info/invite.ts @@ -24,7 +24,9 @@ export default class InviteCommand extends BushCommand { new MessageButton({ style: 'LINK', label: 'Invite Me', - url: `https://discord.com/api/oauth2/authorize?client_id=${client.user.id}&permissions=2147483647&scope=bot%20applications.commands` + url: `https://discord.com/api/oauth2/authorize?client_id=${ + client.user!.id + }&permissions=2147483647&scope=bot%20applications.commands` }) ); return await message.util.reply({ content: 'You can invite me here:', components: [ButtonRow] }); diff --git a/src/commands/info/pronouns.ts b/src/commands/info/pronouns.ts index 6f2b074..c7eac7f 100644 --- a/src/commands/info/pronouns.ts +++ b/src/commands/info/pronouns.ts @@ -1,5 +1,5 @@ -import { BushCommand, BushSlashMessage } from '@lib'; -import { Message, MessageEmbed, User } from 'discord.js'; +import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; +import { MessageEmbed, User } from 'discord.js'; import got, { HTTPError } from 'got'; export const pronounMapping = { @@ -60,8 +60,8 @@ export default class PronounsCommand extends BushCommand { slash: true }); } - override async exec(message: Message | BushSlashMessage, args: { user?: User }): Promise<unknown> { - const user = args.user || message.author; + override async exec(message: BushMessage | BushSlashMessage, args: { user?: User }): Promise<unknown> { + const user = args.user ?? message.author; const author = user.id === message.author.id; try { const apiRes: { pronouns: pronounsType } = await got diff --git a/src/commands/info/snowflakeInfo.ts b/src/commands/info/snowflakeInfo.ts index f293219..c4d71da 100644 --- a/src/commands/info/snowflakeInfo.ts +++ b/src/commands/info/snowflakeInfo.ts @@ -58,7 +58,7 @@ export default class SnowflakeInfoCommand extends BushCommand { // Channel if (client.channels.cache.has(snowflake)) { - const channel: Channel = client.channels.cache.get(snowflake); + const channel: Channel = client.channels.cache.get(snowflake)!; const channelInfo = [`**Type:** ${channel.type}`]; if (['dm', 'group'].includes(channel.type)) { const _channel = channel as DMChannel; @@ -89,38 +89,38 @@ export default class SnowflakeInfoCommand extends BushCommand { // Guild else if (client.guilds.cache.has(snowflake)) { - const guild: Guild = client.guilds.cache.get(snowflake); + const guild: Guild = client.guilds.cache.get(snowflake)!; const guildInfo = [ `**Name:** ${guild.name}`, - `**Owner:** ${client.users.cache.get(guild.ownerId)?.tag || '¯\\_(ツ)_/¯'} (${guild.ownerId})`, + `**Owner:** ${client.users.cache.get(guild.ownerId)?.tag ?? '¯\\_(ツ)_/¯'} (${guild.ownerId})`, `**Members:** ${guild.memberCount?.toLocaleString()}` ]; - snowflakeEmbed.setThumbnail(guild.iconURL({ size: 2048, dynamic: true })); + if (guild.icon) snowflakeEmbed.setThumbnail(guild.iconURL({ size: 2048, dynamic: true })!); snowflakeEmbed.addField('» Server Info', guildInfo.join('\n')); snowflakeEmbed.setTitle(`:snowflake: ${guild.name} \`[Server]\``); } // User else if (client.users.cache.has(snowflake)) { - const user: User = client.users.cache.get(snowflake); + const user: User = client.users.cache.get(snowflake)!; const userInfo = [`**Name:** <@${user.id}> (${user.tag})`]; - snowflakeEmbed.setThumbnail(user.avatarURL({ size: 2048, dynamic: true })); + if (user.avatar) snowflakeEmbed.setThumbnail(user.avatarURL({ size: 2048, dynamic: true })!); snowflakeEmbed.addField('» User Info', userInfo.join('\n')); snowflakeEmbed.setTitle(`:snowflake: ${user.tag} \`[User]\``); } // Emoji else if (client.emojis.cache.has(snowflake)) { - const emoji: Emoji = client.emojis.cache.get(snowflake); + const emoji: Emoji = client.emojis.cache.get(snowflake)!; const emojiInfo = [`**Name:** ${emoji.name}`, `**Animated:** ${emoji.animated}`]; - snowflakeEmbed.setThumbnail(emoji.url); + if (emoji.url) snowflakeEmbed.setThumbnail(emoji.url); snowflakeEmbed.addField('» Emoji Info', emojiInfo.join('\n')); snowflakeEmbed.setTitle(`:snowflake: ${emoji.name} \`[Emoji]\``); } // Role - else if (message.guild.roles.cache.has(snowflake)) { - const role: Role = message.guild.roles.cache.get(snowflake); + else if (message.guild && message.guild.roles.cache.has(snowflake)) { + const role: Role = message.guild.roles.cache.get(snowflake)!; const roleInfo = [ `**Name:** <@&${role.id}> (${role.name})`, `**Members:** ${role.members.size}`, diff --git a/src/commands/info/userInfo.ts b/src/commands/info/userInfo.ts index d9922d0..9ec5552 100644 --- a/src/commands/info/userInfo.ts +++ b/src/commands/info/userInfo.ts @@ -1,7 +1,6 @@ -import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; -import { GuildMember, MessageEmbed } from 'discord.js'; +import { BushCommand, BushMessage, BushSlashMessage, BushUser } from '@lib'; +import { MessageEmbed } from 'discord.js'; -// TODO: Allow looking up a user not in the guild and not cached (if possible) // TODO: Re-Implement Status Emojis // TODO: Add bot information export default class UserInfoCommand extends BushCommand { @@ -17,7 +16,7 @@ export default class UserInfoCommand extends BushCommand { args: [ { id: 'user', - type: 'member', + customType: util.arg.union('user', 'bigint'), prompt: { start: 'What user would you like to find information about?', retry: '{error} Choose a valid user to find information about.', @@ -40,48 +39,57 @@ export default class UserInfoCommand extends BushCommand { }); } - public override async exec(message: BushMessage | BushSlashMessage, args: { user: GuildMember }): Promise<unknown> { - const user = args?.user || message.member; + public override async exec(message: BushMessage | BushSlashMessage, args: { user: BushUser | bigint }): Promise<unknown> { + const user = + args?.user === undefined || args?.user === null + ? message.author + : typeof args.user === 'object' + ? args.user + : await client.users.fetch(`${args.user}`).catch(() => undefined); + if (user === undefined) return message.util.reply(`${util.emojis.error} Invalid user.`); + const member = message.guild ? message.guild.members.cache.get(user.id) : undefined; const emojis = []; const superUsers = client.cache.global.superUsers; const userEmbed: MessageEmbed = new MessageEmbed() - .setTitle(user.user.tag) - .setThumbnail(user.user.avatarURL({ size: 2048, format: 'png', dynamic: true })) + .setTitle(user.tag) + .setThumbnail( + user.avatarURL({ size: 2048, format: 'png', dynamic: true }) ?? 'https://cdn.discordapp.com/embed/avatars/0.png' + ) .setTimestamp(); // Flags if (client.config.owners.includes(user.id)) emojis.push(client.consts.mappings.otherEmojis.DEVELOPER); if (superUsers.includes(user.id)) emojis.push(client.consts.mappings.otherEmojis.SUPERUSER); - const flags = user.user.flags?.toArray(); + const flags = user.flags?.toArray(); if (flags) { flags.forEach((f) => { if (client.consts.mappings.userFlags[f]) { emojis.push(client.consts.mappings.userFlags[f]); - } else emojis.push(f); + } else emojis.push(`\`${f}\``); }); } // Since discord bald I just guess if someone has nitro if ( - Number(user.user.discriminator) < 10 || - client.consts.mappings.maybeNitroDiscrims.includes(user.user.discriminator) || - user.user.displayAvatarURL({ dynamic: true })?.endsWith('.gif') || - user.user.flags?.toArray().includes('PARTNERED_SERVER_OWNER') + Number(user.discriminator) < 10 || + client.consts.mappings.maybeNitroDiscrims.includes(user.discriminator) || + user.displayAvatarURL({ dynamic: true })?.endsWith('.gif') || + user.flags?.toArray().includes('PARTNERED_SERVER_OWNER') ) { emojis.push(client.consts.mappings.otherEmojis.NITRO); } - if (message.guild.ownerId == user.id) emojis.push(client.consts.mappings.otherEmojis.OWNER); - else if (user.permissions.has('ADMINISTRATOR')) emojis.push(client.consts.mappings.otherEmojis.ADMIN); - if (user.premiumSinceTimestamp) emojis.push(client.consts.mappings.otherEmojis.BOOSTER); + if (message.guild?.ownerId == user.id) emojis.push(client.consts.mappings.otherEmojis.OWNER); + else if (member?.permissions.has('ADMINISTRATOR')) emojis.push(client.consts.mappings.otherEmojis.ADMIN); + if (member?.premiumSinceTimestamp) emojis.push(client.consts.mappings.otherEmojis.BOOSTER); - const createdAt = user.user.createdAt.toLocaleString(), - createdAtDelta = util.dateDelta(user.user.createdAt), - joinedAt = user.joinedAt?.toLocaleString(), - joinedAtDelta = util.dateDelta(user.joinedAt, 2), - premiumSince = user.premiumSince?.toLocaleString(), - premiumSinceDelta = util.dateDelta(user.premiumSince, 2); + const createdAt = user.createdAt.toLocaleString(), + createdAtDelta = util.dateDelta(user.createdAt), + joinedAt = member?.joinedAt?.toLocaleString(), + joinedAtDelta = member && member.joinedAt ? util.dateDelta(member.joinedAt, 2) : undefined, + premiumSince = member?.premiumSince?.toLocaleString(), + premiumSinceDelta = member && member.premiumSince ? util.dateDelta(member.premiumSince, 2) : undefined; // General Info const generalInfo = [ @@ -95,27 +103,27 @@ export default class UserInfoCommand extends BushCommand { const serverUserInfo = []; if (joinedAt) serverUserInfo.push( - `**${message.guild.ownerId == user.id ? 'Created Server' : 'Joined'}: ** ${joinedAt} (${joinedAtDelta} ago)` + `**${message.guild!.ownerId == user.id ? 'Created Server' : 'Joined'}: ** ${joinedAt} (${joinedAtDelta} ago)` ); if (premiumSince) serverUserInfo.push(`**Boosting Since:** ${premiumSince} (${premiumSinceDelta} ago)`); - if (user.displayHexColor) serverUserInfo.push(`**Display Color:** ${user.displayHexColor}`); - if (user.id == '322862723090219008' && message.guild.id == client.consts.mappings.guilds.bush) + if (member?.displayHexColor) serverUserInfo.push(`**Display Color:** ${member.displayHexColor}`); + if (user.id == '322862723090219008' && message.guild?.id == client.consts.mappings.guilds.bush) serverUserInfo.push(`**General Deletions:** 1⅓`); if ( ['384620942577369088', '496409778822709251'].includes(user.id) && - message.guild.id == client.consts.mappings.guilds.bush + message.guild?.id == client.consts.mappings.guilds.bush ) serverUserInfo.push(`**General Deletions:** ⅓`); - if (user.nickname) serverUserInfo.push(`**Nickname** ${user.nickname}`); + if (member?.nickname) serverUserInfo.push(`**Nickname** ${member?.nickname}`); if (serverUserInfo.length) - userEmbed.addField('» Server Info', serverUserInfo.join('\n')).setColor(user.displayColor || util.colors.default); + userEmbed.addField('» Server Info', serverUserInfo.join('\n')).setColor(member?.displayColor ?? util.colors.default); // User Presence Info - if (user.presence?.status || user.presence?.clientStatus || user.presence?.activities) { + if (member?.presence?.status || member?.presence?.clientStatus || member?.presence?.activities) { let customStatus = ''; - const activitiesNames = []; - if (user.presence.activities) { - user.presence.activities.forEach((a) => { + const activitiesNames: string[] = []; + if (member.presence.activities) { + member.presence.activities.forEach((a) => { if (a.type == 'CUSTOM' && a.state) { const emoji = `${a.emoji ? `${a.emoji.toString()} ` : ''}`; customStatus = `${emoji}${a.state}`; @@ -124,9 +132,9 @@ export default class UserInfoCommand extends BushCommand { }); } let devices; - if (user.presence.clientStatus) devices = Object.keys(user.presence.clientStatus); + if (member?.presence.clientStatus) devices = Object.keys(member.presence.clientStatus); const presenceInfo = []; - if (user.presence.status) presenceInfo.push(`**Status:** ${user.presence.status}`); + if (member?.presence.status) presenceInfo.push(`**Status:** ${member.presence.status}`); if (devices && devices.length) presenceInfo.push(`**${devices.length - 1 ? 'Devices' : 'Device'}:** ${util.oxford(devices, 'and', '')}`); if (activitiesNames.length) @@ -137,12 +145,14 @@ export default class UserInfoCommand extends BushCommand { // Important Perms const perms = []; - if (user.permissions.has('ADMINISTRATOR') || message.guild.ownerId == user.id) { + if (member?.permissions.has('ADMINISTRATOR') || message.guild?.ownerId == user.id) { perms.push('`Administrator`'); - } else { - user.permissions.toArray(true).forEach((permission) => { - if (client.consts.mappings.permissions[permission]?.important) { - perms.push(`\`${client.consts.mappings.permissions[permission].name}\``); + } else if (member?.permissions.toArray(true).length) { + member.permissions.toArray(true).forEach((permission) => { + if (client.consts.mappings.permissions[permission as keyof typeof client.consts.mappings.permissions]?.important) { + perms.push( + `\`${client.consts.mappings.permissions[permission as keyof typeof client.consts.mappings.permissions].name}\`` + ); } }); } diff --git a/src/commands/moderation/_lockdown.ts b/src/commands/moderation/_lockdown.ts index 32dbd5b..b7bf4b2 100644 --- a/src/commands/moderation/_lockdown.ts +++ b/src/commands/moderation/_lockdown.ts @@ -35,7 +35,7 @@ export default class LockdownCommand extends BushCommand { public override async exec(message: BushMessage | BushSlashMessage, { all }: { all: boolean }): Promise<unknown> { return await message.util.reply('no'); if (!all) { - if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(message.channel.type)) + if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(message.channel!.type)) return message.util.reply(`${util.emojis.error} You can only lock down text and announcement channels.`); // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts index bda0e2b..e32bf18 100644 --- a/src/commands/moderation/ban.ts +++ b/src/commands/moderation/ban.ts @@ -90,15 +90,15 @@ export default class BanCommand extends BushCommand { force }: { user: User; reason?: { duration: number; contentWithoutTime: string }; days?: number; force: boolean } ): Promise<unknown> { - const member = message.guild.members.cache.get(user.id) as BushGuildMember; + const member = message.guild!.members.cache.get(user.id) as BushGuildMember; const useForce = force && message.author.isOwner(); - const canModerateResponse = util.moderationPermissionCheck(message.member, member, 'ban', true, useForce); + const canModerateResponse = util.moderationPermissionCheck(message.member!, member, 'ban', true, useForce); if (canModerateResponse !== true) { return message.util.reply(canModerateResponse); } - if (!Number.isInteger(days) || days < 0 || days > 7) { + if (!Number.isInteger(days) || days! < 0 || days! > 7) { return message.util.reply(`${util.emojis.error} The delete days must be an integer between 0 and 7.`); } @@ -109,12 +109,12 @@ export default class BanCommand extends BushCommand { ? await Argument.cast('duration', client.commandHandler.resolver, message as BushMessage, reason) : reason.duration; } - const parsedReason = reason.contentWithoutTime; + const parsedReason = reason?.contentWithoutTime ?? ''; const responseCode = await member.bushBan({ reason: parsedReason, moderator: message.author, - duration: time, + duration: time! ?? 0, deleteDays: days ?? 0 }); diff --git a/src/commands/moderation/kick.ts b/src/commands/moderation/kick.ts index 2fc133e..8864320 100644 --- a/src/commands/moderation/kick.ts +++ b/src/commands/moderation/kick.ts @@ -59,12 +59,12 @@ export default class KickCommand extends BushCommand { message: BushMessage | BushSlashMessage, { user, reason, force }: { user: BushUser; reason?: string; force: boolean } ): Promise<unknown> { - const member = message.guild.members.cache.get(user.id) as BushGuildMember; + const member = message.guild!.members.cache.get(user.id) as BushGuildMember; if (!member) return await message.util.reply(`${util.emojis.error} You cannot kick members that are not in the server.`); const useForce = force && message.author.isOwner(); - const canModerateResponse = util.moderationPermissionCheck(message.member, member, 'kick', true, useForce); + const canModerateResponse = util.moderationPermissionCheck(message.member!, member, 'kick', true, useForce); if (canModerateResponse !== true) { return message.util.reply(canModerateResponse); diff --git a/src/commands/moderation/modlog.ts b/src/commands/moderation/modlog.ts index 84bb5b5..04264b8 100644 --- a/src/commands/moderation/modlog.ts +++ b/src/commands/moderation/modlog.ts @@ -42,6 +42,7 @@ export default class ModlogCommand extends BushCommand { `**Moderator**: <@!${log.moderator}> (${log.moderator})` ]; if (log.duration) modLog.push(`**Duration**: ${util.humanizeDuration(log.duration)}`); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing modLog.push(`**Reason**: ${log.reason || 'No Reason Specified.'}`); if (log.evidence) modLog.push(`**Evidence:** ${log.evidence}`); return modLog.join(`\n`); @@ -55,7 +56,7 @@ export default class ModlogCommand extends BushCommand { if (foundUser) { const logs = await ModLog.findAll({ where: { - guild: message.guild.id, + guild: message.guild!.id, user: foundUser.id }, order: [['createdAt', 'ASC']] diff --git a/src/commands/moderation/mute.ts b/src/commands/moderation/mute.ts index 9f66558..e6c9065 100644 --- a/src/commands/moderation/mute.ts +++ b/src/commands/moderation/mute.ts @@ -61,11 +61,11 @@ export default class MuteCommand extends BushCommand { message: BushMessage | BushSlashMessage, { user, reason, force }: { user: BushUser; reason?: { duration: number; contentWithoutTime: string }; force: boolean } ): Promise<unknown> { - const member = message.guild.members.cache.get(user.id) as BushGuildMember; + const member = message.guild!.members.cache.get(user.id) as BushGuildMember; if (!member) return await message.util.reply(`${util.emojis.error} You cannot kick members that are not in the server.`); const useForce = force && message.author.isOwner(); - const canModerateResponse = util.moderationPermissionCheck(message.member, member, 'mute', true, useForce); + const canModerateResponse = util.moderationPermissionCheck(message.member!, member, 'mute', true, useForce); const victimBoldTag = `**${member.user.tag}**`; if (canModerateResponse !== true) { @@ -79,16 +79,16 @@ export default class MuteCommand extends BushCommand { ? await Argument.cast('duration', client.commandHandler.resolver, message as BushMessage, reason) : reason.duration; } - const parsedReason = reason.contentWithoutTime; + const parsedReason = reason?.contentWithoutTime ?? ''; const responseCode = await member.mute({ reason: parsedReason, moderator: message.author, - duration: time + duration: time! ?? 0 }); const responseMessage = async () => { - const prefix = await message.guild.getSetting('prefix'); + const prefix = await message.guild!.getSetting('prefix'); switch (responseCode) { case 'missing permissions': return `${util.emojis.error} Could not mute ${victimBoldTag} because I am missing the \`Manage Roles\` permission.`; diff --git a/src/commands/moderation/purge.ts b/src/commands/moderation/purge.ts index 4f1a5a6..b391ff6 100644 --- a/src/commands/moderation/purge.ts +++ b/src/commands/moderation/purge.ts @@ -1,3 +1,4 @@ +import { Message } from 'discord.js'; import { BushCommand, BushMessage } from '../../lib'; export default class PurgeCommand extends BushCommand { @@ -60,10 +61,10 @@ export default class PurgeCommand extends BushCommand { else { await message.util .send(`${util.emojis.success} Successfully purged **${purged.size}** messages.`) - .then(async (purgeMessage: BushMessage) => { + .then(async (purgeMessage) => { if (!message.util.isSlash) { await util.sleep(5); - await purgeMessage.delete().catch(() => {}); + await (purgeMessage as Message).delete().catch(() => {}); } }); } diff --git a/src/commands/moderation/removeReactionEmoji.ts b/src/commands/moderation/removeReactionEmoji.ts index 075b822..4dfd074 100644 --- a/src/commands/moderation/removeReactionEmoji.ts +++ b/src/commands/moderation/removeReactionEmoji.ts @@ -43,9 +43,9 @@ export default class RemoveReactionEmojiCommand extends BushCommand { const id = !['bigint', 'string'].includes(typeof emoji); const emojiID = !id ? `${emoji}` : (emoji as Emoji).id; const success = await messageToRemoveFrom.reactions.cache - .get(emojiID) - .remove() - .catch(() => {}); + ?.get(emojiID!) + ?.remove() + ?.catch(() => {}); if (success) { return await message.util.reply( `${util.emojis.success} Removed all reactions of \`${id ? emojiID : emoji}\` from the message with the id of \`${ diff --git a/src/commands/moderation/role.ts b/src/commands/moderation/role.ts index 0118f22..4575a11 100644 --- a/src/commands/moderation/role.ts +++ b/src/commands/moderation/role.ts @@ -94,26 +94,26 @@ export default class RoleCommand extends BushCommand { message: BushMessage | BushSlashMessage, { action, user, role, duration }: { action: 'add' | 'remove'; user: BushGuildMember; role: BushRole; duration: number } ): Promise<unknown> { - if (!message.member.permissions.has('MANAGE_ROLES')) { + if (!message.member!.permissions.has('MANAGE_ROLES')) { const mappings = client.consts.mappings; let mappedRole: { name: string; id: string }; for (let i = 0; i < mappings.roleMap.length; i++) { const a = mappings.roleMap[i]; if (a.id == role.id) mappedRole = a; } - if (!mappedRole || !mappings.roleWhitelist[mappedRole.name]) { + if (!mappedRole! || !mappings.roleWhitelist[mappedRole.name as keyof typeof mappings.roleWhitelist]) { return await message.util.reply({ content: `${util.emojis.error} <@&${role.id}> is not whitelisted, and you do not have manage roles permission.`, allowedMentions: AllowedMentions.none() }); } - const allowedRoles = mappings.roleWhitelist[mappedRole.name].map((r) => { + const allowedRoles = mappings.roleWhitelist[mappedRole.name as keyof typeof mappings.roleWhitelist].map((r) => { for (let i = 0; i < mappings.roleMap.length; i++) { if (mappings.roleMap[i].name == r) return mappings.roleMap[i].id; } return; }); - if (!message.member.roles.cache.some((role) => allowedRoles.includes(role.id))) { + if (!message.member!.roles.cache.some((role) => allowedRoles.includes(role.id))) { return await message.util.reply({ content: `${util.emojis.error} <@&${role.id}> is whitelisted, but you do not have any of the roles required to manage it.`, allowedMentions: AllowedMentions.none() @@ -125,8 +125,8 @@ export default class RoleCommand extends BushCommand { const responseCode = action === 'add' - ? await user.addRole({ moderator: message.member, addToModlog: shouldLog, role, duration }) - : await user.removeRole({ moderator: message.member, addToModlog: shouldLog, role, duration }); + ? await user.addRole({ moderator: message.member!, addToModlog: shouldLog, role, duration }) + : await user.removeRole({ moderator: message.member!, addToModlog: shouldLog, role, duration }); const responseMessage = () => { switch (responseCode) { diff --git a/src/commands/moderation/slowmode.ts b/src/commands/moderation/slowmode.ts index ec9a9de..1d47616 100644 --- a/src/commands/moderation/slowmode.ts +++ b/src/commands/moderation/slowmode.ts @@ -58,9 +58,9 @@ export default class SlowModeCommand extends BushCommand { channel: TextChannel | ThreadChannel | BushTextChannel | BushNewsChannel | BushThreadChannel | NewsChannel; } ): Promise<unknown> { - if (message.channel.type === 'DM') + if (message.channel!.type === 'DM') return await message.util.reply(`${util.emojis.error} This command cannot be run in dms.`); - if (!channel) channel = message.channel; + if (!channel) channel = message.channel as any; if (!(channel instanceof TextChannel) && !(channel instanceof ThreadChannel)) return await message.util.reply(`${util.emojis.error} <#${channel.id}> is not a text or thread channel.`); if (length) { diff --git a/src/commands/moderation/unban.ts b/src/commands/moderation/unban.ts index 545d75c..f13e7f6 100644 --- a/src/commands/moderation/unban.ts +++ b/src/commands/moderation/unban.ts @@ -58,7 +58,7 @@ export default class UnbanCommand extends BushCommand { if (!(user instanceof User)) { user = util.resolveUser(user, client.users.cache) as BushUser; } - const responseCode = await message.guild.unban({ + const responseCode = await message.guild!.unban({ user, moderator: message.author, reason diff --git a/src/commands/moderation/unmute.ts b/src/commands/moderation/unmute.ts index 918c27f..7e93d31 100644 --- a/src/commands/moderation/unmute.ts +++ b/src/commands/moderation/unmute.ts @@ -56,8 +56,8 @@ export default class UnmuteCommand extends BushCommand { { user, reason }: { user: BushUser; reason?: string } ): Promise<unknown> { const error = util.emojis.error; - const member = message.guild.members.cache.get(user.id) as BushGuildMember; - const canModerateResponse = util.moderationPermissionCheck(message.member, member, 'unmute'); + const member = message.guild!.members.cache.get(user.id) as BushGuildMember; + const canModerateResponse = util.moderationPermissionCheck(message.member!, member, 'unmute'); const victimBoldTag = `**${member.user.tag}**`; if (canModerateResponse !== true) { @@ -70,7 +70,7 @@ export default class UnmuteCommand extends BushCommand { }); const responseMessage = async () => { - const prefix = await message.guild.getSetting('prefix'); + const prefix = await message.guild!.getSetting('prefix'); switch (responseCode) { case 'missing permissions': return `${error} Could not unmute ${victimBoldTag} because I am missing the \`Manage Roles\` permission.`; diff --git a/src/commands/moderation/warn.ts b/src/commands/moderation/warn.ts index 1aa14c3..33ac2a3 100644 --- a/src/commands/moderation/warn.ts +++ b/src/commands/moderation/warn.ts @@ -59,9 +59,9 @@ export default class WarnCommand extends BushCommand { message: BushMessage | BushSlashMessage, { user, reason, force }: { user: BushUser; reason: string; force: boolean } ): Promise<unknown> { - const member = message.guild.members.cache.get(user.id) as BushGuildMember; + const member = message.guild!.members.cache.get(user.id) as BushGuildMember; const useForce = force && message.author.isOwner(); - const canModerateResponse = util.moderationPermissionCheck(message.member, member, 'warn', true, useForce); + const canModerateResponse = util.moderationPermissionCheck(message.member!, member, 'warn', true, useForce); const victimBoldTag = `**${member.user.tag}**`; if (canModerateResponse !== true) { @@ -81,12 +81,12 @@ export default class WarnCommand extends BushCommand { case 'failed to dm': return message.util.reply( `${util.emojis.warn} **${member.user.tag}** has been warned for the ${util.ordinal( - caseNum + caseNum ?? 0 )} time, however I could not send them a dm.` ); case 'success': return message.util.reply( - `${util.emojis.success} Successfully warned **${member.user.tag}** for the ${util.ordinal(caseNum)} time.` + `${util.emojis.success} Successfully warned **${member.user.tag}** for the ${util.ordinal(caseNum ?? 0)} time.` ); } } diff --git a/src/commands/moulberry-bush/capePerms.ts b/src/commands/moulberry-bush/capePerms.ts index eb1ab89..2481e3e 100644 --- a/src/commands/moulberry-bush/capePerms.ts +++ b/src/commands/moulberry-bush/capePerms.ts @@ -48,7 +48,7 @@ export default class CapePermissionsCommand extends BushCommand { perms: string[]; } - let capeperms: Capeperms, uuid: string; + let capeperms: Capeperms | null, uuid: string; try { uuid = await util.findUUID(args.ign); } catch (e) { diff --git a/src/commands/moulberry-bush/giveawayPing.ts b/src/commands/moulberry-bush/giveawayPing.ts index 4abc6ab..4caaf0c 100644 --- a/src/commands/moulberry-bush/giveawayPing.ts +++ b/src/commands/moulberry-bush/giveawayPing.ts @@ -24,7 +24,7 @@ export default class GiveawayPingCommand extends BushCommand { } public override async exec(message: BushMessage): Promise<unknown> { - if (!message.member.permissions.has('MANAGE_GUILD')) + if (!message.member!.permissions.has('MANAGE_GUILD')) await message.util.reply(`${util.emojis.error} You are missing the \`manage server\` permission.`); await message.delete().catch(() => {}); diff --git a/src/commands/moulberry-bush/level.ts b/src/commands/moulberry-bush/level.ts index c202863..02d66be 100644 --- a/src/commands/moulberry-bush/level.ts +++ b/src/commands/moulberry-bush/level.ts @@ -36,7 +36,8 @@ export default class LevelCommand extends BushCommand { required: false } ], - slash: true + slash: true, + channel: 'guild' }); } @@ -143,6 +144,7 @@ export default class LevelCommand extends BushCommand { // 'lel.png' // ) // ); - await message.reply(await this.getResponse(user || message.author, message.guild)); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + await message.reply(await this.getResponse(user || message.author, message.guild!)); } } diff --git a/src/commands/moulberry-bush/report.ts b/src/commands/moulberry-bush/report.ts index e91420b..878337b 100644 --- a/src/commands/moulberry-bush/report.ts +++ b/src/commands/moulberry-bush/report.ts @@ -59,7 +59,7 @@ export default class ReportCommand extends BushCommand { message: BushMessage, { member, evidence }: { member: GuildMember; evidence: string } ): Promise<unknown> { - if (message.guild.id != client.consts.mappings.guilds.bush) + if (message.guild!.id != client.consts.mappings.guilds.bush) return await message.util.reply(`${util.emojis.error} This command can only be run in Moulberry's bush.`); if (!member) return await message.util.reply(`${util.emojis.error} Choose someone to report`); if (member.user.id === '322862723090219008') @@ -76,14 +76,14 @@ export default class ReportCommand extends BushCommand { const reportEmbed = new MessageEmbed() .setFooter(`Reporter ID: ${message.author.id} Reported ID: ${member.user.id}`) .setTimestamp() - .setAuthor(`Report From: ${message.author.tag}`, message.author.avatarURL({ dynamic: true })) + .setAuthor(`Report From: ${message.author.tag}`, message.author.avatarURL({ dynamic: true }) ?? undefined) .setTitle('New Report') .setColor(util.colors.red) .setDescription(evidence) .addField( 'Reporter', `**Name:**${message.author.tag} <@${message.author.id}>\n**Joined:** ${moment( - message.member.joinedTimestamp + message.member!.joinedTimestamp ).fromNow()}\n**Created:** ${moment(message.author.createdTimestamp).fromNow()}\n**Sent From**: <#${ message.channel.id }> [Jump to context](${message.url})`, @@ -99,11 +99,11 @@ export default class ReportCommand extends BushCommand { //reusing code pog if (message.attachments.size > 0) { - const fileName = message.attachments.first().name.toLowerCase(); + const fileName = message.attachments.first()!.name!.toLowerCase(); if (fileName.endsWith('.png') || fileName.endsWith('.jpg') || fileName.endsWith('.gif') || fileName.endsWith('.webp')) { - reportEmbed.setImage(message.attachments.first().url); + reportEmbed.setImage(message.attachments.first()!.url); } else { - reportEmbed.addField('Attachment', message.attachments.first().url); + reportEmbed.addField('Attachment', message.attachments.first()!.url); } } const reportChannel = client.channels.cache.get('782972723654688848') as unknown as BushTextChannel; diff --git a/src/commands/moulberry-bush/rule.ts b/src/commands/moulberry-bush/rule.ts index eb767a8..bf44dad 100644 --- a/src/commands/moulberry-bush/rule.ts +++ b/src/commands/moulberry-bush/rule.ts @@ -106,10 +106,10 @@ export default class RuleCommand extends BushCommand { public override async exec(message: BushMessage, { rule, user }: { rule: undefined | number; user: User }): Promise<unknown> { const rulesEmbed = new MessageEmbed() .setColor('#ef3929') - .setFooter(`Triggered by ${message.author.tag}`, message.author.avatarURL({ dynamic: true })) + .setFooter(`Triggered by ${message.author.tag}`, message.author.avatarURL({ dynamic: true }) ?? undefined) .setTimestamp(); - if (rule > 12 || rule < 1) { + if (rule !== undefined && (rule > 12 || rule < 1)) { rule = undefined; } if (rule) { @@ -131,7 +131,7 @@ export default class RuleCommand extends BushCommand { // If the original message was a reply -> imitate it message.reference?.messageId && !message.util.isSlash ? await message.channel.messages.fetch(message.reference.messageId).then(async (message) => { - await message.util.reply({ embeds: [rulesEmbed], allowedMentions: AllowedMentions.users() }); + await message.util!.reply({ embeds: [rulesEmbed], allowedMentions: AllowedMentions.users() }); }) : await message.util.send({ embeds: [rulesEmbed], allowedMentions: AllowedMentions.users() }) ); diff --git a/src/commands/skyblock-reborn/chooseColor.ts b/src/commands/skyblock-reborn/chooseColor.ts index 4be2243..1d86899 100644 --- a/src/commands/skyblock-reborn/chooseColor.ts +++ b/src/commands/skyblock-reborn/chooseColor.ts @@ -122,7 +122,7 @@ export default class ChooseColorCommand extends BushCommand { message: BushMessage | BushSlashMessage, args: { color: Role | RoleResolvable } ): Promise<unknown> { - if (message.guild.id != client.consts.mappings.guilds.sbr) { + if (message.guild!.id != client.consts.mappings.guilds.sbr) { return await message.util.reply(`${util.emojis.error} This command can only be run in Skyblock: Reborn.`); } const allowedRoles: Snowflake[] = [ @@ -134,7 +134,7 @@ export default class ChooseColorCommand extends BushCommand { !( allowedRoles.some((role) => (message.member as BushGuildMember).roles.cache.has(role)) || (message.member as BushGuildMember).permissions.has('ADMINISTRATOR') || - message.guild.ownerId === message.author.id + message.guild!.ownerId === message.author.id ) ) { const allowed = util.oxford( diff --git a/src/commands/utilities/activity.ts b/src/commands/utilities/activity.ts index 0962fff..8bdfc21 100644 --- a/src/commands/utilities/activity.ts +++ b/src/commands/utilities/activity.ts @@ -1,4 +1,4 @@ -import { VoiceChannel } from 'discord.js'; +import { Message, VoiceChannel } from 'discord.js'; import { BushCommand, BushMessage, BushSlashMessage } from '../../lib'; const activityMap = { @@ -9,7 +9,7 @@ const activityMap = { 'Chess in the Park': '832012774040141894' }; -function map(phase) { +function map(phase: string) { if (['yt', 'youtube'].includes(phase)) return activityMap['YouTube Together']; else if (['chess', 'park'].includes(phase)) return activityMap['Chess in the Park']; else if (['poker'].includes(phase)) return activityMap['Poker Night']; @@ -19,7 +19,7 @@ function map(phase) { } // eslint-disable-next-line @typescript-eslint/no-unused-vars -const activityTypeCaster = (_message: BushMessage, phrase: string) => { +const activityTypeCaster = (_message: Message, phrase: string) => { if (!phrase) return null; const mappedPhrase = map(phrase); if (mappedPhrase) return mappedPhrase; diff --git a/src/commands/utilities/decode.ts b/src/commands/utilities/decode.ts index 9f56cfc..05e988a 100644 --- a/src/commands/utilities/decode.ts +++ b/src/commands/utilities/decode.ts @@ -95,17 +95,20 @@ export default class DecodeCommand extends BushCommand { message: BushMessage | AkairoMessage, { from, to, data }: { from: BufferEncoding; to: BufferEncoding; data: string } ): Promise<unknown> { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const encodeOrDecode = util.capitalizeFirstLetter(message?.util?.parsed?.alias || 'decoded'); const decodedEmbed = new MessageEmbed() .setTitle(`${encodeOrDecode} Information`) - .addField('📥 Input', await util.inspectCleanRedactCodeblock(data, null)); + .addField('📥 Input', await util.inspectCleanRedactCodeblock(data, undefined)); try { const decoded = Buffer.from(data, from).toString(to); - decodedEmbed.setColor(util.colors.success).addField('📤 Output', await util.inspectCleanRedactCodeblock(decoded, null)); + decodedEmbed + .setColor(util.colors.success) + .addField('📤 Output', await util.inspectCleanRedactCodeblock(decoded, undefined)); } catch (error) { decodedEmbed .setColor(util.colors.error) - .addField(`📤 Error ${encodeOrDecode.slice(1)}ing`, await util.inspectCleanRedactCodeblock(error.stack, null)); + .addField(`📤 Error ${encodeOrDecode.slice(1)}ing`, await util.inspectCleanRedactCodeblock(error.stack, undefined)); } return await message.util.reply({ embeds: [decodedEmbed], allowedMentions: AllowedMentions.none() }); } diff --git a/src/commands/utilities/price.ts b/src/commands/utilities/price.ts index a68c01d..921784f 100644 --- a/src/commands/utilities/price.ts +++ b/src/commands/utilities/price.ts @@ -112,6 +112,8 @@ export default class PriceCommand extends BushCommand { let parsedItem = item.toString().toUpperCase().replace(/ /g, '_').replace(/'S/g, ''); const priceEmbed = new MessageEmbed(); + if (bazaar?.success === false) errors.push('bazaar'); + if (errors?.length) { priceEmbed.setFooter(`Could not fetch data from ${util.oxford(errors, 'and', '')}`); } @@ -127,8 +129,8 @@ export default class PriceCommand extends BushCommand { // fuzzy search if (!strict) parsedItem = new Fuse(Array.from(itemNames))?.search(parsedItem)[0]?.item; - // iif bazaar item then it there should not be any ah data - if (bazaar['products'][parsedItem]) { + // if its a bazaar item then it there should not be any ah data + if (bazaar['products']?.[parsedItem]) { const bazaarPriceEmbed = new MessageEmbed() .setColor(errors?.length ? util.colors.warn : util.colors.success) .setTitle(`Bazaar Information for **${parsedItem}**`) @@ -168,8 +170,12 @@ export default class PriceCommand extends BushCommand { return await message.util.reply({ embeds: [priceEmbed] }); // helper functions - function addBazaarInformation(Information: string, digits: number, commas: boolean): string { - const price = bazaar?.products[parsedItem]?.quick_status?.[Information]; + function addBazaarInformation( + Information: keyof Bazaar['products'][string]['quick_status'], + digits: number, + commas: boolean + ): string { + const price = bazaar?.products?.[parsedItem]?.quick_status?.[Information]; const roundedPrice = Number(Number(price).toFixed(digits)); return commas ? roundedPrice?.toLocaleString() : roundedPrice?.toString(); } diff --git a/src/commands/utilities/viewraw.ts b/src/commands/utilities/viewraw.ts index e783dec..f6be382 100644 --- a/src/commands/utilities/viewraw.ts +++ b/src/commands/utilities/viewraw.ts @@ -70,18 +70,21 @@ export default class ViewRawCommand extends BushCommand { return await message.util.reply({ embeds: [messageEmbed] }); } - public static async getRawData(message: BushMessage, options: { json?: boolean; js: boolean }): Promise<unknown> { + public static async getRawData(message: BushMessage, options: { json?: boolean; js: boolean }): Promise<MessageEmbed> { const content = options.json || options.js ? options.json ? inspect(JSON.stringify(message.toJSON())) : inspect(message.toJSON()) || '[No Content]' : message.content || '[No Content]'; - return new MessageEmbed() - .setFooter(message.author.tag, message.author.avatarURL({ dynamic: true })) - .setTimestamp(message.createdTimestamp) - .setColor(message.member?.roles?.color?.color || util.colors.default) - .setTitle('Raw Message Information') - .setDescription(await util.codeblock(content, 2048, 'js')); + return ( + new MessageEmbed() + .setFooter(message.author.tag, message.author.avatarURL({ dynamic: true }) ?? undefined) + .setTimestamp(message.createdTimestamp) + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + .setColor(message.member?.roles?.color?.color || util.colors.default) + .setTitle('Raw Message Information') + .setDescription(await util.codeblock(content, 2048, 'js')) + ); } } diff --git a/src/inhibitors/blacklist/channelGlobalBlacklist.ts b/src/inhibitors/blacklist/channelGlobalBlacklist.ts index 7a1d27d..9bbf30f 100644 --- a/src/inhibitors/blacklist/channelGlobalBlacklist.ts +++ b/src/inhibitors/blacklist/channelGlobalBlacklist.ts @@ -10,12 +10,13 @@ export default class UserGlobalBlacklistInhibitor extends BushInhibitor { } public override exec(message: BushMessage | BushSlashMessage): boolean { - if (!message.author) return false; - if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user.id === message.author.id) + if (!message.author || !message.guild) return false; + if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user!.id === message.author.id) return false; - if (client.cache.global.blacklistedChannels.includes(message.channel.id)) { + if (client.cache.global.blacklistedChannels.includes(message.channel!.id)) { // client.console.debug(`channelGlobalBlacklist blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/blacklist/channelGuildBlacklist.ts b/src/inhibitors/blacklist/channelGuildBlacklist.ts index be338fe..b4c6f3f 100644 --- a/src/inhibitors/blacklist/channelGuildBlacklist.ts +++ b/src/inhibitors/blacklist/channelGuildBlacklist.ts @@ -11,11 +11,12 @@ export default class ChannelGuildBlacklistInhibitor extends BushInhibitor { public override async exec(message: BushMessage | BushSlashMessage): Promise<boolean> { if (!message.author || !message.guild) return false; - if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user.id === message.author.id) + if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user!.id === message.author.id) return false; - if ((await message.guild.getSetting('blacklistedChannels'))?.includes(message.channel.id)) { + if ((await message.guild.getSetting('blacklistedChannels'))?.includes(message.channel!.id)) { // client.console.debug(`channelGuildBlacklist blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/blacklist/guildBlacklist.ts b/src/inhibitors/blacklist/guildBlacklist.ts index afaae9d..de15d76 100644 --- a/src/inhibitors/blacklist/guildBlacklist.ts +++ b/src/inhibitors/blacklist/guildBlacklist.ts @@ -13,12 +13,13 @@ export default class GuildBlacklistInhibitor extends BushInhibitor { if (!message.guild) return false; if ( message.author && - (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user.id === message.author.id) + (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user!.id === message.author.id) ) return false; if (client.cache.global.blacklistedGuilds.includes(message.guild.id)) { // client.console.debug(`GuildBlacklistInhibitor blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/blacklist/userGlobalBlacklist.ts b/src/inhibitors/blacklist/userGlobalBlacklist.ts index 1173d87..967943d 100644 --- a/src/inhibitors/blacklist/userGlobalBlacklist.ts +++ b/src/inhibitors/blacklist/userGlobalBlacklist.ts @@ -11,11 +11,12 @@ export default class UserGlobalBlacklistInhibitor extends BushInhibitor { public override exec(message: BushMessage | BushSlashMessage): boolean { if (!message.author) return false; - if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user.id === message.author.id) + if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user!.id === message.author.id) return false; if (client.cache.global.blacklistedUsers.includes(message.author.id)) { // client.console.debug(`userGlobalBlacklist blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/blacklist/userGuildBlacklist.ts b/src/inhibitors/blacklist/userGuildBlacklist.ts index 95ba17a..0e28ba4 100644 --- a/src/inhibitors/blacklist/userGuildBlacklist.ts +++ b/src/inhibitors/blacklist/userGuildBlacklist.ts @@ -11,11 +11,12 @@ export default class UserGuildBlacklistInhibitor extends BushInhibitor { public override async exec(message: BushMessage | BushSlashMessage): Promise<boolean> { if (!message.author || !message.guild) return false; - if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user.id === message.author.id) + if (client.isOwner(message.author) || client.isSuperUser(message.author) || client.user!.id === message.author.id) return false; if ((await message.guild.getSetting('blacklistedUsers'))?.includes(message.author.id)) { // client.console.debug(`userGuildBlacklist blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/commands/globalDisabledCommand.ts b/src/inhibitors/commands/globalDisabledCommand.ts index 4c85c3b..9a750cc 100644 --- a/src/inhibitors/commands/globalDisabledCommand.ts +++ b/src/inhibitors/commands/globalDisabledCommand.ts @@ -15,5 +15,6 @@ export default class DisabledGuildCommandInhibitor extends BushInhibitor { client.console.debug(`disabledGlobalCommand blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/commands/guildDisabledCommand.ts b/src/inhibitors/commands/guildDisabledCommand.ts index b21e1ef..ee798e5 100644 --- a/src/inhibitors/commands/guildDisabledCommand.ts +++ b/src/inhibitors/commands/guildDisabledCommand.ts @@ -10,12 +10,13 @@ export default class DisabledGuildCommandInhibitor extends BushInhibitor { } public override async exec(message: BushMessage | BushSlashMessage, command: BushCommand): Promise<boolean> { - if (!message.guild || !message.guild) return; + if (!message.guild || !message.guild) return false; if (message.author.isOwner() || message.author.isSuperUser()) return false; // super users bypass guild disabled commands if ((await message.guild.getSetting('disabledCommands'))?.includes(command?.id)) { client.console.debug(`disabledGuildCommand blocked message.`); return true; } + return false; } } diff --git a/src/inhibitors/noCache.ts b/src/inhibitors/noCache.ts index 6bb2001..673f3ac 100644 --- a/src/inhibitors/noCache.ts +++ b/src/inhibitors/noCache.ts @@ -12,7 +12,7 @@ export default class NoCacheInhibitor extends BushInhibitor { public override async exec(message: BushMessage | BushSlashMessage): Promise<boolean> { if (client.isOwner(message.author)) return false; for (const property in client.cache.global) { - if (!client.cache.global[property]) { + if (!client.cache.global[property as keyof typeof client.cache.global]) { client.console.debug(`NoCacheInhibitor blocked message.`); return true; } diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index 5b9ac1b..3feae96 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -2,7 +2,6 @@ import chalk from 'chalk'; import { AkairoClient } from 'discord-akairo'; import { Collection, - Guild, Intents, InteractionReplyOptions, Message, @@ -182,7 +181,7 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re // Create command handler this.commandHandler = new BushCommandHandler(this, { directory: path.join(__dirname, '..', '..', '..', 'commands'), - prefix: async ({ guild }: { guild: Guild }) => { + prefix: async ({ guild }: Message) => { if (this.config.isDevelopment) return 'dev '; if (!guild) return this.config.prefix; const row = await GuildModel.findByPk(guild.id); @@ -262,7 +261,7 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re }; for (const loader of Object.keys(loaders)) { try { - loaders[loader].loadAll(); + loaders[loader as keyof typeof loaders].loadAll(); void this.logger.success('Startup', `Successfully loaded <<${loader}>>.`, false); } catch (e) { void this.logger.error('Startup', `Unable to load loader <<${loader}>> with error:\n${e?.stack || e}`, false); @@ -271,7 +270,7 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re await this.dbPreInit(); await UpdateCacheTask.init(this); void this.console.success('Startup', `Successfully created <<cache>>.`, false); - this.taskHandler.startAll(); + this.taskHandler.startAll!(); } public async dbPreInit(): Promise<void> { @@ -302,7 +301,7 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re try { await this.#init(); - await this.login(this.token); + await this.login(this.token!); } catch (e) { await this.console.error('Start', chalk.red(e?.stack || e), false); exit(2); @@ -313,15 +312,15 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re public override destroy(relogin = false): void | Promise<string> { super.destroy(); if (relogin) { - return this.login(this.token); + return this.login(this.token!); } } public override isOwner(user: BushUserResolvable): boolean { - return this.config.owners.includes(this.users.resolveId(user)); + return this.config.owners.includes(this.users.resolveId(user!)!); } public override isSuperUser(user: BushUserResolvable): boolean { - const userID = this.users.resolveId(user); + const userID = this.users.resolveId(user)!; return !!BushCache?.global?.superUsers?.includes(userID) || this.config.owners.includes(userID); } } diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts index 4f9f09b..88985e1 100644 --- a/src/lib/extensions/discord-akairo/BushClientUtil.ts +++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts @@ -597,7 +597,7 @@ export class BushClientUtil extends ClientUtil { const mentionMatch = text.match(mentionReg); if (mentionMatch) { try { - return await client.users.fetch(mentionMatch.groups.id as Snowflake); + return await client.users.fetch(mentionMatch.groups!.id as Snowflake); } catch { // pass } @@ -626,8 +626,8 @@ export class BushClientUtil extends ClientUtil { */ public chunk<T>(arr: T[], perChunk: number): T[][] { return arr.reduce((all, one, i) => { - const ch = Math.floor(i / perChunk); - all[ch] = [].concat(all[ch] || [], one); + const ch: number = Math.floor(i / perChunk); + (all as any[])[ch] = [].concat(all[ch] || [], one as any); return all; }, []); } @@ -668,7 +668,11 @@ export class BushClientUtil extends ClientUtil { mad: '<:mad:783046135392239626>', join: '<:join:850198029809614858>', leave: '<:leave:850198048205307919>', - loading: '<a:Loading:853419254619963392>' + loading: '<a:Loading:853419254619963392>', + offlineCircle: '<:offline:787550565382750239>', + dndCircle: '<:dnd:787550487633330176>', + idleCircle: '<:idle:787550520956551218>', + onlineCircle: '<:online:787550449435803658>' }; /** @@ -716,6 +720,7 @@ export class BushClientUtil extends ClientUtil { let curPage = 0; if (typeof embeds !== 'object') throw new Error('embeds must be an object'); const msg = (await message.util.reply({ + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing content: text || null, embeds: [embeds[curPage]], components: [getPaginationRow()] @@ -886,7 +891,7 @@ export class BushClientUtil extends ClientUtil { ['betaToken']: 'Beta Token', ['hypixelApiKey']: 'Hypixel Api Key' }; - return mapping[old] || old; + return mapping[old as keyof typeof mapping] || old; } /** @@ -894,7 +899,7 @@ export class BushClientUtil extends ClientUtil { */ public redact(text: string) { for (const credentialName in client.config.credentials) { - const credential = client.config.credentials[credentialName]; + const credential = client.config.credentials[credentialName as keyof typeof client.config.credentials]; const replacement = this.#mapCredential(credentialName); const escapeRegex = /[.*+?^${}()|[\]\\]/g; text = text.replace(new RegExp(credential.toString().replace(escapeRegex, '\\$&'), 'g'), `[${replacement} Omitted]`); @@ -908,7 +913,7 @@ export class BushClientUtil extends ClientUtil { public async inspectCleanRedactCodeblock( input: any, - language: CodeBlockLang, + language?: CodeBlockLang, inspectOptions?: BushInspectOptions, length = 1024 ) { @@ -950,7 +955,7 @@ export class BushClientUtil extends ClientUtil { public async slashRespond( interaction: CommandInteraction, responseOptions: BushSlashSendMessageType | BushSlashEditMessageType - ): Promise<Message | APIMessage> { + ): Promise<Message | APIMessage | undefined> { let newResponseOptions: BushSlashSendMessageType | BushSlashEditMessageType = {}; if (typeof responseOptions === 'string') { newResponseOptions.content = responseOptions; @@ -985,7 +990,7 @@ export class BushClientUtil extends ClientUtil { * const permissions = oxford(['ADMINISTRATOR', 'SEND_MESSAGES', 'MANAGE_MESSAGES'], 'and', 'none'); * console.log(permissions); // ADMINISTRATOR, SEND_MESSAGES and MANAGE_MESSAGES */ - public oxford(array: string[], conjunction: string, ifEmpty: string): string { + public oxford(array: string[], conjunction: string, ifEmpty?: string): string | undefined { const l = array.length; if (!l) return ifEmpty; if (l < 2) return array[0]; @@ -1000,7 +1005,8 @@ export class BushClientUtil extends ClientUtil { key: keyof typeof BushCache['global'], value: any ): Promise<Global | void> { - const row = await Global.findByPk(client.config.environment); + const row = + (await Global.findByPk(client.config.environment)) ?? (await Global.create({ environment: client.config.environment })); const oldValue: any[] = row[key]; const newValue = this.addOrRemoveFromArray(action, oldValue, value); row[key] = newValue; @@ -1010,7 +1016,7 @@ export class BushClientUtil extends ClientUtil { public addOrRemoveFromArray(action: 'add' | 'remove', array: any[], value: any): any[] { let newValue: any[]; - if (!array) return null; + if (!array) throw new Error('array is either null or undefined'); if (action === 'add') { if (!array.includes(action)) array.push(value); newValue = array; @@ -1029,14 +1035,14 @@ export class BushClientUtil extends ClientUtil { * @returns {string[]} */ public surroundArray(array: string[], surroundChar1: string, surroundChar2?: string): string[] { - const newArray = []; + const newArray: string[] = []; array.forEach((a) => { - newArray.push(`${surroundChar1}${a}${surroundChar2 || surroundChar1}`); + newArray.push(`${surroundChar1}${a}${surroundChar2 ?? surroundChar1}`); }); return newArray; } - public parseDuration(content: string, remove = true): { duration: number; contentWithoutTime: string } { + public parseDuration(content: string, remove = true): { duration: number; contentWithoutTime: string | null } { if (!content) return { duration: 0, contentWithoutTime: null }; let duration = 0; @@ -1047,6 +1053,7 @@ export class BushClientUtil extends ClientUtil { for (const unit in BushConstants.TimeUnits) { const regex = BushConstants.TimeUnits[unit].match; const match = regex.exec(contentWithoutTime); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const value = Number(match?.groups?.[unit] || 0); duration += value * BushConstants.TimeUnits[unit].value; @@ -1086,7 +1093,7 @@ export class BushClientUtil extends ClientUtil { if (moderator.roles.highest.position <= victim.roles.highest.position && !isOwner) { return `${util.emojis.error} You cannot ${type} **${victim.user.tag}** because they have higher or equal role hierarchy as you do.`; } - if (victim.roles.highest.position >= victim.guild.me.roles.highest.position) { + if (victim.roles.highest.position >= victim.guild.me!.roles.highest.position) { return `${util.emojis.error} You cannot ${type} **${victim.user.tag}** because they have higher or equal role hierarchy as I do.`; } if (checkModerator && victim.permissions.has('MANAGE_MESSAGES')) { @@ -1100,16 +1107,17 @@ export class BushClientUtil extends ClientUtil { type: ModLogType; user: BushGuildMemberResolvable; moderator: BushGuildMemberResolvable; - reason: string; + reason: string | undefined; duration?: number; guild: BushGuildResolvable; }, getCaseNumber = false - ): Promise<{ log: ModLog; caseNum: number }> { - const user = client.users.resolveId(options.user); - const moderator = client.users.resolveId(options.moderator); - const guild = client.guilds.resolveId(options.guild); - const duration = options.duration || null; + ): Promise<{ log: ModLog | null; caseNum: number | null }> { + const user = client.users.resolveId(options.user)!; + const moderator = client.users.resolveId(options.moderator)!; + const guild = client.guilds.resolveId(options.guild)!; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const duration = options.duration || undefined; // If guild does not exist create it so the modlog can reference a guild. await Guild.findOrCreate({ @@ -1129,7 +1137,7 @@ export class BushClientUtil extends ClientUtil { duration: duration, guild }); - const saveResult: ModLog = await modLogEntry.save().catch((e) => { + const saveResult: ModLog | null = await modLogEntry.save().catch((e) => { void client.console.error('createModLogEntry', e?.stack || e); return null; }); @@ -1143,15 +1151,15 @@ export class BushClientUtil extends ClientUtil { public async createPunishmentEntry(options: { type: 'mute' | 'ban' | 'role' | 'block'; user: BushGuildMemberResolvable; - duration: number; + duration: number | undefined; guild: BushGuildResolvable; modlog: string; extraInfo?: Snowflake; - }): Promise<ActivePunishment> { - const expires = options.duration ? new Date(new Date().getTime() + options.duration) : null; - const user = client.users.resolveId(options.user); - const guild = client.guilds.resolveId(options.guild); - const type = this.#findTypeEnum(options.type); + }): Promise<ActivePunishment | null> { + const expires = options.duration ? new Date(new Date().getTime() + options.duration) : undefined; + const user = client.users.resolveId(options.user)!; + const guild = client.guilds.resolveId(options.guild)!; + const type = this.#findTypeEnum(options.type)!; const entry = options.extraInfo ? ActivePunishment.build({ user, type, guild, expires, modlog: options.modlog, extraInfo: options.extraInfo }) @@ -1266,7 +1274,7 @@ export class BushClientUtil extends ClientUtil { * @param types - Types to use. */ public compose(...types: BushArgumentType[]): ArgumentTypeCaster { - return Argument.compose(types); + return Argument.compose(...types); } /** @@ -1275,7 +1283,7 @@ export class BushClientUtil extends ClientUtil { * @param types - Types to use. */ public composeWithFailure(...types: BushArgumentType[]): ArgumentTypeCaster { - return Argument.composeWithFailure(types); + return Argument.composeWithFailure(...types); } /** @@ -1292,7 +1300,7 @@ export class BushClientUtil extends ClientUtil { * @param types - Types to use. */ public product(...types: BushArgumentType[]): ArgumentTypeCaster { - return Argument.product(types); + return Argument.product(...types); } /** @@ -1323,7 +1331,7 @@ export class BushClientUtil extends ClientUtil { * @param types - Types to use. */ public taggedUnion(...types: BushArgumentType[]): ArgumentTypeCaster { - return Argument.taggedUnion(types); + return Argument.taggedUnion(...types); } /** @@ -1342,7 +1350,7 @@ export class BushClientUtil extends ClientUtil { * @param types - Types to use. */ public union(...types: BushArgumentType[]): ArgumentTypeCaster { - return Argument.union(types); + return Argument.union(...types); } /** diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts index 9f91905..0eaa5e0 100644 --- a/src/lib/extensions/discord-akairo/BushCommand.ts +++ b/src/lib/extensions/discord-akairo/BushCommand.ts @@ -127,7 +127,7 @@ export interface CustomBushArgumentOptions extends BaseBushArgumentOptions { * A regular expression can also be used. * The evaluated argument will be an object containing the `match` and `matches` if global. */ - customType?: ArgumentTypeCaster | (string | string[])[] | RegExp | string; + customType?: ArgumentTypeCaster | (string | string[])[] | RegExp | string | null; } export interface BushCommandOptions extends CommandOptions { @@ -163,22 +163,23 @@ export class BushCommand extends Command { /** Completely hide this command from the help command. */ public completelyHide: boolean; - public constructor(id: string, options?: BushCommandOptions) { + public constructor(id: string, options: BushCommandOptions) { if (options.args && typeof options.args !== 'function') { options.args.forEach((_, index: number) => { - if ('customType' in options.args[index]) { + if ('customType' in options.args![index]) { // @ts-expect-error: shut if (!options.args[index]['type']) options.args[index]['type'] = options.args[index]['customType']; - delete options.args[index]['customType']; + delete options.args![index]['customType']; } }); } super(id, options); this.options = options; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing this.hidden = options.hidden || false; - this.restrictedChannels = options.restrictedChannels; - this.restrictedGuilds = options.restrictedGuilds; - this.completelyHide = options.completelyHide; + this.restrictedChannels = options.restrictedChannels!; + this.restrictedGuilds = options.restrictedGuilds!; + this.completelyHide = options.completelyHide!; } public override exec(message: BushMessage, args: any): any; diff --git a/src/lib/extensions/discord-akairo/BushListener.ts b/src/lib/extensions/discord-akairo/BushListener.ts index 59b6162..b98bb02 100644 --- a/src/lib/extensions/discord-akairo/BushListener.ts +++ b/src/lib/extensions/discord-akairo/BushListener.ts @@ -5,7 +5,7 @@ export class BushListener extends Listener { public declare client: BushClient; public constructor( id: string, - options?: { emitter: string | EventEmitter; event: string; type?: 'on' | 'once'; category?: string } + options: { emitter: string | EventEmitter; event: string; type?: 'on' | 'once'; category?: string } ) { super(id, options); } diff --git a/src/lib/extensions/discord-akairo/BushTask.ts b/src/lib/extensions/discord-akairo/BushTask.ts index b315270..1b14a2b 100644 --- a/src/lib/extensions/discord-akairo/BushTask.ts +++ b/src/lib/extensions/discord-akairo/BushTask.ts @@ -3,7 +3,7 @@ import { BushClient } from './BushClient'; export class BushTask extends Task { public declare client: BushClient; - public constructor(id: string, options?: TaskOptions) { + public constructor(id: string, options: TaskOptions) { super(id, options); } } diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts index dafa1a4..81c0108 100644 --- a/src/lib/extensions/discord.js/BushGuild.ts +++ b/src/lib/extensions/discord.js/BushGuild.ts @@ -41,8 +41,8 @@ export class BushGuild extends Guild { | 'error creating modlog entry' | 'error removing ban entry' > { - const user = client.users.resolveId(options.user); - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)); + const user = client.users.resolveId(options.user)!; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!)!; const bans = await this.bans.fetch(); @@ -50,6 +50,7 @@ export class BushGuild extends Guild { if (!bans.has(user)) notBanned = true; const unbanSuccess = await this.bans + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .remove(user, `${moderator.tag} | ${options.reason || 'No reason provided.'}`) .catch((e) => { if (e?.code === 'UNKNOWN_BAN') { @@ -84,6 +85,7 @@ export class BushGuild extends Guild { const userObject = client.users.cache.get(user); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing userObject?.send(`You have been unbanned from **${this}** for **${options.reason || 'No reason provided'}**.`); if (notBanned) return 'user not banned'; diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts index 7db31c5..641cc74 100644 --- a/src/lib/extensions/discord.js/BushGuildMember.ts +++ b/src/lib/extensions/discord.js/BushGuildMember.ts @@ -80,8 +80,8 @@ export class BushGuildMember extends GuildMember { super(client, data, guild); } - public async warn(options: BushPunishmentOptions): Promise<{ result: WarnResponse; caseNum: number }> { - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + public async warn(options: BushPunishmentOptions): Promise<{ result: WarnResponse | null; caseNum: number | null }> { + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; // add modlog entry const result = await util.createModLogEntry( { @@ -98,6 +98,7 @@ export class BushGuildMember extends GuildMember { // dm user const ending = await this.guild.getSetting('punishmentEnding'); const dmSuccess = await this.send({ + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing content: `You have been warned in **${this.guild}** for **${options.reason || 'No reason provided'}**.${ ending ? `\n\n${ending}` : '' }` @@ -112,7 +113,7 @@ export class BushGuildMember extends GuildMember { const ifShouldAddRole = this.#checkIfShouldAddRole(options.role); if (ifShouldAddRole !== true) return ifShouldAddRole; - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; if (options.addToModlog) { const { log: modlog } = await util.createModLogEntry({ @@ -147,7 +148,7 @@ export class BushGuildMember extends GuildMember { const ifShouldAddRole = this.#checkIfShouldAddRole(options.role); if (ifShouldAddRole !== true) return ifShouldAddRole; - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; if (options.addToModlog) { const { log: modlog } = await util.createModLogEntry({ @@ -180,7 +181,7 @@ export class BushGuildMember extends GuildMember { return 'user hierarchy'; } else if (role.managed) { return 'role managed'; - } else if (this.guild.me.roles.highest.position <= role.position) { + } else if (this.guild.me!.roles.highest.position <= role.position) { return 'client hierarchy'; } return true; @@ -188,17 +189,18 @@ export class BushGuildMember extends GuildMember { public async mute(options: BushTimedPunishmentOptions): Promise<MuteResponse> { // checks - if (!this.guild.me.permissions.has('MANAGE_ROLES')) return 'missing permissions'; + if (!this.guild.me!.permissions.has('MANAGE_ROLES')) return 'missing permissions'; const muteRoleID = await this.guild.getSetting('muteRole'); if (!muteRoleID) return 'no mute role'; const muteRole = this.guild.roles.cache.get(muteRoleID); if (!muteRole) return 'invalid mute role'; - if (muteRole.position >= this.guild.me.roles.highest.position || muteRole.managed) return 'mute role not manageable'; + if (muteRole.position >= this.guild.me!.roles.highest.position || muteRole.managed) return 'mute role not manageable'; - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; // add role const muteSuccess = await this.roles + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .add(muteRole, `[Mute] ${moderator.tag} | ${options.reason || 'No reason provided.'}`) .catch(async (e) => { await client.console.warn('muteRoleAddError', e?.stack || e); @@ -234,6 +236,7 @@ export class BushGuildMember extends GuildMember { const dmSuccess = await this.send({ content: `You have been muted ${ options.duration ? 'for ' + util.humanizeDuration(options.duration) : 'permanently' + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing } in **${this.guild}** for **${options.reason || 'No reason provided'}**.${ending ? `\n\n${ending}` : ''}` }).catch(() => false); @@ -244,17 +247,18 @@ export class BushGuildMember extends GuildMember { public async unmute(options: BushPunishmentOptions): Promise<UnmuteResponse> { //checks - if (!this.guild.me.permissions.has('MANAGE_ROLES')) return 'missing permissions'; + if (!this.guild.me!.permissions.has('MANAGE_ROLES')) return 'missing permissions'; const muteRoleID = await this.guild.getSetting('muteRole'); if (!muteRoleID) return 'no mute role'; const muteRole = this.guild.roles.cache.get(muteRoleID); if (!muteRole) return 'invalid mute role'; - if (muteRole.position >= this.guild.me.roles.highest.position || muteRole.managed) return 'mute role not manageable'; + if (muteRole.position >= this.guild.me!.roles.highest.position || muteRole.managed) return 'mute role not manageable'; - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; //remove role const muteSuccess = await this.roles + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .remove(muteRole, `[Unmute] ${moderator.tag} | ${options.reason || 'No reason provided.'}`) .catch(async (e) => { await client.console.warn('muteRoleAddError', e?.stack || e); @@ -284,6 +288,7 @@ export class BushGuildMember extends GuildMember { //dm user const dmSuccess = await this.send({ + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing content: `You have been unmuted in **${this.guild}** because **${options.reason || 'No reason provided'}**.` }).catch(() => false); @@ -294,20 +299,22 @@ export class BushGuildMember extends GuildMember { public async bushKick(options: BushPunishmentOptions): Promise<KickResponse> { // checks - if (!this.guild.me.permissions.has('KICK_MEMBERS') || !this.kickable) return 'missing permissions'; + if (!this.guild.me?.permissions.has('KICK_MEMBERS') || !this.kickable) return 'missing permissions'; - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; // dm user const ending = await this.guild.getSetting('punishmentEnding'); const dmSuccess = await this.send({ + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing content: `You have been kicked from **${this.guild}** for **${options.reason || 'No reason provided'}**.${ ending ? `\n\n${ending}` : '' }` }).catch(() => false); // kick - const kickSuccess = await this.kick(`${moderator.tag} | ${options.reason || 'No reason provided.'}`).catch(() => false); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const kickSuccess = await this.kick(`${moderator?.tag} | ${options.reason || 'No reason provided.'}`).catch(() => false); if (!kickSuccess) return 'error kicking'; // add modlog entry @@ -319,28 +326,30 @@ export class BushGuildMember extends GuildMember { reason: options.reason, guild: this.guild }) - .catch(() => null); + .catch(() => ({ log: null })); if (!modlog) return 'error creating modlog entry'; if (!dmSuccess) return 'failed to dm'; return 'success'; } - public async bushBan(options?: BushBanOptions): Promise<BanResponse> { + public async bushBan(options: BushBanOptions): Promise<BanResponse> { // checks - if (!this.guild.me.permissions.has('BAN_MEMBERS') || !this.bannable) return 'missing permissions'; + if (!this.guild.me!.permissions.has('BAN_MEMBERS') || !this.bannable) return 'missing permissions'; - const moderator = client.users.cache.get(client.users.resolveId(options.moderator)) ?? client.user; + const moderator = client.users.cache.get(client.users.resolveId(options.moderator!)!) ?? client.user!; // dm user const ending = await this.guild.getSetting('punishmentEnding'); const dmSuccess = await this.send({ content: `You have been banned ${ - options.duration ? 'for ' + util.humanizeDuration(options.duration) : 'permanently' + options?.duration ? 'for ' + util.humanizeDuration(options.duration) : 'permanently' + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing } from **${this.guild}** for **${options.reason || 'No reason provided'}**.${ending ? `\n\n${ending}` : ''}` }).catch(() => false); // ban const banSuccess = await this.ban({ + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing reason: `${moderator.tag} | ${options.reason || 'No reason provided.'}`, days: options.deleteDays }).catch(() => false); diff --git a/src/lib/extensions/discord.js/BushMessage.ts b/src/lib/extensions/discord.js/BushMessage.ts index 921d03e..6d9a332 100644 --- a/src/lib/extensions/discord.js/BushMessage.ts +++ b/src/lib/extensions/discord.js/BushMessage.ts @@ -11,7 +11,7 @@ export interface BushPartialMessage extends Partialize<BushMessage, 'type' | 'system' | 'pinned' | 'tts', 'content' | 'cleanContent' | 'author'> {} export class BushMessage extends Message { public declare readonly client: BushClient; - public override util: BushCommandUtil; + public override util!: BushCommandUtil; public declare readonly guild: BushGuild | null; public declare readonly member: BushGuildMember | null; public declare author: BushUser; diff --git a/src/lib/models/ActivePunishment.ts b/src/lib/models/ActivePunishment.ts index fb2e79f..62bb73e 100644 --- a/src/lib/models/ActivePunishment.ts +++ b/src/lib/models/ActivePunishment.ts @@ -16,7 +16,7 @@ export interface ActivePunishmentModel { user: Snowflake; guild: Snowflake; extraInfo: Snowflake; - expires: Date; + expires: Date | null; modlog: string; } export interface ActivePunishmentModelCreationAttributes { diff --git a/src/lib/models/ModLog.ts b/src/lib/models/ModLog.ts index 5da6027..50d142a 100644 --- a/src/lib/models/ModLog.ts +++ b/src/lib/models/ModLog.ts @@ -25,8 +25,8 @@ export interface ModLogModel { type: ModLogType; user: Snowflake; moderator: Snowflake; - reason: string; - duration: number; + reason: string | null; + duration: number | null; guild: Snowflake; evidence: string; } diff --git a/src/lib/utils/BushConstants.ts b/src/lib/utils/BushConstants.ts index 391db75..e58380b 100644 --- a/src/lib/utils/BushConstants.ts +++ b/src/lib/utils/BushConstants.ts @@ -106,12 +106,13 @@ export class BushConstants { PRIVATE_THREADS: { name: 'Private Threads', important: false, emoji: '<:privateThreads:869763711894700093>', weight: 17 }, THREE_DAY_THREAD_ARCHIVE: { name: 'Three Day Thread Archive', important: false, emoji: '<:threeDayThreadArchive:869767841652564008>', weight: 19 }, SEVEN_DAY_THREAD_ARCHIVE: { name: 'Seven Day Thread Archive', important: false, emoji: '<:sevenDayThreadArchive:869767896123998288>', weight: 20 }, - NEWS: { name: 'Announcement Channels', important: false, emoji: '<:announcementChannels:850790491796013067>', weight: 21 }, - MEMBER_VERIFICATION_GATE_ENABLED: { name: 'Membership Verification Gate', important: false, emoji: '<:memberVerificationGateEnabled:850786829984858212>', weight: 22 }, - WELCOME_SCREEN_ENABLED: { name: 'Welcome Screen Enabled', important: false, emoji: '<:welcomeScreenEnabled:850790575875817504>', weight: 23 }, - COMMUNITY: { name: 'Community', important: false, emoji: '<:community:850786714271875094>', weight: 24 }, - THREADS_ENABLED: {name: 'Threads Enabled', important: false, emoji: '<:threadsEnabled:869756035345317919>', weight: 24 }, - THREADS_ENABLED_TESTING: {name: 'Threads Enabled Testing', important: false, emoji: null, weight: 24 } + ROLE_ICONS: { name: 'Role Icons', important: false, emoji: '<:roleIcons:876993381929222175>', weight: 21 }, + NEWS: { name: 'Announcement Channels', important: false, emoji: '<:announcementChannels:850790491796013067>', weight: 22 }, + MEMBER_VERIFICATION_GATE_ENABLED: { name: 'Membership Verification Gate', important: false, emoji: '<:memberVerificationGateEnabled:850786829984858212>', weight: 23 }, + WELCOME_SCREEN_ENABLED: { name: 'Welcome Screen Enabled', important: false, emoji: '<:welcomeScreenEnabled:850790575875817504>', weight: 24 }, + COMMUNITY: { name: 'Community', important: false, emoji: '<:community:850786714271875094>', weight: 25 }, + THREADS_ENABLED: {name: 'Threads Enabled', important: false, emoji: '<:threadsEnabled:869756035345317919>', weight: 26 }, + THREADS_ENABLED_TESTING: {name: 'Threads Enabled Testing', important: false, emoji: null, weight: 27 }, }, regions: { @@ -169,11 +170,12 @@ export class BushConstants { HOUSE_BRILLIANCE: '<:hypeSquadBrilliance:848742840649646101>', HOUSE_BALANCE: '<:hypeSquadBalance:848742877537370133>', EARLY_SUPPORTER: '<:earlySupporter:848741030102171648>', - //'TEAM_USER': '', - //'SYSTEM': '', + TEAM_USER: 'TEAM_USER', + SYSTEM: 'SYSTEM', BUGHUNTER_LEVEL_2: '<:bugHunterGold:848743283080822794>', - //'VERIFIED_BOT': '', - EARLY_VERIFIED_BOT_DEVELOPER: '<:earlyVerifiedBotDeveloper:848741079875846174>' + VERIFIED_BOT: 'VERIFIED_BOT', + EARLY_VERIFIED_BOT_DEVELOPER: '<:earlyVerifiedBotDeveloper:848741079875846174>', + DISCORD_CERTIFIED_MODERATOR: '<:discordCertifiedModerator:877224285901582366>' }, status: { diff --git a/src/lib/utils/BushLogger.ts b/src/lib/utils/BushLogger.ts index 27c8cd1..60817b9 100644 --- a/src/lib/utils/BushLogger.ts +++ b/src/lib/utils/BushLogger.ts @@ -15,7 +15,7 @@ export class BushLogger { const tempParsedArray: Array<string> = []; newContent.forEach((value, index) => { if (index % 2 !== 0) { - tempParsedArray.push(discordFormat ? `**${Util.escapeMarkdown(value)}**` : chalk[color](value)); + tempParsedArray.push(discordFormat ? `**${Util.escapeMarkdown(value)}**` : color ? chalk[color](value) : value); } else { tempParsedArray.push(Util.escapeMarkdown(value)); } diff --git a/src/lib/utils/CanvasProgressBar.ts b/src/lib/utils/CanvasProgressBar.ts index 521a444..cd86532 100644 --- a/src/lib/utils/CanvasProgressBar.ts +++ b/src/lib/utils/CanvasProgressBar.ts @@ -6,7 +6,7 @@ export class CanvasProgressBar { private readonly h: number; private readonly color: string; private percentage: number; - private p: number; + private p?: number; private ctx: CanvasRenderingContext2D; public constructor( @@ -18,7 +18,7 @@ export class CanvasProgressBar { ({ x: this.x, y: this.y, width: this.w, height: this.h } = dimension); this.color = color; this.percentage = percentage; - this.p; + this.p = undefined; this.ctx = ctx; } diff --git a/src/listeners/client/interactionCreate.ts b/src/listeners/client/interactionCreate.ts index e719517..2c1ab68 100644 --- a/src/listeners/client/interactionCreate.ts +++ b/src/listeners/client/interactionCreate.ts @@ -17,7 +17,11 @@ export default class InteractionCreateListener extends BushListener { void client.console.info( 'SlashCommand', `The <<${interaction.commandName}>> command was used by <<${interaction.user.tag}>> in <<${ - interaction.channel.type == 'DM' ? interaction.channel.recipient + 's DMs' : interaction.channel.name + interaction.channel + ? interaction.channel.type == 'DM' + ? interaction.channel.recipient + 's DMs' + : interaction.channel.name + : 'unknown' }>>.` ); return; diff --git a/src/listeners/client/ready.ts b/src/listeners/client/ready.ts index 39e583b..89c9161 100644 --- a/src/listeners/client/ready.ts +++ b/src/listeners/client/ready.ts @@ -10,7 +10,7 @@ export default class ReadyListener extends BushListener { } public override async exec(): Promise<void> { - const tag = `<<${client.user.tag}>>`, + const tag = `<<${client.user?.tag}>>`, guildCount = `<<${client.guilds.cache.size.toLocaleString()}>>`, userCount = `<<${client.users.cache.size.toLocaleString()}>>`; @@ -22,5 +22,14 @@ export default class ReadyListener extends BushListener { }` ) ); + + setTimeout( + // eslint-disable-next-line @typescript-eslint/no-misused-promises + async () => + await client.application?.commands + .create({ name: 'View Raw', type: 'MESSAGE' }) + .catch((e) => client.console.error(`Ready`, e?.stack ?? e)), + 2_000 + ); } } diff --git a/src/listeners/commands/commandBlocked.ts b/src/listeners/commands/commandBlocked.ts index 5d6bcfb..485de37 100644 --- a/src/listeners/commands/commandBlocked.ts +++ b/src/listeners/commands/commandBlocked.ts @@ -45,7 +45,7 @@ export default class CommandBlockedListener extends BushListener { } case reasons.DISABLED_GUILD: { return await message.util.reply({ - content: `${util.emojis.error} The \`${command}\` command is currently disabled in \`${message.guild.name}\`.`, + content: `${util.emojis.error} The \`${command}\` command is currently disabled in \`${message.guild?.name}\`.`, ephemeral: true }); } @@ -69,11 +69,11 @@ export default class CommandBlockedListener extends BushListener { } case reasons.RESTRICTED_CHANNEL: { const channels = command.restrictedChannels; - const names = []; + const names: string[] = []; channels.forEach((c) => { names.push(`<#${c}>`); }); - const pretty = util.oxford(names, 'and', undefined); + const pretty = util.oxford(names, 'and'); return await message.util.reply({ content: `${util.emojis.error} \`${command}\` can only be run in ${pretty}.`, ephemeral: true @@ -81,11 +81,11 @@ export default class CommandBlockedListener extends BushListener { } case reasons.RESTRICTED_GUILD: { const guilds = command.restrictedGuilds; - const names = []; + const names: string[] = []; guilds.forEach((g) => { - names.push(`\`${client.guilds.cache.get(g).name}\``); + names.push(`\`${client.guilds.cache.get(g)?.name}\``); }); - const pretty = util.oxford(names, 'and', undefined); + const pretty = util.oxford(names, 'and'); return await message.util.reply({ content: `${util.emojis.error} \`${command}\` can only be run in ${pretty}.`, ephemeral: true diff --git a/src/listeners/commands/commandError.ts b/src/listeners/commands/commandError.ts index e5de0cc..d4f68f2 100644 --- a/src/listeners/commands/commandError.ts +++ b/src/listeners/commands/commandError.ts @@ -1,5 +1,6 @@ import { BushCommandHandlerEvents, BushListener } from '@lib'; -import { MessageEmbed } from 'discord.js'; +import { GuildTextBasedChannels } from 'discord-akairo'; +import { DMChannel, MessageEmbed } from 'discord.js'; export default class CommandErrorListener extends BushListener { public constructor() { @@ -16,13 +17,16 @@ export default class CommandErrorListener extends BushListener { public static async handleError( ...[error, message, command]: BushCommandHandlerEvents['error'] | BushCommandHandlerEvents['slashError'] ): Promise<void> { - const isSlash = message.util.isSlash; + const isSlash = message.util!.isSlash; const errorNo = Math.floor(Math.random() * 6969696969) + 69; // hehe funny number - const channel = message.channel.type === 'DM' ? message.channel.recipient.tag : message.channel.name; + const channel = + message.channel!.type === 'DM' + ? (message.channel as DMChannel)!.recipient.tag + : (message.channel as GuildTextBasedChannels)!.name; const errorEmbed: MessageEmbed = new MessageEmbed() .setTitle(`${isSlash ? 'Slash ' : ''}Error # \`${errorNo}\`: An error occurred`) - .addField('Error', await util.inspectCleanRedactCodeblock(error?.stack || error, 'js', undefined)) + .addField('Error', await util.inspectCleanRedactCodeblock(error?.stack ?? error, 'js', undefined)) .setColor(util.colors.error) .setTimestamp(); const description = [ @@ -58,9 +62,13 @@ export default class CommandErrorListener extends BushListener { .setTitle(`A Command Error Occurred ${'code' in error ? `\`${(error as any).code}\`` : ''}`) .setColor(util.colors.error) .setTimestamp() - .setDescription(await util.inspectCleanRedactCodeblock(error?.stack || error, 'js', undefined, 4096)); + .setDescription(await util.inspectCleanRedactCodeblock(error?.stack ?? error, 'js', undefined, 4096)); (await message.util?.send({ embeds: [errorDevEmbed] }).catch((e) => { - const channel = message.channel.type === 'DM' ? message.channel.recipient.tag : message.channel.name; + const channel = message.channel + ? message.channel.type === 'DM' + ? message.channel.recipient.tag + : message.channel.name + : 'unknown'; void client.console.warn(heading, `Failed to send owner error stack in <<${channel}>>.` + e?.stack || e); })) ?? client.console.error(heading, `Failed to send owner error stack.` + error?.stack || error, false); } diff --git a/src/listeners/commands/commandMissingPermissions.ts b/src/listeners/commands/commandMissingPermissions.ts index fdca5d3..dc04ac2 100644 --- a/src/listeners/commands/commandMissingPermissions.ts +++ b/src/listeners/commands/commandMissingPermissions.ts @@ -1,4 +1,5 @@ import { BushCommandHandlerEvents, BushListener } from '@lib'; +import { PermissionString } from 'discord.js'; export default class CommandMissingPermissionsListener extends BushListener { public constructor() { @@ -20,10 +21,10 @@ export default class CommandMissingPermissionsListener extends BushListener { | BushCommandHandlerEvents['missingPermissions'] | BushCommandHandlerEvents['slashMissingPermissions'] ): Promise<unknown> { - const niceMissing = []; - missing.forEach((missing) => { - if (client.consts.mappings.permissions[missing]) { - niceMissing.push(client.consts.mappings.permissions[missing].name); + const niceMissing: string[] = []; + missing.forEach((missing: PermissionString) => { + if (client.consts.mappings.permissions[missing as keyof typeof client.consts.mappings.permissions]) { + niceMissing.push(client.consts.mappings.permissions[missing as keyof typeof client.consts.mappings.permissions].name); } else { niceMissing.push(missing); } diff --git a/src/listeners/commands/slashStarted.ts b/src/listeners/commands/slashStarted.ts index e64df54..855c026 100644 --- a/src/listeners/commands/slashStarted.ts +++ b/src/listeners/commands/slashStarted.ts @@ -12,7 +12,11 @@ export default class SlashStartedListener extends BushListener { return void client.logger.info( 'SlashCommand', `The <<${command.id}>> command was used by <<${message.author.tag}>> in ${ - message.channel.type === 'DM' ? `their <<DMs>>` : `<<#${message.channel.name}>> in <<${message.guild?.name}>>` + message.channel + ? message.channel.type === 'DM' + ? `their <<DMs>>` + : `<<#${message.channel.name}>> in <<${message.guild?.name}>>` + : 'unknown' }.`, true ); diff --git a/src/listeners/message/automodCreate.ts b/src/listeners/message/automodCreate.ts index b447ac8..cd22a16 100644 --- a/src/listeners/message/automodCreate.ts +++ b/src/listeners/message/automodCreate.ts @@ -21,7 +21,7 @@ export default class AutomodMessageCreateListener extends BushListener { public static async automod(message: BushMessage): Promise<unknown> { if (message.guild?.id !== client.consts.mappings.guilds.bush) return; // just temporary /* await message.guild.getSetting('autoModPhases'); */ - const badLinks = {}; + const badLinks: { [key: string]: number } = {}; let temp = _badLinks; if (_badLinksSecret) temp = temp.concat(_badLinksSecret); @@ -39,7 +39,7 @@ export default class AutomodMessageCreateListener extends BushListener { if (cleanMessageContent.includes(cleanWord)) { if (cleanWord === 'whore' && !message.content?.toLowerCase().includes(cleanWord)) return; - if (!offences[word]) offences[word] = wordMap[word]; + if (!offences[word]) offences[word] = wordMap[word as keyof typeof wordMap]; } }); if (!Object.keys(offences)?.length) return; @@ -53,8 +53,8 @@ export default class AutomodMessageCreateListener extends BushListener { } case 1: { void message.delete().catch(() => {}); - void message.member.warn({ - moderator: message.guild.me, + void message.member?.warn({ + moderator: message.guild.me!, reason: 'Saying a blacklisted word.' }); @@ -62,8 +62,8 @@ export default class AutomodMessageCreateListener extends BushListener { } case 2: { void message.delete().catch(() => {}); - void message.member.mute({ - moderator: message.guild.me, + void message.member?.mute({ + moderator: message.guild.me!, reason: 'Saying a blacklisted word.', duration: 900_000 // 15 minutes }); @@ -71,8 +71,8 @@ export default class AutomodMessageCreateListener extends BushListener { } case 3: { void message.delete().catch(() => {}); - void message.member.mute({ - moderator: message.guild.me, + void message.member?.mute({ + moderator: message.guild.me!, reason: 'Saying a blacklisted word.', duration: 0 // perm }); diff --git a/src/listeners/message/blacklistedFile.ts b/src/listeners/message/blacklistedFile.ts index 36bf2e9..a9c5c46 100644 --- a/src/listeners/message/blacklistedFile.ts +++ b/src/listeners/message/blacklistedFile.ts @@ -66,12 +66,13 @@ export default class BlacklistedFileListener extends BushListener { } public override async exec(...[message]: BushClientEvents['messageCreate']): Promise<void> { + if (!message.guild) return; const guildWhitelist = [ client.consts.mappings.guilds.bush, client.consts.mappings.guilds.tree, client.consts.mappings.guilds.space_ship ]; - if (!guildWhitelist.includes(message.guild?.id)) return; + if (!guildWhitelist.includes(message.guild!.id)) return; const embedAttachments = message.embeds.filter((e) => ['image', 'video', 'gifv'].includes(e.type)); const foundEmojis = [...message.content.matchAll(/<(?<animated>a?):\w+:(?<id>\d+)>/g)]; if (message.attachments.size + embedAttachments.length + foundEmojis.length < 1) return; @@ -96,7 +97,7 @@ export default class BlacklistedFileListener extends BushListener { } for (const attachment of embedAttachments) { try { - const req = await got.get(attachment.url); + const req = await got.get(attachment.url!); const rawHash = crypto.createHash('md5'); rawHash.update(req.rawBody.toString('binary')); const hash = rawHash.digest('hex'); @@ -111,7 +112,7 @@ export default class BlacklistedFileListener extends BushListener { for (const attachment of foundEmojis) { try { const req = await got.get( - `https://cdn.discordapp.com/emojis/${attachment.groups.id}.${attachment.groups.animated === 'a' ? 'gif' : 'png'}` + `https://cdn.discordapp.com/emojis/${attachment.groups?.id}.${attachment.groups?.animated === 'a' ? 'gif' : 'png'}` ); const rawHash = crypto.createHash('md5'); rawHash.update(req.rawBody.toString('binary')); @@ -128,7 +129,7 @@ export default class BlacklistedFileListener extends BushListener { try { for (let i = 0; i < foundFiles.length; i++) { if (foundFiles[i].name === 'Discord crash video' && !this.client.ownerID.includes(message.author.id)) { - await message.member.roles.add('748912426581229690'); + await message.member?.roles.add('748912426581229690'); } } await message.delete(); diff --git a/src/listeners/message/booster.ts b/src/listeners/message/booster.ts index e57b8ea..603e535 100644 --- a/src/listeners/message/booster.ts +++ b/src/listeners/message/booster.ts @@ -11,7 +11,7 @@ export default class BoosterMessageListener extends BushListener { } public override async exec(...[message]: BushClientEvents['messageCreate']): Promise<unknown> { - if (message.type === 'USER_PREMIUM_GUILD_SUBSCRIPTION' && message.guild.id === this.client.consts.mappings.guilds.bush) { + if (message.type === 'USER_PREMIUM_GUILD_SUBSCRIPTION' && message.guild!.id === this.client.consts.mappings.guilds.bush) { return await message.react('<:nitroboost:785160348885975062>').catch(() => { void this.client.console.warn('BoosterMessage', `Failed to react to <<${message.id}>>.`); }); diff --git a/src/listeners/message/directMessage.ts b/src/listeners/message/directMessage.ts index 55180b1..a434010 100644 --- a/src/listeners/message/directMessage.ts +++ b/src/listeners/message/directMessage.ts @@ -13,10 +13,10 @@ export default class DirectMessageListener extends BushListener { public override async exec(...[message]: BushClientEvents['messageCreate']): Promise<void> { if (message.channel.type === 'DM') { - if (!(message.author.id == this.client.user.id) && message.author.bot) return; + if (!(message.author.id == this.client.user!.id) && message.author.bot) return; const dmLogEmbed = new MessageEmbed().setTimestamp().setFooter(`User ID • ${message.author.id}`); - if (message.author.id != this.client.user.id) { + if (message.author.id != this.client.user!.id) { dmLogEmbed .setAuthor(`From: ${message.author.username}`, `${message.author.displayAvatarURL({ dynamic: true })}`) .setDescription(`**DM:**\n${message}`) @@ -33,7 +33,7 @@ export default class DirectMessageListener extends BushListener { .setFooter(`ID • ${message.author.id}`); } if (message.attachments.filter((a) => typeof a.size == 'number').size == 1) { - dmLogEmbed.setImage(message.attachments.filter((a) => typeof a.size == 'number').first().proxyURL); + dmLogEmbed.setImage(message.attachments.filter((a) => typeof a.size == 'number').first()!.proxyURL); } else if (message.attachments.size > 0) { dmLogEmbed.addField('Attachments', message.attachments.map((a) => a.proxyURL).join('\n')); } diff --git a/src/listeners/message/level.ts b/src/listeners/message/level.ts index f5fb932..0077276 100644 --- a/src/listeners/message/level.ts +++ b/src/listeners/message/level.ts @@ -42,6 +42,6 @@ export default class LevelListener extends BushListener { `Gave <<${xpToGive}>> XP to <<${message.author.tag}>> in <<${message.guild}>>.` ); this.#levelCooldowns.add(`${message.guild.id}-${message.author.id}`); - setTimeout(() => this.#levelCooldowns.delete(`${message.guild.id}-${message.author.id}`), 60_000); + setTimeout(() => this.#levelCooldowns.delete(`${message.guild!.id}-${message.author.id}`), 60_000); } } diff --git a/src/listeners/message/verbose.ts b/src/listeners/message/verbose.ts index 632a22f..f1530ce 100644 --- a/src/listeners/message/verbose.ts +++ b/src/listeners/message/verbose.ts @@ -10,11 +10,11 @@ export default class MessageVerboseListener extends BushListener { }); } - public override exec(...[message]: BushClientEvents['messageCreate']): Promise<void> { + public override exec(...[message]: BushClientEvents['messageCreate']): Promise<void> | undefined { if (message.channel?.type === 'DM') return; void this.client.console.verbose( 'Message', - `A message was sent by <<${message.author.tag}>> in <<${message.channel.name}>> in <<${message.guild.name}>>.` + `A message was sent by <<${message.author.tag}>> in <<${message.channel.name}>> in <<${message.guild!.name}>>.` ); } } diff --git a/src/tasks/removeExpiredPunishements.ts b/src/tasks/removeExpiredPunishements.ts index c079363..d787063 100644 --- a/src/tasks/removeExpiredPunishements.ts +++ b/src/tasks/removeExpiredPunishements.ts @@ -59,6 +59,7 @@ export default class RemoveExpiredPunishmentsTask extends BushTask { case ActivePunishmentType.ROLE: { if (!member) continue; const role = guild?.roles?.cache?.get(entry.extraInfo); + if (!role) throw new Error(`Cannot unmute ${member.user.tag} because I cannot find the mute role.`); const result = await member.removeRole({ reason: 'Punishment expired.', role: role, diff --git a/src/tasks/updateCache.ts b/src/tasks/updateCache.ts index 910088f..7fb7eb3 100644 --- a/src/tasks/updateCache.ts +++ b/src/tasks/updateCache.ts @@ -24,20 +24,11 @@ export class UpdateCacheTask extends BushTask { private static async updateGlobalCache(client: BushClient): Promise<void> { const environment = config.environment; - const row = ( - (await Global.findByPk(environment)) || - (await Global.create({ - environment, - superUsers: [], - blacklistedChannels: [], - blacklistedGuilds: [], - blacklistedUsers: [], - disabledCommands: [] - })) - ).toJSON(); + const row = ((await Global.findByPk(environment)) ?? (await Global.create({ environment }))).toJSON(); for (const option in row) { - if (Object.keys(client.cache.global).includes(option)) client.cache.global[option] = row[option]; + if (Object.keys(client.cache.global).includes(option)) + client.cache.global[option as keyof typeof client.cache.global] = row[option as keyof typeof row]; } } diff --git a/tsconfig.json b/tsconfig.json index c40a7e2..a94bb7c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,8 +13,8 @@ "emitDecoratorMetadata": true, "resolveJsonModule": true, "noImplicitOverride": true, - "alwaysStrict": true, "noErrorTruncation": true, + "strict": true, "baseUrl": "./", "paths": { "src/*": ["./src/*"], @@ -22,5 +22,5 @@ } }, "include": ["src/**/*.ts"], - "exclude": ["node_modules"] + "exclude": [] } @@ -392,6 +392,13 @@ __metadata: languageName: node linkType: hard +"@types/validator@npm:^13.6.3": + version: 13.6.3 + resolution: "@types/validator@npm:13.6.3" + checksum: b06b684d4d1ff4b59449a974cb8cdd96ccde4660958e541acf66711c8f60026912202e4d924ccd2016ec8bdd4e1f71e8122e5c568deefcdecffc04a73acff460 + languageName: node + linkType: hard + "@types/ws@npm:^7.4.4, @types/ws@npm:^7.4.7": version: 7.4.7 resolution: "@types/ws@npm:7.4.7" @@ -402,11 +409,11 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^4.14.1": - version: 4.29.1 - resolution: "@typescript-eslint/eslint-plugin@npm:4.29.1" + version: 4.29.2 + resolution: "@typescript-eslint/eslint-plugin@npm:4.29.2" dependencies: - "@typescript-eslint/experimental-utils": 4.29.1 - "@typescript-eslint/scope-manager": 4.29.1 + "@typescript-eslint/experimental-utils": 4.29.2 + "@typescript-eslint/scope-manager": 4.29.2 debug: ^4.3.1 functional-red-black-tree: ^1.0.1 regexpp: ^3.1.0 @@ -418,66 +425,66 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 66d8a92a0dc6fe4353334b5fadda73231dc7dbea977bc41f867bf9907e6781dc9594401273280d8de88165223bbf131241a1646ff5f2246bb4289949f95e7a5d + checksum: 3d3646059daa3d95200d71945a1ec8daebf62c7fedc3f29e1bece87bee9d689b06856fb18a8c55917f9c0bb5e86ddc8bc4c4f65f171e7d5784756dd59e3ff51d languageName: node linkType: hard -"@typescript-eslint/experimental-utils@npm:4.29.1": - version: 4.29.1 - resolution: "@typescript-eslint/experimental-utils@npm:4.29.1" +"@typescript-eslint/experimental-utils@npm:4.29.2": + version: 4.29.2 + resolution: "@typescript-eslint/experimental-utils@npm:4.29.2" dependencies: "@types/json-schema": ^7.0.7 - "@typescript-eslint/scope-manager": 4.29.1 - "@typescript-eslint/types": 4.29.1 - "@typescript-eslint/typescript-estree": 4.29.1 + "@typescript-eslint/scope-manager": 4.29.2 + "@typescript-eslint/types": 4.29.2 + "@typescript-eslint/typescript-estree": 4.29.2 eslint-scope: ^5.1.1 eslint-utils: ^3.0.0 peerDependencies: eslint: "*" - checksum: 4ab7827edfb42aa01a34b342656a2c6ef6ac753bff7523cffe6e2bd50de8c86c304abc8a790f11c2b02172436d1cc941ff26aa96a0b40ccaffc02f032faf6582 + checksum: e07b6b58f386ba84801d10bfe494548c3af20448c2f5596b77d13ba8621345ced4e1c6cf946dcf118c1e8566e0eed8284200f3f3a96f89aa7f367d9cdf6549a3 languageName: node linkType: hard "@typescript-eslint/parser@npm:^4.14.1": - version: 4.29.1 - resolution: "@typescript-eslint/parser@npm:4.29.1" + version: 4.29.2 + resolution: "@typescript-eslint/parser@npm:4.29.2" dependencies: - "@typescript-eslint/scope-manager": 4.29.1 - "@typescript-eslint/types": 4.29.1 - "@typescript-eslint/typescript-estree": 4.29.1 + "@typescript-eslint/scope-manager": 4.29.2 + "@typescript-eslint/types": 4.29.2 + "@typescript-eslint/typescript-estree": 4.29.2 debug: ^4.3.1 peerDependencies: eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 227119d9f7e406b741662417570034396c8ea14016e07c64caf3b8cc8973d6ccc92f98e84cf53cf96cf26825ec62873e0a4dd745f6d1043ce54498d1eec7a20e + checksum: 59f9727cea89c208fb31433c24dd7c1b4f2feb3af831b9320f4577f7b84f014f803864d4660b0f6bd16a4026d7ecd22b88523feb8c1593ef4a0a43ca9ea09c33 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:4.29.1": - version: 4.29.1 - resolution: "@typescript-eslint/scope-manager@npm:4.29.1" +"@typescript-eslint/scope-manager@npm:4.29.2": + version: 4.29.2 + resolution: "@typescript-eslint/scope-manager@npm:4.29.2" dependencies: - "@typescript-eslint/types": 4.29.1 - "@typescript-eslint/visitor-keys": 4.29.1 - checksum: e8d34ac72f5184c93e45785f50c80bdb7602814cfeacd6c700bca4f4e482fddc3f0191a6fc36782e19ffeef15791b0792b26c940c1d3c0e549d7dc1dc1ccc983 + "@typescript-eslint/types": 4.29.2 + "@typescript-eslint/visitor-keys": 4.29.2 + checksum: f89d11cf7ce28c37a913db432d3dd2c4e5f5bc431bac205dd55c3d49704be691a28d5f27ae96fde7feee23d3e80192d7aff3d8350aef53b415e5b0b53cd965d7 languageName: node linkType: hard -"@typescript-eslint/types@npm:4.29.1": - version: 4.29.1 - resolution: "@typescript-eslint/types@npm:4.29.1" - checksum: feb40f23db3c20d7fe9e629a44ef54d7225e064df6435e31f8417a9a1f5c216f92782a7c03a5fc9808b313a93a2f91df324d01a2e58478c57c5bbb0eb1f519a9 +"@typescript-eslint/types@npm:4.29.2": + version: 4.29.2 + resolution: "@typescript-eslint/types@npm:4.29.2" + checksum: 0bcab66bb1848e2361bb366abebe1f94baa56d7d2058b62467f14c054b969b72d1aa17717a52c11f48e9cfb50846f0e227e49ccc7f06ff750b9eb28ca8b064de languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:4.29.1, @typescript-eslint/typescript-estree@npm:^4.8.2": - version: 4.29.1 - resolution: "@typescript-eslint/typescript-estree@npm:4.29.1" +"@typescript-eslint/typescript-estree@npm:4.29.2, @typescript-eslint/typescript-estree@npm:^4.8.2": + version: 4.29.2 + resolution: "@typescript-eslint/typescript-estree@npm:4.29.2" dependencies: - "@typescript-eslint/types": 4.29.1 - "@typescript-eslint/visitor-keys": 4.29.1 + "@typescript-eslint/types": 4.29.2 + "@typescript-eslint/visitor-keys": 4.29.2 debug: ^4.3.1 globby: ^11.0.3 is-glob: ^4.0.1 @@ -486,17 +493,17 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 2721bb06f920e6efa710e689eefc20729a882ded71de1c7e81f866fb0ceda00b2e7f4e742842bd79c94985390f98180588e3b7bfb6b50c4844fb857ae18eaef3 + checksum: 90342d27f3f0837ad39f9b7e7d7c3c0b6de9c5b0770f5a18d490ebaf7be78efa65ba46ce0ca3004ad946ca1adc5865c5d3ba3b049c95b3b193bfdf0eb5e23095 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:4.29.1": - version: 4.29.1 - resolution: "@typescript-eslint/visitor-keys@npm:4.29.1" +"@typescript-eslint/visitor-keys@npm:4.29.2": + version: 4.29.2 + resolution: "@typescript-eslint/visitor-keys@npm:4.29.2" dependencies: - "@typescript-eslint/types": 4.29.1 + "@typescript-eslint/types": 4.29.2 eslint-visitor-keys: ^2.0.0 - checksum: a99db94f80331a0bdd2e4828d43daa7d391312d6edf77d8f80fcd37530ea9eacbf8014dc3378a26e9e22891e0d97c5637fcde2d6272ed091de74ede22bec0224 + checksum: 34185d8c6466340aba746d69b36d357da2d06577d73f58358648c142bd0f181d7fae01ca1138188a665ef074ea7e1bc6306ef9d50f29914c8bcea4e9ea1f82f2 languageName: node linkType: hard @@ -792,6 +799,7 @@ __metadata: "@types/node-fetch": ^2 "@types/tinycolor2": ^1 "@types/uuid": ^8.3.0 + "@types/validator": ^13.6.3 "@typescript-eslint/eslint-plugin": ^4.14.1 "@typescript-eslint/parser": ^4.14.1 body-parser: ^1.19.0 @@ -1369,7 +1377,7 @@ discord-akairo@NotEnoughUpdates/discord-akairo: discord.js@NotEnoughUpdates/discord.js: version: 13.2.0-dev - resolution: "discord.js@https://github.com/NotEnoughUpdates/discord.js.git#commit=564f2e06b5c072239d8cc2a66374169ad314b392" + resolution: "discord.js@https://github.com/NotEnoughUpdates/discord.js.git#commit=46c02e304815df787ed80952b54919e22f896987" dependencies: "@discordjs/builders": ^0.5.0 "@discordjs/collection": ^0.2.1 @@ -1379,7 +1387,7 @@ discord.js@NotEnoughUpdates/discord.js: discord-api-types: ^0.22.0 node-fetch: ^2.6.1 ws: ^7.5.1 - checksum: d78a07e59c59d3ae8d052a3c4381e3d2743ac7a32c4dd4010c0e45e80be1ff7acf4258fd77aa8a5601ccb44a59c9c5dd62a629e5afb16ee75a423d7b3e5b26d3 + checksum: fd054f9a573a18819d44ac98e1b8ff616d3a335895707b156bd280d740a88abb1cf6bac2d14c9caa9d30491f3cde8a38c9e4186aea1b5ce4db09090b5a15b9c4 languageName: node linkType: hard |