aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commands/dev/eval.ts2
-rw-r--r--src/commands/info/avatar.ts3
-rw-r--r--src/commands/info/guildInfo.ts57
-rw-r--r--src/commands/info/userInfo.ts18
-rw-r--r--src/commands/moderation/slowmode.ts21
-rw-r--r--src/commands/skyblock-reborn/chooseColor.ts (renamed from src/commands/skyblock-reborn/chooseColorCommand.ts)4
-rw-r--r--src/lib/badlinks.json289
-rw-r--r--src/lib/badwords.json15
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts12
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts86
-rw-r--r--src/lib/extensions/discord-akairo/BushCommand.ts7
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts43
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommandManager.ts26
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts54
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.ts31
-rw-r--r--src/lib/extensions/discord.js/BushClientEvents.d.ts6
-rw-r--r--src/lib/extensions/discord.js/BushGuild.ts7
-rw-r--r--src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts18
-rw-r--r--src/lib/extensions/discord.js/BushGuildApplicationCommandManager.ts10
-rw-r--r--src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts19
-rw-r--r--src/lib/extensions/discord.js/BushGuildEmojiRoleManager.ts13
-rw-r--r--src/lib/extensions/discord.js/BushGuildMemberManager.d.ts35
-rw-r--r--src/lib/extensions/discord.js/BushGuildMemberManager.ts11
-rw-r--r--src/lib/extensions/discord.js/BushMessageManager.d.ts33
-rw-r--r--src/lib/extensions/discord.js/BushMessageManager.ts15
-rw-r--r--src/lib/extensions/discord.js/BushThreadManager.d.ts25
-rw-r--r--src/lib/extensions/discord.js/BushThreadManager.ts11
-rw-r--r--src/lib/extensions/discord.js/BushThreadMemberManager.d.ts15
-rw-r--r--src/lib/extensions/discord.js/BushThreadMemberManager.ts14
-rw-r--r--src/lib/index.ts8
-rw-r--r--src/lib/utils/BushConstants.ts77
-rw-r--r--src/listeners/guild/syncUnban.ts4
-rw-r--r--src/listeners/message/autoPublisher.ts25
-rw-r--r--src/listeners/message/automodCreate.ts2
-rw-r--r--src/listeners/message/automodUpdate.ts2
-rw-r--r--src/listeners/message/blacklistedFile.ts159
-rw-r--r--src/listeners/message/booster.ts20
-rw-r--r--src/listeners/message/directMessage.ts44
-rw-r--r--src/listeners/message/verbose.ts20
-rw-r--r--src/listeners/other/consoleListener.ts1
40 files changed, 1030 insertions, 232 deletions
diff --git a/src/commands/dev/eval.ts b/src/commands/dev/eval.ts
index abdf2b9..4f6a293 100644
--- a/src/commands/dev/eval.ts
+++ b/src/commands/dev/eval.ts
@@ -86,10 +86,8 @@ export default class EvalCommand extends BushCommand {
config = client.config,
members = message.guild?.members,
roles = message.guild?.roles,
- client = client,
emojis = util.emojis,
colors = util.colors,
- util = util,
{ ActivePunishment, Global, Guild, Level, ModLog, StickyRole } = await import('@lib'),
{
ButtonInteraction,
diff --git a/src/commands/info/avatar.ts b/src/commands/info/avatar.ts
index dc10f7d..4f7449b 100644
--- a/src/commands/info/avatar.ts
+++ b/src/commands/info/avatar.ts
@@ -43,9 +43,8 @@ export default class AvatarCommand extends BushCommand {
const embed = new MessageEmbed()
.setTimestamp()
.setColor(util.colors.default)
- .setTitle(user.tag)
+ .setTitle(`${user.tag}'s Avatar`)
.setImage(user.avatarURL({ size: 2048, format: 'png', dynamic: true }));
-
await message.util.reply({ embeds: [embed] });
}
}
diff --git a/src/commands/info/guildInfo.ts b/src/commands/info/guildInfo.ts
index e82a5fe..577086b 100644
--- a/src/commands/info/guildInfo.ts
+++ b/src/commands/info/guildInfo.ts
@@ -1,8 +1,7 @@
import { Argument, Constants } from 'discord-akairo';
-import { Guild, GuildPreview, MessageEmbed, Snowflake, Vanity } from 'discord.js';
+import { BaseGuildVoiceChannel, Guild, GuildPreview, MessageEmbed, Snowflake, Vanity } from 'discord.js';
import { BushCommand, BushMessage, BushSlashMessage } from '../../lib';
-// TODO: Implement regions and security
export default class GuildInfoCommand extends BushCommand {
public constructor() {
super('guildInfo', {
@@ -58,9 +57,9 @@ 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 = [];
- if (['516977525906341928', '784597260465995796', '717176538717749358', '767448775450820639'].includes(guild.id))
- emojis.push(client.consts.mappings.otherEmojis.BUSH_VERIFIED);
+ const guildSecurity = [];
+ 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]);
@@ -91,21 +90,29 @@ export default class GuildInfoCommand extends BushCommand {
.size.toLocaleString()}`
];
- // TODO add guild regions
- // const guildRegions = [];
+ const guildRegions = [];
+ guild.channels.cache.forEach((channel) => {
+ if (!channel.type.includes('VOICE')) return;
+ else if (!guildRegions.includes((channel as BaseGuildVoiceChannel).rtcRegion ?? 'automatic')) {
+ guildRegions.push((channel as BaseGuildVoiceChannel).rtcRegion ?? 'automatic');
+ }
+ });
guildAbout.push(
`**Owner:** ${guild.members.cache.get(guild.ownerId)?.user.tag}`,
- `**Created** ${guild.createdAt.toLocaleString()}`,
- `**Members:** ${guild.memberCount.toLocaleString()}`,
- `**Online:** ${guild.approximatePresenceCount?.toLocaleString()}`,
- `**Channels:** ${guild.channels.cache.size} (${channelTypes.join(', ')})`,
- `**Emojis:** ${guild.emojis.cache.size.toLocaleString()}`
- // `**Region:** ${guildRegions.join()}`
+ `**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(', ')}`
);
if (guild.premiumSubscriptionCount)
guildAbout.push(
- `**Boosts:** Level ${guild.premiumTier.slice(0, 4)} with ${guild.premiumSubscriptionCount ?? 0} boosts`
+ `**Boosts:** Level ${guild.premiumTier == 'NONE' ? '0' : guild.premiumTier[5]} with ${
+ guild.premiumSubscriptionCount ?? 0
+ } boosts`
);
if (guild.me?.permissions.has('MANAGE_GUILD') && guild.vanityURLCode) {
const vanityInfo: Vanity = await guild.fetchVanityData();
@@ -115,12 +122,22 @@ export default class GuildInfoCommand extends BushCommand {
);
}
- // guildSecurity.push;
+ guildSecurity.push(
+ `**Verification Level**: ${guild.verificationLevel.toLowerCase().replace(/_/g, ' ')}`,
+ `**Explicit Content Filter:** ${guild.explicitContentFilter.toLowerCase().replace(/_/g, ' ')}`,
+ `**Default Message Notifications:** ${
+ typeof guild.defaultMessageNotifications === 'string'
+ ? guild.defaultMessageNotifications.toLowerCase().replace(/_/g, ' ')
+ : guild.defaultMessageNotifications
+ }`,
+ `**2FA Required**: ${guild.mfaLevel === 'ELEVATED' ? 'yes' : 'no'}`
+ );
} else {
guildAbout.push(
`**Members:** ${guild.approximateMemberCount?.toLocaleString()}`,
`**Online:** ${guild.approximatePresenceCount?.toLocaleString()}`,
- `**Emojis:** ${(guild as GuildPreview).emojis.size}`
+ `**Emojis:** ${(guild as GuildPreview).emojis.size?.toLocaleString() ?? 0}`
+ // `**Stickers:** ${(guild as GuildPreview).stickers.size}`
);
}
@@ -160,11 +177,11 @@ export default class GuildInfoCommand extends BushCommand {
if (guildIcon) {
guildInfoEmbed.setThumbnail(guildIcon);
}
- // if (!isPreview) {
- // guildInfoEmbed.addField('» Security', guildSecurity.join('\n'));
- // }
+ if (!isPreview) {
+ guildInfoEmbed.addField('» Security', guildSecurity.join('\n'));
+ }
if (emojis) {
- guildInfoEmbed.setDescription(emojis.join(' '));
+ guildInfoEmbed.setDescription('\u200B' /*zero width space*/ + emojis.join(' '));
}
return await message.util.reply({ embeds: [guildInfoEmbed] });
}
diff --git a/src/commands/info/userInfo.ts b/src/commands/info/userInfo.ts
index 87235a9..e36e92b 100644
--- a/src/commands/info/userInfo.ts
+++ b/src/commands/info/userInfo.ts
@@ -1,6 +1,5 @@
import { BushCommand, BushMessage, BushSlashMessage } from '@lib';
import { GuildMember, MessageEmbed } from 'discord.js';
-import moment from 'moment';
// TODO: Allow looking up a user not in the guild and not cached
// TODO: Re-Implement Status Emojis
@@ -78,11 +77,11 @@ export default class UserInfoCommand extends BushCommand {
if (user.premiumSinceTimestamp) emojis.push(client.consts.mappings.otherEmojis.BOOSTER);
const createdAt = user.user.createdAt.toLocaleString(),
- createdAtDelta = moment(moment(user.user.createdAt).diff(moment())).toLocaleString(),
+ createdAtDelta = util.dateDelta(user.user.createdAt),
joinedAt = user.joinedAt?.toLocaleString(),
- joinedAtDelta = moment(user.joinedAt)?.diff(moment()).toLocaleString(),
+ joinedAtDelta = util.dateDelta(user.joinedAt, 2),
premiumSince = user.premiumSince?.toLocaleString(),
- premiumSinceDelta = moment(user.premiumSince)?.diff(moment()).toLocaleString();
+ premiumSinceDelta = util.dateDelta(user.premiumSince, 2);
// General Info
const generalInfo = [
@@ -101,12 +100,12 @@ export default class UserInfoCommand extends BushCommand {
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)
- serverUserInfo.push(`**General Deletions:** 2`);
+ serverUserInfo.push(`**General Deletions:** 1⅓`);
if (
['384620942577369088', '496409778822709251'].includes(user.id) &&
message.guild.id == client.consts.mappings.guilds.bush
)
- serverUserInfo.push(`**General Deletions:** 1`);
+ serverUserInfo.push(`**General Deletions:** ⅓`);
if (user.nickname) serverUserInfo.push(`**Nickname** ${user.nickname}`);
if (serverUserInfo.length)
userEmbed.addField('» Server Info', serverUserInfo.join('\n')).setColor(user.displayColor || util.colors.default);
@@ -128,10 +127,11 @@ export default class UserInfoCommand extends BushCommand {
if (user.presence.clientStatus) devices = Object.keys(user.presence.clientStatus);
const presenceInfo = [];
if (user.presence.status) presenceInfo.push(`**Status:** ${user.presence.status}`);
- if (devices) presenceInfo.push(`**${devices.length - 1 ? 'Devices' : 'Device'}:** ${util.oxford(devices, 'and', '')}`);
+ if (devices && devices.length)
+ presenceInfo.push(`**${devices.length - 1 ? 'Devices' : 'Device'}:** ${util.oxford(devices, 'and', '')}`);
if (activitiesNames.length)
presenceInfo.push(`**Activit${activitiesNames.length - 1 ? 'ies' : 'y'}:** ${util.oxford(activitiesNames, 'and', '')}`);
- if (customStatus) presenceInfo.push(`**Custom Status:** ${customStatus}`);
+ if (customStatus && customStatus.length) presenceInfo.push(`**Custom Status:** ${customStatus}`);
userEmbed.addField('» Presence', presenceInfo.join('\n'));
}
@@ -148,7 +148,7 @@ export default class UserInfoCommand extends BushCommand {
}
if (perms.length) userEmbed.addField('» Important Perms', perms.join(' '));
- if (emojis) userEmbed.setDescription('​' /*zero width space*/ + emojis.join(' '));
+ if (emojis) userEmbed.setDescription('\u200B' /*zero width space*/ + emojis.join(' '));
return await message.util.reply({ embeds: [userEmbed] });
}
diff --git a/src/commands/moderation/slowmode.ts b/src/commands/moderation/slowmode.ts
index f9ffbab..9b0d300 100644
--- a/src/commands/moderation/slowmode.ts
+++ b/src/commands/moderation/slowmode.ts
@@ -1,6 +1,6 @@
-import { BushCommand, BushMessage, BushSlashMessage } from '@lib';
-import { Argument, Constants } from 'discord-akairo';
-import { TextChannel, ThreadChannel } from 'discord.js';
+import { BushCommand, BushMessage, BushNewsChannel, BushSlashMessage, BushTextChannel, BushThreadChannel } from '@lib';
+import { Argument } from 'discord-akairo';
+import { NewsChannel, TextChannel, ThreadChannel } from 'discord.js';
export default class SlowModeCommand extends BushCommand {
public constructor() {
@@ -25,8 +25,7 @@ export default class SlowModeCommand extends BushCommand {
},
{
id: 'channel',
- type: Constants.ArgumentTypes.CHANNEL,
- match: Constants.ArgumentMatches.PHRASE,
+ type: 'channel',
prompt: {
start: 'What channel would you like to change?',
retry: '{error} Choose a valid channel.',
@@ -51,12 +50,18 @@ export default class SlowModeCommand extends BushCommand {
public async exec(
message: BushMessage | BushSlashMessage,
- { length, channel }: { length: number | 'off' | 'none' | 'disable'; channel: TextChannel | ThreadChannel }
+ {
+ length,
+ channel
+ }: {
+ length: number | 'off' | 'none' | 'disable';
+ channel: TextChannel | ThreadChannel | BushTextChannel | BushNewsChannel | BushThreadChannel | NewsChannel;
+ }
): Promise<unknown> {
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 as ThreadChannel | TextChannel;
- if (!(channel instanceof TextChannel) || !(channel instanceof ThreadChannel))
+ if (!channel) channel = message.channel;
+ 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) {
length =
diff --git a/src/commands/skyblock-reborn/chooseColorCommand.ts b/src/commands/skyblock-reborn/chooseColor.ts
index 0138e36..2b72301 100644
--- a/src/commands/skyblock-reborn/chooseColorCommand.ts
+++ b/src/commands/skyblock-reborn/chooseColor.ts
@@ -93,7 +93,7 @@ export default class ChooseColorCommand extends BushCommand {
args: [
{
id: 'color',
- type: Constants.ArgumentTypes.ROLE,
+ type: 'role',
match: Constants.ArgumentMatches.REST,
prompt: {
start: 'Please choose a valid color.',
@@ -102,7 +102,7 @@ export default class ChooseColorCommand extends BushCommand {
}
}
],
- clientPermissions: ['EMBED_LINKS', 'SEND_MESSAGES'],
+ clientPermissions: ['EMBED_LINKS', 'SEND_MESSAGES', 'MANAGE_ROLES'],
channel: 'guild',
restrictedGuilds: ['839287012409999391'],
slash: true,
diff --git a/src/lib/badlinks.json b/src/lib/badlinks.json
new file mode 100644
index 0000000..f010bc3
--- /dev/null
+++ b/src/lib/badlinks.json
@@ -0,0 +1,289 @@
+[
+ "streammcomunnity.ru",
+ "stceamcomminity.com",
+ "steamcommnuninty.com",
+ "steamcommnunily.com",
+ "steamncommuniity.com",
+ "steamcommuniiy.ru",
+ "steamcomnumity.ru",
+ "steamoemmunity.com",
+ "streancommunuty.ru",
+ "streamcommuninnity.com",
+ "streamcomnumity.ru",
+ "stemcommunnilty.com",
+ "steamsupportpowered.icu",
+ "staemcomrnunity.store",
+ "steam-trades.icu",
+ "facecup.fun",
+ "fatown.net",
+ "ultracup.fun",
+ "iemcup.com",
+ "esea-mdl.com",
+ "uspringcup.com",
+ "denforapasi.cf",
+ "streamcommulinty.com",
+ "csskill.com",
+ "csgo-gifts.com",
+ "eplcups.com",
+ "tf2market.store",
+ "gamerich.xyz",
+ "anomalygiveaways.pro",
+ "casefire.fun",
+ "fineleague.fun",
+ "stearmcommunnitty.online",
+ "stearncomminuty.ru",
+ "stiemcommunitty.ru",
+ "strearmcommunity.ru",
+ "steancomunnity.ru",
+ "cloud9team.space",
+ "streancommunuty.ru",
+ "strearmcomunity.ru",
+ "stermccommunitty.ru",
+ "steamcommunytu.ru",
+ "streamcomunity.com",
+ "steamncommunity.com",
+ "steamcommunily.uno",
+ "acercup.com",
+ "xgamercup.com",
+ "lootxmarket.com",
+ "roll4tune.com",
+ "fivetown.net",
+ "giveavvay.com",
+ "stermcommuniity.com",
+ "skinxinfo.net",
+ "bit-skins.ru",
+ "aladdinhub.fun",
+ "allskinz.xyz",
+ "ano-skinspin.xyz",
+ "anomalyknifes.xyz",
+ "anomalyskin.xyz",
+ "anomalyskinz.xyz",
+ "anoskinzz.xyz",
+ "berrygamble.com",
+ "bitknife.xyz",
+ "bitskines.ru",
+ "challengeme.vip",
+ "challengeme.in",
+ "challengme.ru",
+ "cmepure.com",
+ "cmskillcup.com",
+ "counterpaid.xyz",
+ "counterspin.top",
+ "counterstrikegift.xyz",
+ "cs-beast.xyz",
+ "cs-lucky.xyz",
+ "cs-pill.xyz",
+ "cs-prizeskins.xyz",
+ "cs-prizeskinz.xyz",
+ "cs-simpleroll.xyz",
+ "cs-skinz.xyz",
+ "cs-smoke.xyz",
+ "cs-spinz.xyz",
+ "cs-victory.xyz",
+ "csallskin.xyz",
+ "csbuyskins.in",
+ "cscoat.eu",
+ "csgo-analyst.com",
+ "csgo-cash.eu",
+ "csgo-steamanalyst.net",
+ "csgo-swapskin.com",
+ "csgo-trade.net",
+ "csgo-up.com",
+ "csgobeats.com",
+ "csgocase.one",
+ "csgocashs.com",
+ "csgocheck.ru",
+ "csgocompetive.com",
+ "csgodetails.info",
+ "csgodreamer.com",
+ "csgodrs.com",
+ "csgoelite.xyz",
+ "csgoencup.com",
+ "csgoevent.xyz",
+ "csgoindex.ru",
+ "csgoitemdetails.com",
+ "csgoitemsprices.com",
+ "csgoko.tk",
+ "csgomarble.xyz",
+ "csgomarketplace.net",
+ "csgomarkets.net",
+ "csgoprocupgo.com",
+ "csgorcup.com",
+ "csgorose.com",
+ "csgoroyalskins1.com",
+ "csgoskill.ru",
+ "csgoskinprices.com",
+ "csgoskinsinfo.com",
+ "csgoskinsroll.com",
+ "csgosteamanalysis.com",
+ "csgosteamanalyst.ru",
+ "csgoteammate.gq",
+ "csgothunby.com",
+ "csgotrades.net",
+ "csgovip.ru",
+ "csgoxgiveaway.ru",
+ "csgozone.net.in",
+ "csgunskins.xyz",
+ "csmoneyskinz.xyz",
+ "csmvcecup.com",
+ "csprices.in",
+ "csskillpro.xyz",
+ "csskinz.xyz",
+ "cstournament.ru",
+ "csxrnoney.com",
+ "cybergamearena.ru",
+ "d2cups.com",
+ "d2faceit.com",
+ "deamonbets.ru",
+ "demonbets.ru",
+ "diablobets.com",
+ "doatgiveaway.top",
+ "dopeskins.com",
+ "dota2fight.ru",
+ "dota2fight.net",
+ "dota2giveaway.top",
+ "dota2giveaways.top",
+ "dotafights.vip",
+ "dotagiveaway.win",
+ "earnskinz.xyz",
+ "emeraldbets.ru",
+ "esportgaming.ru",
+ "event-games4roll.com",
+ "exchangeuritems.gq",
+ "extraskinscs.xyz",
+ "ezwin24.ru",
+ "faceiteasyleague.ru",
+ "fireopencase.com",
+ "free-skins.ru",
+ "game4roll.com",
+ "gameluck.ru",
+ "games-roll.ru",
+ "games-roll.ml",
+ "games-roll.ga",
+ "giveawayskin.com",
+ "global-skins.gq",
+ "globalcsskins.xyz",
+ "globalskins.tk",
+ "goldendota.com",
+ "goodskins.gq",
+ "gosteamanalyst.com",
+ "gtakey.ru",
+ "hellgiveaway.trade",
+ "hltvcsgo.com",
+ "hltvgames.net",
+ "knifespin.top",
+ "knifespin.xyz",
+ "knifespin.top",
+ "knifespins.xyz",
+ "knifez-roll.xyz",
+ "knifez-win.xyz",
+ "league-csgo.com",
+ "lehatop-01.ru",
+ "loungeztrade.com",
+ "lucky-skins.xyz",
+ "makson-gta.ru",
+ "maxskins.xyz",
+ "mvcsgo.com",
+ "mvpcup.ru",
+ "mvptournament.com",
+ "mygames4roll.com",
+ "night-skins.com",
+ "ownerbets.com",
+ "playerskinz.xyz",
+ "rangskins.com",
+ "roll-skins.ru",
+ "roll4knife.xyz",
+ "rollknfez.xyz",
+ "rollskin-simple.xyz",
+ "csgo-market.ru.com",
+ "sakuralive.ru.com",
+ "csgocupp.ru.com",
+ "csgoeasywin.ru.com",
+ "csgocybersport.ru.com",
+ "csgocheck.ru.com",
+ "csgo-market.ru.com",
+ "csgoindex.ru.com",
+ "rushbskins.xyz",
+ "rushskins.xyz",
+ "s1mple-spin.xyz",
+ "simple-knifez.xyz",
+ "simple-win.xyz",
+ "simplegamepro.ru",
+ "simpleroll-cs.xyz",
+ "simplespinz.xyz",
+ "simplewinz.xyz",
+ "skin-index.com",
+ "skin888trade.com",
+ "skincs-spin.xyz",
+ "skincs-spin.top",
+ "skinmarkets.net",
+ "skins-hub.top",
+ "skins-info.net",
+ "skins-jungle.xyz",
+ "skinsboost.ru",
+ "skinsdatabse.com",
+ "skinsind.com",
+ "skinsmind.ru",
+ "skinspace.ru",
+ "skinsplane.com",
+ "skinsplanes.com",
+ "skinsplanets.com",
+ "skinxmarket.site",
+ "skinz-spin.top",
+ "skinz-spin.xyz",
+ "skinzjar.ru",
+ "skinzprize.xyz",
+ "skinzspin-cs.xyz",
+ "skinzspinz.xyz",
+ "spin-games.com",
+ "spin4skinzcs.top",
+ "spin4skinzcs.xyz",
+ "spinforskin.ml",
+ "sponsored-simple.xyz",
+ "staffstatsgo.com",
+ "starrygamble.com",
+ "stat-csgo.ru",
+ "stats-cs.ru",
+ "steam-analyst.ru",
+ "steamanalysts.com",
+ "steamgamesroll.ru",
+ "stewie2k-giveaway-150days.pro",
+ "sunnygamble.com",
+ "swapskins.live",
+ "test-domuin2.com",
+ "test-domuin3.ru",
+ "test-domuin4.ru",
+ "test-domuin5.ru",
+ "tournamentt.com",
+ "waterbets.ru",
+ "ultimateskins.xyz",
+ "win-skin.top",
+ "win-skin.xyz",
+ "winknifespin.xyz",
+ "winskin-simple.xyz",
+ "winskins.top",
+ "wintheskin.xyz",
+ "steemcommnunity.ru",
+ "steamcomminytu.ru",
+ "stearncommunity.ru",
+ "stearncommunytiy.ru",
+ "steamcommutiny.com",
+ "steamcomrunity.com",
+ "steamcommunytiu.ru",
+ "steamcommnuntiy.com",
+ "steamcomminytiu.ru",
+ "steamcomminytiu.com",
+ "steancomunyiti.ru",
+ "steamcormmuntiy.com",
+ "store-stempowered.com",
+ "dlscord.store",
+ "streamcommuunnity.com",
+ "steamcommunityw.com",
+ "steamconmunlty.com",
+ "steamcommrutiny.ru",
+ "dlscord.info",
+ "steamcomnmuituy.com",
+ "steamcommunityu.com",
+ "dicsord.gifts",
+ "discod.gift"
+]
diff --git a/src/lib/badwords.json b/src/lib/badwords.json
new file mode 100644
index 0000000..94c854f
--- /dev/null
+++ b/src/lib/badwords.json
@@ -0,0 +1,15 @@
+{
+ "nigger": 3,
+ "nigga": 3,
+ "retard": 2,
+ "retarted": 2,
+ "faggot": 2,
+ "slut": 1,
+ "whore": 1,
+ "卍": 3,
+ "found a cool software that improves the": 3,
+ "hi, bro h am leaving cs:go and giving away my skin": 3,
+ "hi friend, today i am leaving this fucking game": 3,
+ "hi guys, i'm leaving this fucking game, take my": 3,
+ "you can choose any skin for yourself": 3
+}
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index 10db18d..54b5250 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -1,6 +1,7 @@
import chalk from 'chalk';
import { AkairoClient } from 'discord-akairo';
import {
+ Collection,
Guild,
Intents,
InteractionReplyOptions,
@@ -31,6 +32,7 @@ import { BushCache } from '../../utils/BushCache';
import { BushConstants } from '../../utils/BushConstants';
import { BushLogger } from '../../utils/BushLogger';
import { Config } from '../../utils/Config';
+import { BushApplicationCommand } from '../discord.js/BushApplicationCommand';
import { BushButtonInteraction } from '../discord.js/BushButtonInteraction';
import { BushCategoryChannel } from '../discord.js/BushCategoryChannel';
import { BushCommandInteraction } from '../discord.js/BushCommandInteraction';
@@ -42,6 +44,7 @@ import { BushMessage } from '../discord.js/BushMessage';
import { BushMessageReaction } from '../discord.js/BushMessageReaction';
import { BushNewsChannel } from '../discord.js/BushNewsChannel';
import { BushPresence } from '../discord.js/BushPresence';
+import { BushReactionEmoji } from '../discord.js/BushReactionEmoji';
import { BushRole } from '../discord.js/BushRole';
import { BushSelectMenuInteraction } from '../discord.js/BushSelectMenuInteraction';
import { BushStoreChannel } from '../discord.js/BushStoreChannel';
@@ -66,6 +69,15 @@ export type BushThreadMemberResolvable = BushThreadMember | BushUserResolvable;
export type BushUserResolvable = BushUser | Snowflake | BushMessage | BushGuildMember | BushThreadMember;
export type BushGuildMemberResolvable = BushGuildMember | BushUserResolvable;
export type BushRoleResolvable = BushRole | Snowflake;
+export type BushMessageResolvable = BushMessage | Snowflake;
+export type BushEmojiResolvable = Snowflake | BushGuildEmoji | BushReactionEmoji;
+export type BushEmojiIdentifierResolvable = string | BushEmojiResolvable;
+export type BushThreadChannelResolvable = BushThreadChannel | Snowflake;
+export type BushApplicationCommandResolvable = BushApplicationCommand | Snowflake;
+export interface BushFetchedThreads {
+ threads: Collection<Snowflake, BushThreadChannel>;
+ hasMore?: boolean;
+}
const rl = readline.createInterface({
input: process.stdin,
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index ebac9eb..926a529 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -38,7 +38,10 @@ import {
} from 'discord.js';
import got from 'got';
import humanizeDuration from 'humanize-duration';
+import moment from 'moment';
import { inspect, InspectOptions, promisify } from 'util';
+import _badLinks from '../../badlinks.json'; // Stolen from https://github.com/nacrt/SkyblockClient-REPO/blob/main/files/scamlinks.json
+import badWords from '../../badwords.json';
import { ActivePunishment, ActivePunishmentType } from '../../models/ActivePunishment';
import { BushNewsChannel } from '../discord.js/BushNewsChannel';
import { BushTextChannel } from '../discord.js/BushTextChannel';
@@ -752,8 +755,13 @@ export class BushClientUtil extends ClientUtil {
return typeMap[type];
}
- public humanizeDuration(duration: number): string {
- return humanizeDuration(duration, { language: 'en', maxDecimalPoints: 2 });
+ public humanizeDuration(duration: number, largest?: number): string {
+ if (largest) return humanizeDuration(duration, { language: 'en', maxDecimalPoints: 2, largest });
+ else return humanizeDuration(duration, { language: 'en', maxDecimalPoints: 2 });
+ }
+
+ public dateDelta(date: Date, largest?: number) {
+ return this.humanizeDuration(moment(date).diff(moment()), largest ?? 3);
}
public async findUUID(player: string): Promise<string> {
@@ -790,8 +798,78 @@ export class BushClientUtil extends ClientUtil {
/* eslint-enable @typescript-eslint/no-unused-vars */
public async automod(message: BushMessage) {
- const autoModPhases = await message.guild.getSetting('autoModPhases');
- if (autoModPhases.includes(message.content.toString()) && message.deletable) return await message.delete();
+ if (message.guild.id !== client.consts.mappings.guilds.bush) return; // just temporary
+ /* await message.guild.getSetting('autoModPhases'); */
+ const badLinks = _badLinks.map((link) => {
+ return { [link]: 3 };
+ });
+
+ const wordArray = [...Object.keys(badWords), ...Object.keys(badLinks)];
+ const offences: { [key: string]: number } = {};
+ wordArray.forEach((word) => {
+ if (message.content?.toLowerCase().replace(/ /g, '').includes(word.toLowerCase().replace(/ /g, ''))) {
+ if (offences[word]) offences[word] = wordArray[word];
+ }
+ });
+ if (!Object.keys(offences)?.length) return;
+
+ const highestOffence = Object.values(offences).sort((a, b) => b - a)[0];
+
+ switch (highestOffence) {
+ case 0: {
+ if (message.deletable) void message.delete();
+ break;
+ }
+ case 1: {
+ if (message.deletable) void message.delete();
+ void message.member.warn({
+ moderator: message.guild.me,
+ reason: 'Saying a blacklisted word.'
+ });
+ break;
+ }
+ case 2: {
+ if (message.deletable) void message.delete();
+ void message.member.mute({
+ moderator: message.guild.me,
+ reason: 'Saying a blacklisted word.',
+ duration: 900_000 // 15 minutes
+ });
+ break;
+ }
+ case 3: {
+ if (message.deletable) void message.delete();
+ void message.member.mute({
+ moderator: message.guild.me,
+ reason: 'Saying a blacklisted word.',
+ duration: 0 // perm
+ });
+ break;
+ }
+ }
+
+ const color =
+ highestOffence === 0
+ ? util.colors.lightGray
+ : highestOffence === 1
+ ? util.colors.yellow
+ : highestOffence === 2
+ ? util.colors.orange
+ : util.colors.red;
+ void (message.guild.channels.cache.get('783088333055066212') as TextChannel).send({
+ embeds: [
+ new MessageEmbed()
+ .setTitle(`[Severity ${highestOffence}] Automod Action Performed`)
+ .setDescription(
+ `**User:** ${message.author} (${message.author.tag})\n**Blacklisted Words:** ${util
+ .surroundArray(Object.keys(offences), '`')
+ .join()}`
+ )
+ .addField('Message Content', `${this.codeblock(message.content, 1024)}`)
+ .setColor(color)
+ .setTimestamp()
+ ]
+ });
}
public capitalizeFirstLetter(string: string): string {
diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts
index 0127a59..3f79aeb 100644
--- a/src/lib/extensions/discord-akairo/BushCommand.ts
+++ b/src/lib/extensions/discord-akairo/BushCommand.ts
@@ -78,7 +78,7 @@ export interface BushArgumentOptions extends BaseBushArgumentOptions {
type?: BushArgumentType;
}
export interface CustomBushArgumentOptions extends BaseBushArgumentOptions {
- type?: ArgumentTypeCaster | (string | string[])[] | RegExp | string;
+ customType?: ArgumentTypeCaster | (string | string[])[] | RegExp | string;
}
export interface BushCommandOptions extends CommandOptions {
@@ -122,6 +122,11 @@ export class BushCommand extends Command {
this.restrictedChannels = options.restrictedChannels;
this.restrictedGuilds = options.restrictedGuilds;
this.completelyHide = options.completelyHide;
+ if (options.args && typeof options.args !== 'function') {
+ options.args.forEach((arg: BushArgumentOptions | CustomBushArgumentOptions) => {
+ if (arg['customType']) arg.type = arg['customType'];
+ });
+ }
}
public exec(message: BushMessage, args: any): any;
diff --git a/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts b/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts
new file mode 100644
index 0000000..0e071ff
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts
@@ -0,0 +1,43 @@
+import { ApplicationCommandData, CachedManager, Collection, FetchApplicationCommandOptions, Snowflake } from 'discord.js';
+import { BushApplicationCommandResolvable, BushClient } from '../discord-akairo/BushClient';
+import { BushApplicationCommand } from './BushApplicationCommand';
+import { BushApplicationCommandPermissionsManager } from './BushApplicationCommandPermissionsManager';
+import { BushGuildResolvable } from './BushCommandInteraction';
+
+export class BushApplicationCommandManager<
+ ApplicationCommandType = BushApplicationCommand<{ guild: BushGuildResolvable }>,
+ PermissionsOptionsExtras = { guild: BushGuildResolvable },
+ PermissionsGuildType = null
+> extends CachedManager<Snowflake, ApplicationCommandType, BushApplicationCommandResolvable> {
+ public constructor(client: BushClient, iterable?: Iterable<unknown>);
+ public declare readonly client: BushClient;
+ public permissions: BushApplicationCommandPermissionsManager<
+ { command?: BushApplicationCommandResolvable } & PermissionsOptionsExtras,
+ { command: BushApplicationCommandResolvable } & PermissionsOptionsExtras,
+ PermissionsOptionsExtras,
+ PermissionsGuildType,
+ null
+ >;
+ private commandPath({ id, guildId }: { id?: Snowflake; guildId?: Snowflake }): unknown;
+ public create(command: ApplicationCommandData): Promise<ApplicationCommandType>;
+ public create(command: ApplicationCommandData, guildId: Snowflake): Promise<BushApplicationCommand>;
+ public delete(command: BushApplicationCommandResolvable, guildId?: Snowflake): Promise<ApplicationCommandType | null>;
+ public edit(command: BushApplicationCommandResolvable, data: ApplicationCommandData): Promise<ApplicationCommandType>;
+ public edit(
+ command: BushApplicationCommandResolvable,
+ data: ApplicationCommandData,
+ guildId: Snowflake
+ ): Promise<BushApplicationCommand>;
+ public fetch(
+ id: Snowflake,
+ options: FetchApplicationCommandOptions & { guildId: Snowflake }
+ ): Promise<BushApplicationCommand>;
+ public fetch(id: Snowflake, options?: FetchApplicationCommandOptions): Promise<ApplicationCommandType>;
+ public fetch(
+ id?: Snowflake,
+ options?: FetchApplicationCommandOptions
+ ): Promise<Collection<Snowflake, ApplicationCommandType>>;
+ public set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, ApplicationCommandType>>;
+ public set(commands: ApplicationCommandData[], guildId: Snowflake): Promise<Collection<Snowflake, BushApplicationCommand>>;
+ private static transformCommand(command: ApplicationCommandData): unknown;
+}
diff --git a/src/lib/extensions/discord.js/BushApplicationCommandManager.ts b/src/lib/extensions/discord.js/BushApplicationCommandManager.ts
deleted file mode 100644
index a8abb6f..0000000
--- a/src/lib/extensions/discord.js/BushApplicationCommandManager.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { ApplicationCommandManager, GuildResolvable, Snowflake } from 'discord.js';
-import { BushClient } from '../discord-akairo/BushClient';
-import { BushApplicationCommand } from './BushApplicationCommand';
-import { BushApplicationCommandPermissionsManager } from './BushApplicationCommandPermissionsManager';
-import { BushGuildResolvable } from './BushCommandInteraction';
-
-export type BushApplicationCommandResolvable = BushApplicationCommand | Snowflake;
-
-export class BushApplicationCommandManager<
- ApplicationCommandType = BushApplicationCommand<{ guild: BushGuildResolvable }>,
- PermissionsOptionsExtras = { guild: GuildResolvable },
- PermissionsGuildType = null
-> extends ApplicationCommandManager<ApplicationCommandType, PermissionsOptionsExtras, PermissionsGuildType> {
- public declare permissions: BushApplicationCommandPermissionsManager<
- { command?: BushApplicationCommandResolvable } & PermissionsOptionsExtras,
- { command: BushApplicationCommandResolvable } & PermissionsOptionsExtras,
- PermissionsOptionsExtras,
- PermissionsGuildType,
- null
- >;
-
- public constructor(client: BushClient, iterable?: Iterable<any>) {
- super(client, iterable);
- }
-}
diff --git a/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts b/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts
new file mode 100644
index 0000000..443fee2
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts
@@ -0,0 +1,54 @@
+import {
+ ApplicationCommand,
+ ApplicationCommandManager,
+ ApplicationCommandPermissionData,
+ ApplicationCommandPermissions,
+ BaseManager,
+ Collection,
+ GuildApplicationCommandManager,
+ GuildApplicationCommandPermissionData,
+ Snowflake
+} from 'discord.js';
+import { BushClient, BushRoleResolvable, BushUserResolvable } from '../discord-akairo/BushClient';
+
+export class BushApplicationCommandPermissionsManager<
+ BaseOptions,
+ FetchSingleOptions,
+ FullPermissionsOptions,
+ GuildType,
+ CommandIdType
+> extends BaseManager {
+ public constructor(manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand);
+ public declare readonly client: BushClient;
+ public commandId: CommandIdType;
+ public guild: GuildType;
+ public guildId: Snowflake | null;
+ public manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand;
+ public add(
+ options: FetchSingleOptions & { permissions: ApplicationCommandPermissionData[] }
+ ): Promise<ApplicationCommandPermissions[]>;
+ public has(options: FetchSingleOptions & { permissionId: BushUserResolvable | BushRoleResolvable }): Promise<boolean>;
+ public fetch(options: FetchSingleOptions): Promise<ApplicationCommandPermissions[]>;
+ public fetch(options: BaseOptions): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
+ public remove(
+ options:
+ | (FetchSingleOptions & {
+ users: BushUserResolvable | BushUserResolvable[];
+ roles?: BushRoleResolvable | BushRoleResolvable[];
+ })
+ | (FetchSingleOptions & {
+ users?: BushUserResolvable | BushUserResolvable[];
+ roles: BushRoleResolvable | BushRoleResolvable[];
+ })
+ ): Promise<ApplicationCommandPermissions[]>;
+ public set(
+ options: FetchSingleOptions & { permissions: ApplicationCommandPermissionData[] }
+ ): Promise<ApplicationCommandPermissions[]>;
+ public set(
+ options: FullPermissionsOptions & {
+ fullPermissions: GuildApplicationCommandPermissionData[];
+ }
+ ): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
+ private permissionsPath(guildId: Snowflake, commandId?: Snowflake): unknown;
+ private static transformPermissions(permissions: ApplicationCommandPermissionData, received?: boolean): unknown;
+}
diff --git a/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.ts b/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.ts
deleted file mode 100644
index 3a98833..0000000
--- a/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import {
- ApplicationCommand,
- ApplicationCommandManager,
- ApplicationCommandPermissionsManager,
- GuildApplicationCommandManager
-} from 'discord.js';
-import { BushClient } from '../discord-akairo/BushClient';
-import { BushApplicationCommand } from './BushApplicationCommand';
-import { BushApplicationCommandManager } from './BushApplicationCommandManager';
-import { BushGuildApplicationCommandManager } from './BushGuildApplicationCommandManager';
-
-export class BushApplicationCommandPermissionsManager<
- BaseOptions,
- FetchSingleOptions,
- FullPermissionsOptions,
- GuildType,
- CommandIdType
-> extends ApplicationCommandPermissionsManager<
- BaseOptions,
- FetchSingleOptions,
- FullPermissionsOptions,
- GuildType,
- CommandIdType
-> {
- public declare client: BushClient;
- public declare manager: BushApplicationCommandManager | BushGuildApplicationCommandManager | BushApplicationCommand;
-
- public constructor(manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand) {
- super(manager);
- }
-}
diff --git a/src/lib/extensions/discord.js/BushClientEvents.d.ts b/src/lib/extensions/discord.js/BushClientEvents.d.ts
new file mode 100644
index 0000000..6c1fec5
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushClientEvents.d.ts
@@ -0,0 +1,6 @@
+import { ClientEvents } from 'discord.js';
+import { BushMessage } from './BushMessage';
+
+export interface BushClientEvents extends ClientEvents {
+ messageCreate: [message: BushMessage];
+}
diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts
index 9d618ec..dd41dad 100644
--- a/src/lib/extensions/discord.js/BushGuild.ts
+++ b/src/lib/extensions/discord.js/BushGuild.ts
@@ -1,12 +1,13 @@
import { Guild, User } from 'discord.js';
-import { ModLogType } from '../..';
+import { BushGuildMember, ModLogType } from '../..';
import { Guild as GuildDB, GuildModel } from '../../models/Guild';
import { BushClient, BushUserResolvable } from '../discord-akairo/BushClient';
+import { BushGuildMemberManager } from './BushGuildMemberManager';
export class BushGuild extends Guild {
public declare readonly client: BushClient;
- // I cba to do this
- //// public declare members: GuildMemberManager;
+ public declare readonly me: BushGuildMember | null;
+ public declare members: BushGuildMemberManager;
public constructor(client: BushClient, data: unknown) {
super(client, data);
}
diff --git a/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts b/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts
new file mode 100644
index 0000000..c0400ce
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts
@@ -0,0 +1,18 @@
+/* eslint-disable @typescript-eslint/ban-types */
+import { ApplicationCommandData, BaseFetchOptions, Collection, Snowflake } from 'discord.js';
+import { BushApplicationCommandResolvable, BushClient } from '../discord-akairo/BushClient';
+import { BushApplicationCommand } from './BushApplicationCommand';
+import { BushApplicationCommandManager } from './BushApplicationCommandManager';
+import { BushGuild } from './BushGuild';
+
+export class BushGuildApplicationCommandManager extends BushApplicationCommandManager<BushApplicationCommand, {}, BushGuild> {
+ public constructor(guild: BushGuild, iterable?: Iterable<unknown>);
+ public declare readonly client: BushClient;
+ public guild: BushGuild;
+ public create(command: ApplicationCommandData): Promise<BushApplicationCommand>;
+ public delete(command: BushApplicationCommandResolvable): Promise<BushApplicationCommand | null>;
+ public edit(command: BushApplicationCommandResolvable, data: ApplicationCommandData): Promise<BushApplicationCommand>;
+ public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<BushApplicationCommand>;
+ public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, BushApplicationCommand>>;
+ public set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, BushApplicationCommand>>;
+}
diff --git a/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.ts b/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.ts
deleted file mode 100644
index 3dd79a4..0000000
--- a/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { GuildApplicationCommandManager } from 'discord.js';
-import { BushGuild } from './BushGuild';
-
-export class BushGuildApplicationCommandManager extends GuildApplicationCommandManager {
- public declare guild: BushGuild;
- public constructor(guild: BushGuild, iterable?: Iterable<any>) {
- super(guild, iterable);
- }
-}
diff --git a/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts b/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts
new file mode 100644
index 0000000..6e36292
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts
@@ -0,0 +1,19 @@
+import { Collection, DataManager, Snowflake } from 'discord.js';
+import { BushClient, BushRoleResolvable } from '../discord-akairo/BushClient';
+import { BushGuild } from './BushGuild';
+import { BushGuildEmoji } from './BushGuildEmoji';
+import { BushRole } from './BushRole';
+
+export class BushGuildEmojiRoleManager extends DataManager<Snowflake, BushRole, BushRoleResolvable> {
+ public constructor(emoji: BushGuildEmoji);
+ public declare readonly client: BushClient;
+ public emoji: BushGuildEmoji;
+ public guild: BushGuild;
+ public add(
+ roleOrRoles: BushRoleResolvable | readonly BushRoleResolvable[] | Collection<Snowflake, BushRole>
+ ): Promise<BushGuildEmoji>;
+ public set(roles: readonly BushRoleResolvable[] | Collection<Snowflake, BushRole>): Promise<BushGuildEmoji>;
+ public remove(
+ roleOrRoles: BushRoleResolvable | readonly BushRoleResolvable[] | Collection<Snowflake, BushRole>
+ ): Promise<BushGuildEmoji>;
+}
diff --git a/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.ts b/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.ts
deleted file mode 100644
index 00afb25..0000000
--- a/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Collection, GuildEmojiRoleManager, Snowflake } from 'discord.js';
-import { BushGuild } from './BushGuild';
-import { BushGuildEmoji } from './BushGuildEmoji';
-import { BushRole } from './BushRole';
-
-export class BushGuildEmojiRoleManager extends GuildEmojiRoleManager {
- public declare emoji: BushGuildEmoji;
- public declare guild: BushGuild;
- public declare cache: Collection<Snowflake, BushRole>;
- public constructor(emoji: BushGuildEmoji) {
- super(emoji);
- }
-}
diff --git a/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts b/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts
new file mode 100644
index 0000000..96b99e5
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts
@@ -0,0 +1,35 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import {
+ BanOptions,
+ CachedManager,
+ Collection,
+ FetchMemberOptions,
+ FetchMembersOptions,
+ GuildMember,
+ GuildMemberEditData,
+ GuildPruneMembersOptions,
+ GuildSearchMembersOptions,
+ Snowflake,
+ User,
+ UserResolvable
+} from 'discord.js';
+import { BushClient, BushGuildMemberResolvable, BushUserResolvable } from '../discord-akairo/BushClient';
+import { BushGuild } from './BushGuild';
+import { BushGuildMember } from './BushGuildMember';
+
+export class BushGuildMemberManager extends CachedManager<Snowflake, BushGuildMember, BushGuildMemberResolvable> {
+ public constructor(guild: BushGuild, iterable?: Iterable<unknown>);
+ public declare readonly client: BushClient;
+ public guild: BushGuild;
+ public ban(user: BushUserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>;
+ public edit(user: BushUserResolvable, data: GuildMemberEditData, reason?: string): Promise<void>;
+ public fetch(
+ options: UserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: UserResolvable })
+ ): Promise<GuildMember>;
+ public fetch(options?: FetchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;
+ public kick(user: UserResolvable, reason?: string): Promise<BushGuildMember | User | Snowflake>;
+ public prune(options: GuildPruneMembersOptions & { dry?: false; count: false }): Promise<null>;
+ public prune(options?: GuildPruneMembersOptions): Promise<number>;
+ public search(options: GuildSearchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;
+ public unban(user: UserResolvable, reason?: string): Promise<User>;
+}
diff --git a/src/lib/extensions/discord.js/BushGuildMemberManager.ts b/src/lib/extensions/discord.js/BushGuildMemberManager.ts
deleted file mode 100644
index dbc2da5..0000000
--- a/src/lib/extensions/discord.js/BushGuildMemberManager.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// /* eslint-disable @typescript-eslint/no-explicit-any */
-// import { GuildMemberManager } from 'discord.js';
-// import { BushGuild } from './BushGuild';
-
-// export class BushGuildMemberManager extends GuildMemberManager {
-// public guild: BushGuild;
-
-// public constructor(guild: BushGuild, iterable?: Iterable<any>) {
-// super(guild, iterable);
-// }
-// }
diff --git a/src/lib/extensions/discord.js/BushMessageManager.d.ts b/src/lib/extensions/discord.js/BushMessageManager.d.ts
new file mode 100644
index 0000000..bf795ad
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushMessageManager.d.ts
@@ -0,0 +1,33 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import {
+ BaseFetchOptions,
+ CachedManager,
+ ChannelLogsQueryOptions,
+ Collection,
+ EmojiIdentifierResolvable,
+ MessageEditOptions,
+ MessagePayload,
+ Snowflake,
+ TextBasedChannelFields
+} from 'discord.js';
+import { BushClient, BushMessageResolvable } from '../discord-akairo/BushClient';
+import { BushDMChannel } from './BushDMChannel';
+import { BushMessage } from './BushMessage';
+import { BushTextChannel } from './BushTextChannel';
+import { BushThreadChannel } from './BushThreadChannel';
+
+export class BushMessageManager extends CachedManager<Snowflake, BushMessage, BushMessageResolvable> {
+ public constructor(channel: BushTextChannel | BushDMChannel | BushThreadChannel, iterable?: Iterable<unknown>);
+ public declare readonly client: BushClient;
+ public channel: TextBasedChannelFields;
+ public cache: Collection<Snowflake, BushMessage>;
+ public crosspost(message: BushMessageResolvable): Promise<BushMessage>;
+ public delete(message: BushMessageResolvable): Promise<void>;
+ public edit(message: BushMessageResolvable, options: MessagePayload | MessageEditOptions): Promise<BushMessage>;
+ public fetch(message: Snowflake, options?: BaseFetchOptions): Promise<BushMessage>;
+ public fetch(options?: ChannelLogsQueryOptions, cacheOptions?: BaseFetchOptions): Promise<Collection<Snowflake, BushMessage>>;
+ public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, BushMessage>>;
+ public react(message: BushMessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;
+ public pin(message: BushMessageResolvable): Promise<void>;
+ public unpin(message: BushMessageResolvable): Promise<void>;
+}
diff --git a/src/lib/extensions/discord.js/BushMessageManager.ts b/src/lib/extensions/discord.js/BushMessageManager.ts
deleted file mode 100644
index 181808a..0000000
--- a/src/lib/extensions/discord.js/BushMessageManager.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { Collection, MessageManager, Snowflake } from 'discord.js';
-import { BushClient } from '../discord-akairo/BushClient';
-import { BushDMChannel } from './BushDMChannel';
-import { BushMessage } from './BushMessage';
-import { BushTextChannel } from './BushTextChannel';
-import { BushThreadChannel } from './BushThreadChannel';
-
-export class BushMessageManager extends MessageManager {
- public declare readonly client: BushClient;
- public declare cache: Collection<Snowflake, BushMessage>;
- public constructor(channel: BushTextChannel | BushDMChannel | BushThreadChannel, iterable?: Iterable<any>) {
- super(channel, iterable);
- }
-}
diff --git a/src/lib/extensions/discord.js/BushThreadManager.d.ts b/src/lib/extensions/discord.js/BushThreadManager.d.ts
new file mode 100644
index 0000000..6b8250b
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushThreadManager.d.ts
@@ -0,0 +1,25 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import {
+ BaseFetchOptions,
+ CachedManager,
+ FetchArchivedThreadOptions,
+ FetchThreadsOptions,
+ Snowflake,
+ ThreadChannelResolvable,
+ ThreadCreateOptions
+} from 'discord.js';
+import { BushClient, BushFetchedThreads, BushThreadChannelResolvable } from '../discord-akairo/BushClient';
+import { BushNewsChannel } from './BushNewsChannel';
+import { BushTextChannel } from './BushTextChannel';
+import { BushThreadChannel } from './BushThreadChannel';
+
+export class BushThreadManager<AllowedThreadType> extends CachedManager<Snowflake, BushThreadChannel, ThreadChannelResolvable> {
+ public constructor(channel: BushTextChannel | BushNewsChannel, iterable?: Iterable<unknown>);
+ public declare readonly client: BushClient;
+ public channel: BushTextChannel | BushNewsChannel;
+ public create(options: ThreadCreateOptions<AllowedThreadType>): Promise<BushThreadChannel>;
+ public fetch(options: BushThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise<BushThreadChannel | null>;
+ public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise<BushFetchedThreads>;
+ public fetchArchived(options?: FetchArchivedThreadOptions, cache?: boolean): Promise<BushFetchedThreads>;
+ public fetchActive(cache?: boolean): Promise<BushFetchedThreads>;
+}
diff --git a/src/lib/extensions/discord.js/BushThreadManager.ts b/src/lib/extensions/discord.js/BushThreadManager.ts
deleted file mode 100644
index 50eaa2d..0000000
--- a/src/lib/extensions/discord.js/BushThreadManager.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { ThreadManager } from 'discord.js';
-import { BushNewsChannel } from './BushNewsChannel';
-import { BushTextChannel } from './BushTextChannel';
-
-export class BushThreadManager<AllowedThreadType> extends ThreadManager<AllowedThreadType> {
- public declare channel: BushTextChannel | BushNewsChannel;
- public constructor(channel: BushTextChannel | BushNewsChannel, iterable?: Iterable<any>) {
- super(channel, iterable);
- }
-}
diff --git a/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts b/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts
new file mode 100644
index 0000000..ba9b90b
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts
@@ -0,0 +1,15 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+/* eslint-disable @typescript-eslint/no-empty-interface */
+import { CachedManager, Collection, Snowflake, ThreadChannel, ThreadMember, UserResolvable } from 'discord.js';
+import { BushClient, BushThreadMemberResolvable } from '../discord-akairo/BushClient';
+import { BushThreadChannel } from './BushThreadChannel';
+import { BushThreadMember } from './BushThreadMember';
+
+export class BushThreadMemberManager extends CachedManager<Snowflake, BushThreadMember, BushThreadMemberResolvable> {
+ public constructor(thread: BushThreadChannel, iterable?: Iterable<unknown>);
+ public declare readonly client: BushClient;
+ public thread: ThreadChannel;
+ public add(member: UserResolvable | '@me', reason?: string): Promise<Snowflake>;
+ public fetch(cache?: boolean): Promise<Collection<Snowflake, ThreadMember>>;
+ public remove(id: Snowflake | '@me', reason?: string): Promise<Snowflake>;
+}
diff --git a/src/lib/extensions/discord.js/BushThreadMemberManager.ts b/src/lib/extensions/discord.js/BushThreadMemberManager.ts
deleted file mode 100644
index e585ee7..0000000
--- a/src/lib/extensions/discord.js/BushThreadMemberManager.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable @typescript-eslint/no-empty-interface */
-import { ThreadMemberManager } from 'discord.js';
-import { BushClient } from '../discord-akairo/BushClient';
-import { BushThreadChannel } from './BushThreadChannel';
-
-export class BushThreadMemberManager extends ThreadMemberManager {
- public declare thread: BushThreadChannel;
- public declare readonly client: BushClient;
-
- public constructor(thread: BushThreadChannel, iterable?: Iterable<unknown>) {
- super(thread, iterable);
- }
-}
diff --git a/src/lib/index.ts b/src/lib/index.ts
index 73cee56..1e789e5 100644
--- a/src/lib/index.ts
+++ b/src/lib/index.ts
@@ -13,22 +13,16 @@ export * from './extensions/discord-akairo/BushTask';
export * from './extensions/discord-akairo/BushTaskHandler';
export * from './extensions/discord.js/BushActivity';
export * from './extensions/discord.js/BushApplicationCommand';
-export * from './extensions/discord.js/BushApplicationCommandManager';
-export * from './extensions/discord.js/BushApplicationCommandPermissionsManager';
export * from './extensions/discord.js/BushButtonInteraction';
export * from './extensions/discord.js/BushCategoryChannel';
export * from './extensions/discord.js/BushCommandInteraction';
export * from './extensions/discord.js/BushDMChannel';
export * from './extensions/discord.js/BushEmoji';
export * from './extensions/discord.js/BushGuild';
-export * from './extensions/discord.js/BushGuildApplicationCommandManager';
export * from './extensions/discord.js/BushGuildChannel';
export * from './extensions/discord.js/BushGuildEmoji';
-export * from './extensions/discord.js/BushGuildEmojiRoleManager';
export * from './extensions/discord.js/BushGuildMember';
-// export * from './extensions/discord.js/BushGuildMemberManager';
export * from './extensions/discord.js/BushMessage';
-export * from './extensions/discord.js/BushMessageManager';
export * from './extensions/discord.js/BushMessageReaction';
export * from './extensions/discord.js/BushNewsChannel';
export * from './extensions/discord.js/BushPresence';
@@ -40,9 +34,7 @@ export * from './extensions/discord.js/BushStageInstance';
export * from './extensions/discord.js/BushStoreChannel';
export * from './extensions/discord.js/BushTextChannel';
export * from './extensions/discord.js/BushThreadChannel';
-export * from './extensions/discord.js/BushThreadManager';
export * from './extensions/discord.js/BushThreadMember';
-export * from './extensions/discord.js/BushThreadMemberManager';
export * from './extensions/discord.js/BushUser';
export * from './extensions/discord.js/BushVoiceChannel';
export * from './extensions/discord.js/BushVoiceState';
diff --git a/src/lib/utils/BushConstants.ts b/src/lib/utils/BushConstants.ts
index 5a99798..97f86c4 100644
--- a/src/lib/utils/BushConstants.ts
+++ b/src/lib/utils/BushConstants.ts
@@ -63,7 +63,7 @@ export class BushConstants {
EMBED_LINKS: { name: 'Embed Links', important: false },
ATTACH_FILES: { name: 'Attach Files', important: false },
READ_MESSAGE_HISTORY: { name: 'Read Message History', important: false },
- MENTION_EVERYONE: { name: 'Mention @​everyone, @​here, and All Roles', important: true }, // name has a zero-width space to prevent accidents
+ MENTION_EVERYONE: { name: 'Mention @\u200Beveryone, @\u200Bhere, and All Roles', important: true }, // name has a zero-width space to prevent accidents
USE_EXTERNAL_EMOJIS: { name: 'Use External Emoji', important: false },
VIEW_GUILD_INSIGHTS: { name: 'View Server Insights', important: true },
CONNECT: { name: 'Connect', important: false },
@@ -84,48 +84,51 @@ export class BushConstants {
MANAGE_THREADS: { name: 'Manage Threads', important: true }
},
+ // prettier-ignore
features: {
- ANIMATED_ICON: { name: 'Animated Icon', important: false, emoji: '<:animatedIcon:850774498071412746>', weight: 14 },
- BANNER: { name: 'Banner', important: false, emoji: '<:banner:850786673150787614>', weight: 15 },
- COMMERCE: { name: 'Store Channels', important: true, emoji: '<:storeChannels:850786692432396338>', weight: 11 },
- COMMUNITY: { name: 'Community', important: false, emoji: '<:community:850786714271875094>', weight: 20 },
- DISCOVERABLE: { name: 'Discoverable', important: true, emoji: '<:discoverable:850786735360966656>', weight: 6 },
- ENABLED_DISCOVERABLE_BEFORE: {
- name: 'Enabled Discovery Before',
- important: false,
- emoji: '<:enabledDiscoverableBefore:850786754670624828>',
- weight: 7
- },
- FEATURABLE: { name: 'Featurable', important: true, emoji: '<:featurable:850786776372084756>', weight: 4 },
- INVITE_SPLASH: { name: 'Invite Splash', important: false, emoji: '<:inviteSplash:850786798246559754>', weight: 16 },
- MEMBER_VERIFICATION_GATE_ENABLED: {
- name: 'Membership Verification Gate',
- important: false,
- emoji: '<:memberVerificationGateEnabled:850786829984858212>',
- weight: 18
- },
- MONETIZATION_ENABLED: { name: 'Monetization Enabled', important: true, emoji: null, weight: 8 },
- MORE_EMOJI: { name: 'More Emoji', important: true, emoji: '<:moreEmoji:850786853497602080>', weight: 3 },
- MORE_STICKERS: { name: 'More Stickers', important: true, emoji: null, weight: 2 },
- NEWS: {
- name: 'Announcement Channels',
- important: false,
- emoji: '<:announcementChannels:850790491796013067>',
- weight: 17
- },
+ VERIFIED: { name: 'Verified', important: true, emoji: '<:verified:850795049817473066>', weight: 0 },
PARTNERED: { name: 'Partnered', important: true, emoji: '<:partneredServer:850794851955507240>', weight: 1 },
- PREVIEW_ENABLED: { name: 'Preview Enabled', important: true, emoji: '<:previewEnabled:850790508266913823>', weight: 10 },
+ MORE_STICKERS: { name: 'More Stickers', important: true, emoji: null, weight: 2 },
+ MORE_EMOJI: { name: 'More Emoji', important: true, emoji: '<:moreEmoji:850786853497602080>', weight: 3 },
+ FEATURABLE: { name: 'Featurable', important: true, emoji: '<:featurable:850786776372084756>', weight: 4 },
RELAY_ENABLED: { name: 'Relay Enabled', important: true, emoji: '<:relayEnabled:850790531441229834>', weight: 5 },
+ DISCOVERABLE: { name: 'Discoverable', important: true, emoji: '<:discoverable:850786735360966656>', weight: 6 },
+ ENABLED_DISCOVERABLE_BEFORE: { name: 'Enabled Discovery Before', important: false, emoji: '<:enabledDiscoverableBefore:850786754670624828>', weight: 7 },
+ MONETIZATION_ENABLED: { name: 'Monetization Enabled', important: true, emoji: null, weight: 8 },
TICKETED_EVENTS_ENABLED: { name: 'Ticketed Events Enabled', important: true, emoji: null, weight: 9 },
+ PREVIEW_ENABLED: { name: 'Preview Enabled', important: true, emoji: '<:previewEnabled:850790508266913823>', weight: 10 },
+ COMMERCE: { name: 'Store Channels', important: true, emoji: '<:storeChannels:850786692432396338>', weight: 11 },
VANITY_URL: { name: 'Vanity URL', important: false, emoji: '<:vanityURL:850790553079644160>', weight: 12 },
- VERIFIED: { name: 'Verified', important: true, emoji: '<:verified:850795049817473066>', weight: 0 },
VIP_REGIONS: { name: 'VIP Regions', important: false, emoji: '<:VIPRegions:850794697496854538>', weight: 13 },
- WELCOME_SCREEN_ENABLED: {
- name: 'Welcome Screen Enabled',
- important: false,
- emoji: '<:welcomeScreenEnabled:850790575875817504>',
- weight: 19
- }
+ ANIMATED_ICON: { name: 'Animated Icon', important: false, emoji: '<:animatedIcon:850774498071412746>', weight: 14 },
+ BANNER: { name: 'Banner', important: false, emoji: '<:banner:850786673150787614>', weight: 15 },
+ INVITE_SPLASH: { name: 'Invite Splash', important: false, emoji: '<:inviteSplash:850786798246559754>', weight: 16 },
+ 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 }
+ },
+
+ regions: {
+ 'automatic': ':united_nations: Automatic',
+ 'brazil': ':flag_br: Brazil',
+ 'europe': ':flag_eu: Europe',
+ 'hongkong': ':flag_hk: Hongkong',
+ 'india': ':flag_in: India',
+ 'japan': ':flag_jp: Japan',
+ 'russia': ':flag_ru: Russia',
+ 'singapore': ':flag_sg: Singapore',
+ 'southafrica': ':flag_za: South Africa',
+ 'sydney': ':flag_au: Sydney',
+ 'us-central': ':flag_us: US Central',
+ 'us-east': ':flag_us: US East',
+ 'us-south': ':flag_us: US South',
+ 'us-west': ':flag_us: US West'
},
otherEmojis: {
diff --git a/src/listeners/guild/syncUnban.ts b/src/listeners/guild/syncUnban.ts
index 389aae6..00f260c 100644
--- a/src/listeners/guild/syncUnban.ts
+++ b/src/listeners/guild/syncUnban.ts
@@ -12,8 +12,8 @@ export default class SyncUnbanListener extends BushListener {
public async exec(...[ban]: ClientEvents['guildBanRemove']): Promise<void> {
const bans = await ActivePunishment.findAll({
where: {
- user: ban.user,
- guild: ban.guild,
+ user: ban.user.id,
+ guild: ban.guild.id,
type: ActivePunishmentType.BAN
}
});
diff --git a/src/listeners/message/autoPublisher.ts b/src/listeners/message/autoPublisher.ts
new file mode 100644
index 0000000..3941371
--- /dev/null
+++ b/src/listeners/message/autoPublisher.ts
@@ -0,0 +1,25 @@
+import { BushListener } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class autoPublisherListener extends BushListener {
+ public constructor() {
+ super('autoPublisher', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ public async exec(...[message]: BushClientEvents['messageCreate']): Promise<void> {
+ if (!message.guild) return;
+ const autoPublishChannels = await message.guild.getSetting('autoPublishChannels');
+ if (autoPublishChannels) {
+ if (message.channel.type === 'GUILD_NEWS' && autoPublishChannels.some((x) => message.channel.id.includes(x))) {
+ const success = await message.crosspost().catch(() => false);
+ if (!success)
+ void client.console.warn('AutoPublisher', `Failed to publish <<${message.id}>> in <<${message.guild.name}>>.`);
+ void client.logger.log('AutoPublisher', `Published message <<${message.id}>> in <<${message.guild.name}>>.`);
+ }
+ }
+ }
+}
diff --git a/src/listeners/message/automodCreate.ts b/src/listeners/message/automodCreate.ts
index b8057c5..b6718fc 100644
--- a/src/listeners/message/automodCreate.ts
+++ b/src/listeners/message/automodCreate.ts
@@ -10,7 +10,7 @@ export default class AutomodMessageCreateListener extends BushListener {
});
}
- async exec(...[message]: ClientEvents['messageCreate']): Promise<void> {
+ async exec(...[message]: ClientEvents['messageCreate']): Promise<unknown> {
return await util.automod(message as BushMessage);
}
}
diff --git a/src/listeners/message/automodUpdate.ts b/src/listeners/message/automodUpdate.ts
index 9d17ef0..e455a3d 100644
--- a/src/listeners/message/automodUpdate.ts
+++ b/src/listeners/message/automodUpdate.ts
@@ -10,7 +10,7 @@ export default class AutomodMessageUpdateListener extends BushListener {
});
}
- async exec(...[message]: ClientEvents['messageUpdate']): Promise<void> {
+ async exec(...[message]: ClientEvents['messageUpdate']): Promise<unknown> {
const fullMessage = message.partial ? await message.fetch() : (message as Message);
return await util.automod(fullMessage as BushMessage);
}
diff --git a/src/listeners/message/blacklistedFile.ts b/src/listeners/message/blacklistedFile.ts
new file mode 100644
index 0000000..93ed7b7
--- /dev/null
+++ b/src/listeners/message/blacklistedFile.ts
@@ -0,0 +1,159 @@
+import crypto from 'crypto';
+import got from 'got';
+import { BushListener } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class BlacklistedFileListener extends BushListener {
+ private blacklistedFiles: { hash: string[]; name: string; description: string }[] = [
+ {
+ hash: ['a0f5e30426234bc9d09306ffc9474422'],
+ name: 'Play twice audio',
+ description: 'weird audio files'
+ },
+ {
+ hash: ['43e55abbcea67d9e6d7abfff944a8d0b'],
+ name: 'Flashy loud jumpscare',
+ description: 'flashy, loud gifs'
+ },
+ {
+ hash: [
+ '7a0831239e8c8368e96fb4cacd61b5f2',
+ '3bdb44bf3702f15d118f04fa63b927a9',
+ 'b6e45619a68c0e20749edb2412590b15',
+ 'bb8a27047518a8a7e420509af0e9e0ed',
+ 'f8076cd51e1ddab4ceded26a764af160',
+ '1757f0442b5e337bba0340f7b116e6f7',
+ 'f59185531f0dfa9bdd323b86f796c3bd',
+ '2825d3d82af65de210e638911e49b3a2',
+ '5256c3c18b367552e55e463a60af7760'
+ ],
+ name: 'Discord crash video/gif',
+ description: 'media that crashes discord'
+ },
+ {
+ hash: ['1fd6b3f255946236fd55d3e4bef01c5f', '157d374ec41adeef9601fd87e23f4bf5'],
+ name: 'Repost lobster video',
+ description: 'images encouraging spam'
+ },
+ {
+ hash: ['10ad124fc47cd9b7de2ec629bc945bf2'],
+ name: 'Jarvis message top user troll thingy',
+ description: 'gifs encouraging spam'
+ },
+ {
+ hash: ['312cda77d3e1f5fa00f482aed3b36f6f'],
+ name: 'Discord token stealer',
+ description: 'discord token stealers'
+ },
+ {
+ hash: ['f37f772246db9d690dee0f581682dfb7'],
+ name: 'Weird nsfw dog vid',
+ description: 'weird nsfw videos'
+ },
+ {
+ hash: ['5a5bfdf02a0224d3468499d099ec4eee'],
+ name: 'Virus (or at least flags antiviruses)',
+ description: 'viruses'
+ }
+ ];
+
+ constructor() {
+ super('blacklistedFile', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ public async exec(...[message]: BushClientEvents['messageCreate']): Promise<void> {
+ 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;
+ 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;
+ const foundFiles = [] as {
+ name: string;
+ hash: string[];
+ description: string;
+ }[];
+ for (const attachment of message.attachments) {
+ try {
+ const req = await got.get(attachment[1].proxyURL);
+ const rawHash = crypto.createHash('md5');
+ rawHash.update(req.rawBody.toString('binary'));
+ const hash = rawHash.digest('hex');
+ const blacklistData = this.blacklistedFiles.find((h) => h.hash.some((h) => h === hash));
+ if (blacklistData !== undefined) {
+ foundFiles.push(blacklistData);
+ }
+ } catch {
+ continue;
+ }
+ }
+ for (const attachment of embedAttachments) {
+ try {
+ const req = await got.get(attachment.url);
+ const rawHash = crypto.createHash('md5');
+ rawHash.update(req.rawBody.toString('binary'));
+ const hash = rawHash.digest('hex');
+ const blacklistData = this.blacklistedFiles.find((h) => h.hash.some((h) => h === hash));
+ if (blacklistData !== undefined) {
+ foundFiles.push(blacklistData);
+ }
+ } catch {
+ continue;
+ }
+ }
+ 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'}`
+ );
+ const rawHash = crypto.createHash('md5');
+ rawHash.update(req.rawBody.toString('binary'));
+ const hash = rawHash.digest('hex');
+ const blacklistData = this.blacklistedFiles.find((h) => h.hash.some((h) => h === hash));
+ if (blacklistData !== undefined) {
+ foundFiles.push(blacklistData);
+ }
+ } catch {
+ continue;
+ }
+ }
+ if (foundFiles.length > 0) {
+ 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.delete();
+
+ await message.util.send(
+ `<@!${message.author.id}>, please do not send ${foundFiles.map((f) => f.description).join(' or ')}.`
+ );
+ if (message.channel.type === 'DM') return;
+ void this.client.console.info(
+ 'BlacklistedFile',
+ `Deleted <<${foundFiles.map((f) => f.description).join(' and ')}>> sent by <<${message.author.tag}>> in ${
+ message.channel.name
+ }.`
+ );
+ } catch (e) {
+ void message.util.send(
+ `<@!${message.author.id}>, please do not send ${foundFiles.map((f) => f.description).join(' or ')}.`
+ );
+ void this.client.console.warn(
+ 'BlacklistedFile',
+ `Failed to delete <<${foundFiles.map((f) => f.description).join(' and ')}>> sent by <<${message.author.tag}>> in <<${
+ message.channel.type === 'DM' ? `${message.channel.recipient.tag}'s DMs` : message.channel.name
+ }>>.`
+ );
+ }
+ }
+ }
+}
diff --git a/src/listeners/message/booster.ts b/src/listeners/message/booster.ts
new file mode 100644
index 0000000..a042ad1
--- /dev/null
+++ b/src/listeners/message/booster.ts
@@ -0,0 +1,20 @@
+import { BushListener } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class BoosterMessageListener extends BushListener {
+ public constructor() {
+ super('boosterMessage', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ public async exec(...[message]: BushClientEvents['messageCreate']): Promise<unknown> {
+ 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
new file mode 100644
index 0000000..3dc84ab
--- /dev/null
+++ b/src/listeners/message/directMessage.ts
@@ -0,0 +1,44 @@
+import { MessageEmbed } from 'discord.js';
+import { BushListener } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class DirectMessageListener extends BushListener {
+ public constructor() {
+ super('directMessage', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ public async exec(...[message]: BushClientEvents['messageCreate']): Promise<void> {
+ if (message.channel.type === 'DM') {
+ 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) {
+ dmLogEmbed
+ .setAuthor(`From: ${message.author.username}`, `${message.author.displayAvatarURL({ dynamic: true })}`)
+ .setDescription(`**DM:**\n${message}`)
+ .setColor(this.client.util.colors.blue);
+ } else {
+ dmLogEmbed
+ .setAuthor(
+ `To: ${message.channel.recipient.username}`,
+ `${message.channel.recipient.displayAvatarURL({ dynamic: true })}`
+ )
+ .setDescription(`**DM:**\n${message}`)
+ .setColor(this.client.util.colors.red)
+ .setTimestamp()
+ .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);
+ } else if (message.attachments.size > 0) {
+ dmLogEmbed.addField('Attachments', message.attachments.map((a) => a.proxyURL).join('\n'));
+ }
+ const dmChannel = await util.getConfigChannel('dm');
+ await dmChannel.send({ embeds: [dmLogEmbed] });
+ }
+ }
+}
diff --git a/src/listeners/message/verbose.ts b/src/listeners/message/verbose.ts
new file mode 100644
index 0000000..45bf1de
--- /dev/null
+++ b/src/listeners/message/verbose.ts
@@ -0,0 +1,20 @@
+import { BushListener } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class MessageVerboseListener extends BushListener {
+ public constructor() {
+ super('messageVerbose', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ public exec(...[message]: BushClientEvents['messageCreate']): Promise<void> {
+ 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}>>.`
+ );
+ }
+}
diff --git a/src/listeners/other/consoleListener.ts b/src/listeners/other/consoleListener.ts
index b6f53d8..4e72ec9 100644
--- a/src/listeners/other/consoleListener.ts
+++ b/src/listeners/other/consoleListener.ts
@@ -17,7 +17,6 @@ export default class ConsoleListener extends BushListener {
const sh = promisify(exec),
bot = client,
config = client.config,
- client = client,
{ ActivePunishment, Global, Guild, Level, ModLog, StickyRole } = await import('@lib'),
{
ButtonInteraction,