Compare commits

...

3 Commits

Author SHA1 Message Date
Anthony Berg
132e3cc62b refactor(arabot): create separate functions for fetching and checking types of users, channels, etc
Some checks failed
Prettier / Run prettier scanning (push) Successful in 2m35s
ESLint / Run eslint scanning (push) Failing after 24s
CodeQL / Analyze (javascript) (push) Failing after 58s
2025-01-19 16:56:07 +01:00
Anthony Berg
db9204c115 build(arabot): update dependencies 2025-01-19 16:48:27 +01:00
Anthony Berg
0419488b6f refactor(arabot): change deprecated reply options 2025-01-19 13:21:33 +01:00
89 changed files with 2121 additions and 1948 deletions

View File

@ -34,12 +34,12 @@
"pnpm": ">=9"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"@prisma/client": "^6.2.1",
"@sapphire/discord.js-utilities": "^7.3.2",
"@sapphire/framework": "^5.3.2",
"@sapphire/plugin-logger": "^4.0.2",
"@sapphire/plugin-scheduled-tasks": "^10.0.2",
"@sapphire/plugin-subcommands": "^6.0.3",
"@sapphire/plugin-subcommands": "^7.0.1",
"@sapphire/stopwatch": "^1.5.4",
"@sapphire/time-utilities": "^1.7.14",
"@sapphire/ts-config": "^5.0.1",
@ -51,13 +51,13 @@
"typescript": "~5.4.5"
},
"devDependencies": {
"@types/node": "^20.17.13",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "8.56.0",
"eslint-config-prettier": "^9.1.0",
"prettier": "3.2.4",
"prisma": "^5.22.0"
"@types/node": "^22.10.7",
"@typescript-eslint/eslint-plugin": "^8.20.0",
"@typescript-eslint/parser": "^8.20.0",
"eslint": "9.18.0",
"eslint-config-prettier": "^10.0.1",
"prettier": "3.4.2",
"prisma": "^6.2.1"
},
"packageManager": "pnpm@9.12.2+sha512.22721b3a11f81661ae1ec68ce1a7b879425a1ca5b991c975b074ac220b187ce56c708fe5db69f4c962c989452eee76c82877f4ee80f474cebd61ee13461b6228"
}

692
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { ChannelType } from 'discord.js';
import { MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { isRole, isUser } from '#utils/typeChecking';
import { isTextChannel } from '@sapphire/discord.js-utilities';
export class AccessCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -79,7 +81,7 @@ export class AccessCommand extends Command {
if (!interaction.inCachedGuild()) {
await interaction.reply({
content: 'This command can only be run in a server!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -91,32 +93,29 @@ export class AccessCommand extends Command {
const role = interaction.options.getRole('role');
// Checks if all the variables are of the right type
if (user === null && role === null) {
if (!isUser(user) && !isRole(role)) {
await interaction.reply({
content: 'Error fetching slash command data!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// If user and role is provided, the return an error
if (user !== null && role !== null) {
if (isUser(user) && isRole(role)) {
await interaction.reply({
content:
'You have entered a user and a role at the same time! Please only enter one at a time.',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// Checks that the channel is a GuildText or GuildVoice, otherwise, return error
if (
channel.type !== ChannelType.GuildText &&
channel.type !== ChannelType.GuildVoice
) {
if (!isTextChannel(channel) && !channel.isVoiceBased()) {
await interaction.reply({
content: 'Please only select a text or voice channel!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -129,7 +128,7 @@ export class AccessCommand extends Command {
) {
await interaction.reply({
content: 'Channel is not in ModMail/Private/Restricted category!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -143,13 +142,13 @@ export class AccessCommand extends Command {
} else {
await interaction.reply({
content: 'Could not find the role to edit permissions!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// Set permissions of voice channel
if (channel.type === ChannelType.GuildVoice) {
if (channel.isVoiceBased()) {
switch (permission) {
case 'add':
await channel.permissionOverwrites.create(permId, {
@ -185,7 +184,7 @@ export class AccessCommand extends Command {
default:
await interaction.reply({
content: 'Incorrect permission option!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -220,7 +219,7 @@ export class AccessCommand extends Command {
default:
await interaction.reply({
content: 'Incorrect permission option!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}

View File

@ -20,6 +20,7 @@
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Message, MessageFlagsBitField } from 'discord.js';
import { ChannelType, TextChannel } from 'discord.js';
import { isTextChannel } from '@sapphire/discord.js-utilities';
export class AnonymousCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -74,7 +75,7 @@ export class AnonymousCommand extends Command {
}
if (channel === null) {
if (interaction.channel === null) {
if (!isTextChannel(interaction.channel)) {
await interaction.reply({
content: 'Error getting the channel!',
flags: MessageFlagsBitField.Flags.Ephemeral,

View File

@ -18,7 +18,8 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Message } from 'discord.js';
import { Message, MessageFlagsBitField } from 'discord.js';
import { isGuildBasedChannel } from '@sapphire/discord.js-utilities';
export class ClearCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -57,11 +58,11 @@ export class ClearCommand extends Command {
const messages = interaction.options.getInteger('messages', true);
const { channel } = interaction;
if (channel === null || channel.isDMBased()) {
if (!isGuildBasedChannel(channel)) {
await interaction.reply({
content: 'Could not fetch channel!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -70,8 +71,8 @@ export class ClearCommand extends Command {
await interaction.reply({
content: `Successfully deleted ${messages} messages!`,
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
}
@ -92,7 +93,7 @@ export class ClearCommand extends Command {
const { channel } = message;
if (!channel.isTextBased() || channel.isDMBased()) {
if (!isGuildBasedChannel(channel)) {
await message.react('❌');
await message.reply('Unsupported channel type!');
return;

View File

@ -19,9 +19,8 @@
import { RegisterBehavior } from '@sapphire/framework';
import { Subcommand } from '@sapphire/plugin-subcommands';
import type { Guild, TextChannel, Snowflake } from 'discord.js';
import { TextChannel, Snowflake, MessageFlagsBitField } from 'discord.js';
import {
CategoryChannel,
ChannelType,
EmbedBuilder,
GuildMember,
@ -29,6 +28,19 @@ import {
time,
} from 'discord.js';
import IDs from '#utils/ids';
import {
isCategoryChannel,
isGuildBasedChannel,
isGuildMember,
isTextChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
import {
getCategoryChannel,
getGuildMember,
getVoiceChannel,
} from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
export class PrivateCommand extends Subcommand {
public constructor(
@ -93,7 +105,9 @@ export class PrivateCommand extends Subcommand {
const modUser = interaction.user;
const { guild } = interaction;
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
// Checks if all the variables are of the right type
if (guild === null) {
@ -103,11 +117,11 @@ export class PrivateCommand extends Subcommand {
return;
}
const member = guild.members.cache.get(user.id);
const mod = guild.members.cache.get(modUser.id);
const member = await getGuildMember(user.id, guild);
const mod = await getGuildMember(modUser.id, guild);
// Checks if guildMember is null
if (member === undefined || mod === undefined) {
if (!isGuildMember(member) || !isGuildMember(mod)) {
await interaction.editReply({
content: 'Error fetching users!',
});
@ -116,7 +130,7 @@ export class PrivateCommand extends Subcommand {
const [name, coordinator] = this.getCoordinator(mod);
if (this.checkPrivate(member.id, coordinator, guild)) {
if (await this.checkPrivate(member.id, coordinator)) {
await interaction.editReply({
content: 'A private channel already exists!',
});
@ -235,20 +249,22 @@ export class PrivateCommand extends Subcommand {
const modUser = interaction.user;
const { guild, channel } = interaction;
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
// Checks if all the variables are of the right type
if (guild === null || channel === null) {
if (guild === null || !isGuildBasedChannel(channel)) {
await interaction.editReply({
content: 'Error fetching user!',
});
return;
}
const mod = guild.members.cache.get(modUser.id);
const mod = await getGuildMember(modUser.id, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
await interaction.editReply({
content: 'Error fetching users!',
});
@ -259,8 +275,8 @@ export class PrivateCommand extends Subcommand {
const coordinator = coordinatorInfo[1];
let topic: string[];
if (user === null) {
if (channel.type !== ChannelType.GuildText) {
if (!isUser(user)) {
if (!isTextChannel(channel)) {
await interaction.editReply({
content:
'Please make sure you ran this command in the original private text channel!',
@ -287,10 +303,10 @@ export class PrivateCommand extends Subcommand {
await channel.delete();
const vcId = topic[topic.indexOf(coordinator) + 1];
const voiceChannel = guild.channels.cache.get(vcId);
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.private
) {
await voiceChannel.delete();
@ -298,9 +314,7 @@ export class PrivateCommand extends Subcommand {
return;
}
const category = guild.channels.cache.get(IDs.categories.private) as
| CategoryChannel
| undefined;
const category = await getCategoryChannel(IDs.categories.private);
if (category === undefined) {
await interaction.editReply({
@ -309,26 +323,32 @@ export class PrivateCommand extends Subcommand {
return;
}
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
const textChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
for (const c of textChannels) {
const channel = c[1];
if (!isTextChannel(channel)) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (textChannel.topic?.includes(user?.id)) {
topic = textChannel.topic.split(' ');
if (channel.topic !== null && channel.topic.includes(user.id)) {
topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(coordinator) + 1];
const voiceChannel = guild.channels.cache.get(vcId);
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.private
) {
voiceChannel.delete();
await voiceChannel.delete();
}
await channel.delete();
}
textChannel.delete();
}
});
await interaction.editReply({
content: `Successfully deleted the channel for ${user}`,
@ -369,29 +389,35 @@ export class PrivateCommand extends Subcommand {
return [name, id];
}
private checkPrivate(user: Snowflake, coordinator: string, guild: Guild) {
const category = guild.channels.cache.get(IDs.categories.private) as
| CategoryChannel
| undefined;
private async checkPrivate(user: Snowflake, coordinator: string) {
const category = await getCategoryChannel(IDs.categories.private);
if (category === undefined) {
if (!isCategoryChannel(category)) {
return true;
}
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
);
let exists = false;
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
for (const c of textChannels) {
const channel = c[1];
if (!isTextChannel(channel)) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (
textChannel.topic?.includes(user) &&
textChannel.topic?.includes(coordinator)
channel.topic !== null &&
channel.topic.includes(user) &&
channel.topic.includes(coordinator)
) {
exists = true;
}
});
}
return exists;
}
}

View File

@ -18,10 +18,12 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import type { User, Guild, Message } from 'discord.js';
import { User, Guild, Message, MessageFlagsBitField } from 'discord.js';
import { updateUser } from '#utils/database/dbExistingUser';
import { getBalance } from '#utils/database/fun/economy';
import { EmbedBuilder } from 'discord.js';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class BalanceCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -50,7 +52,7 @@ export class BalanceCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Could not find the guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -66,15 +68,9 @@ export class BalanceCommand extends Command {
}
public async messageRun(message: Message) {
const user = message.member?.user;
const user = message.author;
const { guild } = message;
if (user === undefined) {
await message.react('❌');
await message.reply('Could not find your user!');
return;
}
if (guild === null) {
await message.react('❌');
await message.reply('Could not find the guild!');
@ -99,9 +95,9 @@ export class BalanceCommand extends Command {
success: false,
};
const member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Could not find your guild member!';
return info;
}

View File

@ -19,11 +19,19 @@
import { Command, RegisterBehavior } from '@sapphire/framework';
import { Time } from '@sapphire/time-utilities';
import type { User, Guild, GuildMember, Message } from 'discord.js';
import {
User,
Guild,
GuildMember,
Message,
MessageFlagsBitField,
} from 'discord.js';
import { updateUser } from '#utils/database/dbExistingUser';
import { daily, getLastDaily } from '#utils/database/fun/economy';
import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class DailyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -51,7 +59,7 @@ export class DailyCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Could not find the guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -67,15 +75,9 @@ export class DailyCommand extends Command {
}
public async messageRun(message: Message) {
const user = message.member?.user;
const user = message.author;
const { guild } = message;
if (user === undefined) {
await message.react('❌');
await message.reply('Could not find your user!');
return;
}
if (guild === null) {
await message.react('❌');
await message.reply('Could not find the guild!');
@ -114,9 +116,9 @@ export class DailyCommand extends Command {
return info;
}
const member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Could not find your guild member!';
return info;
}

View File

@ -18,11 +18,13 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { User, Guild, Message } from 'discord.js';
import { User, Guild, Message, MessageFlagsBitField } from 'discord.js';
import { updateUser } from '#utils/database/dbExistingUser';
import { getBalance, transfer } from '#utils/database/fun/economy';
import { EmbedBuilder, TextChannel } from 'discord.js';
import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids';
import { getGuildMember, getTextBasedChannel } from '#utils/fetcher';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
export class BalanceCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -75,7 +77,7 @@ export class BalanceCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Could not find the guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -117,15 +119,9 @@ export class BalanceCommand extends Command {
return;
}
const user = message.member?.user;
const user = message.author;
const { guild } = message;
if (user === undefined) {
await message.react('❌');
await message.reply('Could not find your user!');
return;
}
if (guild === null) {
await message.react('❌');
await message.reply('Could not find the guild!');
@ -164,15 +160,15 @@ export class BalanceCommand extends Command {
return info;
}
const member = guild.members.cache.get(user.id);
const recipientMember = guild.members.cache.get(recipient.id);
const member = await getGuildMember(user.id, guild);
const recipientMember = await getGuildMember(recipient.id, guild);
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Could not find your guild member!';
return info;
}
if (recipientMember === undefined) {
if (!isGuildMember(recipientMember)) {
info.message = 'Could not find the user!';
return info;
}
@ -206,18 +202,16 @@ export class BalanceCommand extends Command {
info.embeds.push(embed);
// Log the payment in the server
let logChannel = guild.channels.cache.get(IDs.channels.logs.economy) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.economy);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.economy)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
this.container.logger.error('Pay Error: Could not fetch log channel');
if (!isTextChannel(logChannel)) {
this.container.logger.error('Pay: Could not fetch log channel');
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Pay: the bot does not have permission to send in the log channel',
);
return info;
}
}
const logEmbed = new EmbedBuilder(embed.data);

View File

@ -18,9 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { N1984 } from '#utils/gifs';
import { addFunLog, countTotal } from '#utils/database/fun/fun';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class N1984Command extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -48,10 +49,10 @@ export class N1984Command extends Command {
const { member } = interaction;
// Type checks
if (!(member instanceof GuildMember)) {
if (!isGuildMember(member)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -79,6 +80,6 @@ export class N1984Command extends Command {
.setFooter({ text: embedFooter });
// Send the embed
await interaction.reply({ embeds: [n1984Embed], fetchReply: true });
await interaction.reply({ embeds: [n1984Embed], withResponse: true });
}
}

View File

@ -18,9 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Cringe } from '#utils/gifs';
import { addFunLog, countTotal } from '#utils/database/fun/fun';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class CringeCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -47,10 +48,10 @@ export class CringeCommand extends Command {
const { member } = interaction;
// Type check
if (!(member instanceof GuildMember)) {
if (!isGuildMember(member)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -74,6 +75,6 @@ export class CringeCommand extends Command {
.setFooter({ text: embedFooter });
// Send the embed
await interaction.reply({ embeds: [cringeEmbed], fetchReply: true });
await interaction.reply({ embeds: [cringeEmbed], withResponse: true });
}
}

View File

@ -18,8 +18,9 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Happy } from '#utils/gifs';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class HappyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -46,10 +47,10 @@ export class HappyCommand extends Command {
const { member } = interaction;
// Type checks
if (!(member instanceof GuildMember)) {
if (!isGuildMember(member)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -62,6 +63,6 @@ export class HappyCommand extends Command {
.setImage(randomHappy);
// Send the embed
await interaction.reply({ embeds: [happyEmbed], fetchReply: true });
await interaction.reply({ embeds: [happyEmbed], withResponse: true });
}
}

View File

@ -18,9 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Hugs } from '#utils/gifs';
import { addFunLog, countTotal } from '#utils/database/fun/fun';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class HugCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -58,10 +59,10 @@ export class HugCommand extends Command {
// Type Checks
if (!(hugger instanceof GuildMember)) {
if (!isGuildMember(hugger)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -96,7 +97,7 @@ export class HugCommand extends Command {
await interaction.reply({
content: `${user}`,
embeds: [hugEmbed],
fetchReply: true,
withResponse: true,
});
}
}

View File

@ -18,9 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Kill } from '#utils/gifs';
import { addFunLog, countTotal } from '#utils/database/fun/fun';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class KillCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -57,10 +58,10 @@ export class KillCommand extends Command {
const sender = interaction.member;
// Type checks
if (!(sender instanceof GuildMember)) {
if (!isGuildMember(sender)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -92,7 +93,7 @@ export class KillCommand extends Command {
await interaction.reply({
content: `${user}`,
embeds: [killEmbed],
fetchReply: true,
withResponse: true,
});
}
}

View File

@ -18,9 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Poke } from '#utils/gifs';
import { addFunLog, countTotal } from '#utils/database/fun/fun';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class PokeCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -57,10 +58,10 @@ export class PokeCommand extends Command {
const sender = interaction.member;
// Type checks
if (!(sender instanceof GuildMember)) {
if (!isGuildMember(sender)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -95,7 +96,7 @@ export class PokeCommand extends Command {
await interaction.reply({
content: `${user}`,
embeds: [pokeEmbed],
fetchReply: true,
withResponse: true,
});
}
}

View File

@ -18,8 +18,9 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Sad } from '#utils/gifs';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class SadCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -46,10 +47,10 @@ export class SadCommand extends Command {
const { member } = interaction;
// Type checks
if (!(member instanceof GuildMember)) {
if (!isGuildMember(member)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -62,6 +63,6 @@ export class SadCommand extends Command {
.setImage(randomSad);
// Send the embed
await interaction.reply({ embeds: [sadEmbed], fetchReply: true });
await interaction.reply({ embeds: [sadEmbed], withResponse: true });
}
}

View File

@ -18,8 +18,9 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Shrug } from '#utils/gifs';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class ShrugCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -46,10 +47,10 @@ export class ShrugCommand extends Command {
const { member } = interaction;
// Type checks
if (!(member instanceof GuildMember)) {
if (!isGuildMember(member)) {
await interaction.reply({
ephemeral: true,
content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -62,6 +63,6 @@ export class ShrugCommand extends Command {
.setImage(randomShrug);
// Send the embed
await interaction.reply({ embeds: [shrugEmbed], fetchReply: true });
await interaction.reply({ embeds: [shrugEmbed], withResponse: true });
}
}

View File

@ -18,7 +18,13 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { User, Message, Snowflake, TextChannel, Guild } from 'discord.js';
import {
User,
Message,
Snowflake,
Guild,
MessageFlagsBitField,
} from 'discord.js';
import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids';
import { addBan, checkBan } from '#utils/database/moderation/ban';
@ -27,6 +33,12 @@ import {
checkTempBan,
removeTempBan,
} from '#utils/database/moderation/tempBan';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
export class BanCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -75,13 +87,15 @@ export class BanCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const ban = await this.ban(user.id, mod.id, reason, guild);
@ -142,17 +156,19 @@ export class BanCommand extends Command {
success: false,
};
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = (await guild.client.users.fetch(userId)) as User;
if (!isUser(user)) {
info.message =
'The user does not exist! (The user provided is probably wrong, or their account has been deleted.)';
return info;
}
// Gets mod's GuildMember
const mod = guild.members.cache.get(modId);
const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!';
return info;
}
@ -166,13 +182,9 @@ export class BanCommand extends Command {
await updateUser(mod);
// Gets guildMember
let member = guild.members.cache.get(userId);
const member = await getGuildMember(userId, guild);
if (member === undefined) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
if (member !== undefined) {
if (isGuildMember(member)) {
// Checks if the user is not restricted
if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
info.message = 'You need to restrict the user first!';
@ -206,19 +218,20 @@ export class BanCommand extends Command {
info.success = true;
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(
IDs.channels.logs.restricted,
)) as TextChannel | undefined;
if (logChannel === undefined) {
this.container.logger.error('Ban Error: Could not fetch log channel');
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('Ban: Could not fetch log channel');
info.message = `${user} has been banned. This hasn't been logged in a text channel as log channel could not be found`;
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Ban: The bot does not have permission to send in the logs channel!',
);
info.message = `${user} has been banned. This hasn't been logged in a text channel as the bot does not have permission to send logs!`;
return info;
}
}
const log = new EmbedBuilder()

View File

@ -19,11 +19,17 @@
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Duration, DurationFormatter } from '@sapphire/time-utilities';
import type { User, Snowflake, TextChannel, Guild } from 'discord.js';
import { User, Snowflake, Guild, MessageFlagsBitField } from 'discord.js';
import { EmbedBuilder, Message } from 'discord.js';
import IDs from '#utils/ids';
import { addTempBan, checkTempBan } from '#utils/database/moderation/tempBan';
import { addEmptyUser, updateUser } from '#utils/database/dbExistingUser';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
export class TempBanCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -79,8 +85,8 @@ export class TempBanCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -94,7 +100,9 @@ export class TempBanCommand extends Command {
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const ban = await this.ban(user.id, mod.id, time, reason, guild);
@ -201,17 +209,19 @@ export class TempBanCommand extends Command {
const banLength = new DurationFormatter().format(time.offset);
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = (await guild.client.users.fetch(userId)) as User;
if (!isUser(user)) {
info.message =
'The user does not exist! (The user provided is probably wrong, or their account has been deleted.)';
return info;
}
// Gets mod's GuildMember
const mod = guild.members.cache.get(modId);
const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!';
return info;
}
@ -225,13 +235,9 @@ export class TempBanCommand extends Command {
await updateUser(mod);
// Gets guildMember
let member = guild.members.cache.get(userId);
const member = await getGuildMember(userId, guild);
if (member === undefined) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
if (member !== undefined) {
if (isGuildMember(member)) {
// Checks if the user is not restricted
if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
info.message = 'You need to restrict the user first!';
@ -273,23 +279,25 @@ export class TempBanCommand extends Command {
info.success = true;
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('Temp Ban: Could not fetch log channel');
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(
IDs.channels.logs.restricted,
)) as TextChannel | undefined;
if (logChannel === undefined) {
this.container.logger.error(
'Temp Ban Error: Could not fetch log channel',
);
info.message =
`${user} has been temporarily banned for ${banLength}. ` +
"This hasn't been logged in a text channel as log channel could not be found";
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Temp Ban: The bot does not have permission to send in the logs channel!',
);
info.message =
`${user} has been temporarily banned for ${banLength}. ` +
"This hasn't been logged in a text channel as the bot does not have permission to send logs!";
return info;
}
}
const log = new EmbedBuilder()

View File

@ -18,13 +18,13 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type {
import {
User,
Message,
Snowflake,
TextChannel,
Guild,
GuildBan,
MessageFlagsBitField,
} from 'discord.js';
import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids';
@ -34,6 +34,12 @@ import {
removeTempBan,
} from '#utils/database/moderation/tempBan';
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
import { isNullish } from '@sapphire/utilities';
export class UnbanCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -75,8 +81,8 @@ export class UnbanCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -123,10 +129,10 @@ export class UnbanCommand extends Command {
};
// Gets mod's GuildMember
const mod = guild.members.cache.get(modId);
const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!';
return info;
}
@ -134,15 +140,12 @@ export class UnbanCommand extends Command {
// Check if mod is in database
await addExistingUser(mod);
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
info.message = 'Could not fetch the user!';
return info;
}
}
let dbBan = await checkBan(userId);
const dbTempBan = await checkTempBan(userId);
@ -161,7 +164,7 @@ export class UnbanCommand extends Command {
}
let { reason } = ban;
if (reason === null || reason === undefined) {
if (isNullish(reason)) {
reason = '';
}
@ -191,19 +194,21 @@ export class UnbanCommand extends Command {
info.success = true;
// Log unban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
let logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('Unban Error: Could not fetch log channel');
info.message = `${user} has been unbanned. This hasn't been logged in a text channel as log channel could not be found`;
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(
IDs.channels.logs.restricted,
)) as TextChannel | undefined;
if (logChannel === undefined) {
this.container.logger.error('Ban Error: Could not fetch log channel');
info.message = `${user} has been banned. This hasn't been logged in a text channel as log channel could not be found`;
return info;
}
if (!logChannel.isSendable()) {
this.container.logger.error(
'Unban: The bot does not have permission to send in the logs channel!',
);
info.message = `${user} has been unbanned. This hasn't been logged in a text channel as the bot does not have permission to send logs!`;
return info;
}
const log = new EmbedBuilder()

View File

@ -22,13 +22,20 @@
import { Args, container, RegisterBehavior } from '@sapphire/framework';
import { Subcommand } from '@sapphire/plugin-subcommands';
import {
ChannelType,
GuildMember,
Message,
MessageFlagsBitField,
PermissionsBitField,
} from 'discord.js';
import type { TextChannel, Snowflake } from 'discord.js';
import type { Snowflake } from 'discord.js';
import IDs from '#utils/ids';
import { getGuildMember, getRole, getTextBasedChannel } from '#utils/fetcher';
import {
isGuildMember,
isTextChannel,
isThreadChannel,
} from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class DiversityCommand extends Subcommand {
public constructor(
@ -89,47 +96,25 @@ export class DiversityCommand extends Subcommand {
// Command run
public async toggleOpen(interaction: Subcommand.ChatInputCommandInteraction) {
// Check if guild is not null
if (interaction.guild === null) {
await interaction.reply({
content: 'Guild not found!',
ephemeral: true,
fetchReply: true,
});
return;
}
// Get the channel
const channel = interaction.guild.channels.cache.get(interaction.channelId);
// Check if channel is not undefined
if (channel === undefined) {
await interaction.reply({
content: 'Channel not found!',
ephemeral: true,
fetchReply: true,
});
return;
}
const channel = await getTextBasedChannel(interaction.channelId);
// Check if channel is text
if (channel.type !== ChannelType.GuildText) {
if (!isTextChannel(channel)) {
await interaction.reply({
content: 'Channel is not a text channel!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Converts GuildBasedChannel to TextChannel
const channelText = channel as TextChannel;
// Check if the command was run in the diversity section
if (channel.parentId !== IDs.categories.diversity) {
await interaction.reply({
content: 'Command was not run in the Diversity section!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -140,13 +125,13 @@ export class DiversityCommand extends Subcommand {
.has([PermissionsBitField.Flags.SendMessages]);
// Toggle send message in channel
await channelText.permissionOverwrites.edit(IDs.roles.vegan.vegan, {
await channel.permissionOverwrites.edit(IDs.roles.vegan.vegan, {
SendMessages: !open,
});
await interaction.reply({
content: `${!open ? 'Opened' : 'Closed'} this channel.`,
fetchReply: true,
withResponse: true,
});
}
@ -155,51 +140,69 @@ export class DiversityCommand extends Subcommand {
) {
// TODO add database updates
// Get the arguments
const user = interaction.options.getUser('user');
const user = interaction.options.getUser('user', true);
const mod = interaction.member;
const { guild } = interaction;
// Checks if all the variables are of the right type
if (user === null || guild === null || mod === null) {
if (guild === null) {
await interaction.reply({
content: 'Error fetching user!',
ephemeral: true,
fetchReply: true,
content: 'Error fetching the guild!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Gets guildMember whilst removing the ability of each other variables being null
const guildMember = guild.members.cache.get(user.id);
const diversity = guild.roles.cache.get(IDs.roles.staff.diversity);
// Checks if guildMember is null
if (guildMember === undefined || diversity === undefined) {
if (!isGuildMember(mod)) {
await interaction.reply({
content: 'Error fetching user!',
ephemeral: true,
fetchReply: true,
content: 'Error fetching your user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
const member = await getGuildMember(user.id, guild);
const diversity = await getRole(IDs.roles.staff.diversity, guild);
// Checks if the member was found
if (!isGuildMember(member)) {
await interaction.reply({
content: 'Error fetching the user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Checks if the role was found
if (!isRole(diversity)) {
await interaction.reply({
content: 'Error fetching the diversity role!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Checks if the user has Diversity and to give them or remove them based on if they have it
if (guildMember.roles.cache.has(IDs.roles.staff.diversity)) {
if (member.roles.cache.has(IDs.roles.staff.diversity)) {
// Remove the Diversity role from the user
await guildMember.roles.remove(diversity);
await this.threadManager(guildMember.id, false);
await member.roles.remove(diversity);
await this.threadManager(member.id, false);
await interaction.reply({
content: `Removed the ${diversity.name} role from ${user}`,
fetchReply: true,
withResponse: true,
});
return;
}
// Add Diversity Team role to the user
await guildMember.roles.add(diversity);
await this.threadManager(guildMember.id, true);
await member.roles.add(diversity);
await this.threadManager(member.id, true);
await interaction.reply({
content: `Gave ${user} the ${diversity.name} role!`,
fetchReply: true,
withResponse: true,
});
await user
.send(`You have been given the ${diversity.name} role by ${mod}!`)
@ -219,7 +222,7 @@ export class DiversityCommand extends Subcommand {
const mod = message.member;
if (mod === null) {
if (!isGuildMember(mod)) {
await message.react('❌');
await message.reply(
'Diversity coordinator not found! Try again or contact a developer!',
@ -235,9 +238,9 @@ export class DiversityCommand extends Subcommand {
return;
}
const diversity = guild.roles.cache.get(IDs.roles.staff.diversity);
const diversity = await getRole(IDs.roles.staff.diversity, guild);
if (diversity === undefined) {
if (!isRole(diversity)) {
await message.react('❌');
await message.reply('Role not found! Try again or contact a developer!');
return;
@ -270,11 +273,8 @@ export class DiversityCommand extends Subcommand {
const thread = await container.client.channels.fetch(
IDs.channels.diversity.diversity,
);
if (thread === null) {
return;
}
if (!thread.isThread()) {
if (!isThreadChannel(thread)) {
return;
}

View File

@ -21,8 +21,13 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Message } from 'discord.js';
import { Message, MessageFlagsBitField } from 'discord.js';
import { ChannelType } from 'discord.js';
import {
isGuildMember,
isVoiceBasedChannel,
} from '@sapphire/discord.js-utilities';
import { getVoiceBasedChannel } from '#utils/fetcher';
export class MoveAllCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -61,7 +66,9 @@ export class MoveAllCommand extends Command {
const { member } = interaction;
const { guild } = interaction;
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
if (
channel.type !== ChannelType.GuildVoice &&
@ -81,40 +88,31 @@ export class MoveAllCommand extends Command {
return;
}
if (member === null) {
if (!isGuildMember(member)) {
await interaction.editReply({
content: 'Error fetching your user',
});
return;
}
const mod = guild.members.cache.get(member.user.id);
if (mod === undefined) {
await interaction.editReply({
content: 'Error fetching user from guild',
});
return;
}
if (mod.voice.channelId === null) {
if (member.voice.channelId === null) {
await interaction.editReply({
content: 'You need to be in a voice channel to run this command!',
});
return;
}
const voice = guild.channels.cache.get(mod.voice.channelId);
const voice = await getVoiceBasedChannel(member.voice.channelId);
if (voice === undefined || !voice.isVoiceBased()) {
if (!isVoiceBasedChannel(voice)) {
await interaction.editReply({
content: 'Error fetching your current voice channel!',
});
return;
}
voice.members.forEach((memberVC) => {
memberVC.voice.setChannel(channel.id);
voice.members.forEach((vcMember) => {
vcMember.voice.setChannel(channel.id);
});
await interaction.editReply({
@ -135,7 +133,7 @@ export class MoveAllCommand extends Command {
const mod = message.member;
const { guild } = message;
if (mod === null) {
if (!isGuildMember(mod)) {
await message.react('❌');
await message.reply('Could not find your user!');
return;
@ -155,9 +153,9 @@ export class MoveAllCommand extends Command {
return;
}
const voice = guild.channels.cache.get(mod.voice.channelId);
const voice = await getVoiceBasedChannel(mod.voice.channelId);
if (voice === undefined || !voice.isVoiceBased()) {
if (!isVoiceBasedChannel(voice)) {
await message.react('❌');
await message.reply('Could not fetch current voice channel!');
return;

View File

@ -18,7 +18,9 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { GuildMember, Message } from 'discord.js';
import { GuildMember, Message, MessageFlagsBitField } from 'discord.js';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class RenameUserCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -68,21 +70,21 @@ export class RenameUserCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Gets guildMember whilst removing the ability of each other variables being null
const member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
// Checks if guildMember is null
if (member === undefined) {
if (!isGuildMember(member)) {
await interaction.reply({
content: 'Error fetching user!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -93,15 +95,15 @@ export class RenameUserCommand extends Command {
} catch {
await interaction.reply({
content: "Bot doesn't have permission to change the user's name!",
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.reply({
content: `Changed ${user}'s nickname`,
fetchReply: true,
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
}

View File

@ -26,6 +26,7 @@ import {
import {
ChannelType,
EmbedBuilder,
MessageFlagsBitField,
PermissionsBitField,
time,
} from 'discord.js';
@ -39,6 +40,11 @@ import {
import { restrict, checkActive } from '#utils/database/moderation/restriction';
import { randint } from '#utils/maths';
import { blockedRolesAfterRestricted } from '#utils/blockedRoles';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
export async function restrictRun(
userId: Snowflake,
@ -52,21 +58,18 @@ export async function restrictRun(
success: false,
};
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
info.message = 'Error fetching user';
return info;
}
}
// Gets mod's GuildMember
const mod = guild.members.cache.get(modId);
const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
info.message = 'Error fetching mod';
return info;
}
@ -80,17 +83,13 @@ export async function restrictRun(
}
// Gets guildMember
let member = guild.members.cache.get(userId);
if (member === undefined) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
const member = await getGuildMember(userId, guild);
const restrictRoles = IDs.roles.restrictions.restricted;
let section = tolerance ? randint(3, 4) : randint(1, 2);
if (member !== undefined) {
if (isGuildMember(member)) {
// Checks if the user is not restricted
if (member.roles.cache.hasAny(...restrictRoles)) {
info.message = `${member} is already restricted!`;
@ -218,7 +217,7 @@ export async function restrictRun(
}
}
if (member !== undefined && member.voice.channelId !== null) {
if (isGuildMember(member) && member.voice.channelId !== null) {
await member.voice.disconnect();
}
@ -242,19 +241,20 @@ export async function restrictRun(
await user.send({ embeds: [dmEmbed] }).catch(() => {});
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.restricted)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
container.logger.error('Restrict Error: Could not fetch log channel');
if (!isTextBasedChannel(logChannel)) {
container.logger.error('Restrict: Could not fetch log channel');
info.message = `Restricted ${user} but could not find the log channel. This has been logged to the database.`;
return info;
} else if (!logChannel.isSendable()) {
container.logger.error(
'Restrict: The bot does not have permission to send in the logs channel!',
);
info.message = `${user} has been restricted. This hasn't been logged in a text channel as the bot does not have permission to send logs!`;
return info;
}
}
const message = new EmbedBuilder()
@ -324,15 +324,17 @@ export class RestrictCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await restrictRun(user?.id, mod.id, reason, guild);
const info = await restrictRun(user.id, mod.id, reason, guild);
await interaction.editReply({
content: info.message,
@ -367,7 +369,7 @@ export class RestrictCommand extends Command {
return;
}
const info = await restrictRun(user?.id, mod.id, reason, guild);
const info = await restrictRun(user.id, mod.id, reason, guild);
await message.reply(info.message);
await message.react(info.success ? '✅' : '❌');

View File

@ -18,11 +18,14 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { ChannelType, EmbedBuilder } from 'discord.js';
import type { Message, TextChannel, Guild, Snowflake } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import type { Message, Guild, Snowflake } from 'discord.js';
import IDs from '#utils/ids';
import { getRestrictions } from '#utils/database/moderation/restriction';
import { checkStaff } from '#utils/checker';
import { isUser } from '#utils/typeChecking';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
import { getGuildMember, getUser } from '#utils/fetcher';
export class RestrictLogsCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -56,47 +59,48 @@ export class RestrictLogsCommand extends Command {
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
// Get the arguments
const user = interaction.options.getUser('user');
let { channel } = interaction;
const { channel } = interaction;
const { guild } = interaction;
// Checks if all the variables are of the right type
if (guild === null || channel === null) {
await interaction.reply({
content: 'Error fetching guild or channel!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
let userId: Snowflake | null = null;
if (user !== undefined && user !== null) {
if (isUser(user)) {
userId = user.id;
}
const staffChannel = checkStaff(channel);
if (staffChannel) {
channel = channel as TextChannel;
// Checking Channel topic for Snowflake
if (userId === null) {
let topic: string[];
if (channel.parentId === IDs.categories.modMail) {
if (
isTextChannel(channel) &&
channel.parentId === IDs.categories.modMail &&
channel.topic !== null
) {
// Checks if the channel topic has the user's snowflake
if (channel.topic !== null) {
topic = channel.topic.split(' ');
// eslint-disable-next-line prefer-destructuring
userId = topic[2];
}
}
}
// If no Snowflake was provided/found
if (userId === null) {
await interaction.reply({
content: 'User could not be found or was not provided!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -106,8 +110,8 @@ export class RestrictLogsCommand extends Command {
await interaction.reply({
embeds: info.embeds,
content: info.message,
fetchReply: true,
ephemeral: !staffChannel,
withResponse: true,
flags: staffChannel ? undefined : MessageFlagsBitField.Flags.Ephemeral,
});
}
}
@ -131,10 +135,11 @@ export class RestrictLogsCommand extends Command {
return;
}
// Attempting to get the user's Snowflake from the channel topic.
if (userId === null) {
const { channel } = message;
if (channel.type !== ChannelType.GuildText) {
if (!isTextChannel(channel)) {
await message.react('❌');
await message.reply('User was not provided!');
return;
@ -142,15 +147,15 @@ export class RestrictLogsCommand extends Command {
let topic: string[];
if (channel.parentId === IDs.categories.modMail) {
// Checks if the channel topic has the user's snowflake
if (channel.topic !== null) {
if (
channel.parentId === IDs.categories.modMail &&
channel.topic !== null
) {
topic = channel.topic.split(' ');
// eslint-disable-next-line prefer-destructuring
userId = topic[2];
}
}
}
if (userId === null) {
await message.react('❌');
@ -173,15 +178,13 @@ export class RestrictLogsCommand extends Command {
success: false,
};
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
info.message = 'Error fetching user';
if (!isUser(user)) {
info.message =
'Error fetching user. (You probably provided an incorrect user.)';
return info;
}
}
const restrictions = await getRestrictions(userId);
@ -205,14 +208,15 @@ export class RestrictLogsCommand extends Command {
) {
// Get mod names
let restMod = restrictions[i].modId;
const restModMember = guild.members.cache.get(restMod);
if (restModMember !== undefined) {
const restModMember = await getGuildMember(restMod, guild);
if (isGuildMember(restModMember)) {
restMod = restModMember.displayName;
}
let endRestMod = restrictions[i].endModId;
if (endRestMod !== null) {
const endRestModMember = guild.members.cache.get(endRestMod);
if (endRestModMember !== undefined) {
const endRestModMember = await getGuildMember(endRestMod, guild);
if (isGuildMember(endRestModMember)) {
endRestMod = endRestModMember.displayName;
}
}

View File

@ -18,7 +18,7 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { User, Message } from 'discord.js';
import { User, Message, MessageFlagsBitField } from 'discord.js';
import { restrictRun } from './restrict';
export class RestrictToleranceCommand extends Command {
@ -69,15 +69,17 @@ export class RestrictToleranceCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await restrictRun(user?.id, mod.id, reason, guild, true);
const info = await restrictRun(user.id, mod.id, reason, guild, true);
await interaction.editReply({
content: info.message,
@ -112,7 +114,7 @@ export class RestrictToleranceCommand extends Command {
return;
}
const info = await restrictRun(user?.id, mod.id, reason, guild, true);
const info = await restrictRun(user.id, mod.id, reason, guild, true);
await message.reply(info.message);
await message.react(info.success ? '✅' : '❌');

View File

@ -19,9 +19,15 @@
import { RegisterBehavior } from '@sapphire/framework';
import { Subcommand } from '@sapphire/plugin-subcommands';
import type { TextChannel } from 'discord.js';
import { CategoryChannel, ChannelType } from 'discord.js';
import { MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { isUser } from '#utils/typeChecking';
import {
isCategoryChannel,
isTextChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
import { getCategoryChannel, getVoiceChannel } from '#utils/fetcher';
export class RestrictToolsCommand extends Subcommand {
public constructor(
@ -78,7 +84,9 @@ export class RestrictToolsCommand extends Subcommand {
const user = interaction.options.getUser('user');
const { guild, channel } = interaction;
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
// Checks if all the variables are of the right type
if (guild === null || channel === null) {
@ -90,8 +98,8 @@ export class RestrictToolsCommand extends Subcommand {
let topic: string[];
if (user === null) {
if (channel.type !== ChannelType.GuildText) {
if (!isUser(user)) {
if (!isTextChannel(channel)) {
await interaction.editReply({
content:
'Please make sure you ran this command in the original restricted text channel!',
@ -130,10 +138,10 @@ export class RestrictToolsCommand extends Subcommand {
await channel.delete();
const vcId = topic[3];
const voiceChannel = guild.channels.cache.get(vcId);
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.restricted
) {
await voiceChannel.delete();
@ -142,37 +150,47 @@ export class RestrictToolsCommand extends Subcommand {
return;
}
const category = guild.channels.cache.get(IDs.categories.restricted) as
| CategoryChannel
| undefined;
const category = await getCategoryChannel(IDs.categories.restricted);
if (category === undefined) {
if (!isCategoryChannel(category)) {
await interaction.editReply({
content: 'Could not find category!',
});
return;
}
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
const textChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
for (const c of textChannels) {
const channel = c[1];
// Checks that the channel is a text channel
if (!isTextChannel(channel)) {
continue;
}
// Checks that the channel has a topic
if (channel.topic === null) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (textChannel.topic?.includes(user?.id)) {
topic = textChannel.topic.split(' ');
const vcId = topic[topic.indexOf(user?.id) + 1];
const voiceChannel = guild.channels.cache.get(vcId);
if (channel.topic.includes(user.id)) {
topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(user.id) + 1];
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.restricted
) {
voiceChannel.delete();
await voiceChannel.delete();
}
await channel.delete();
}
textChannel.delete();
}
});
await interaction.editReply({
content: `Successfully deleted the channel for ${user}`,

View File

@ -18,15 +18,30 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { CategoryChannel, ChannelType, EmbedBuilder } from 'discord.js';
import type { User, Message, TextChannel, Guild, Snowflake } from 'discord.js';
import type { Guild, Message, Snowflake, User } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { fetchRoles, addExistingUser } from '#utils/database/dbExistingUser';
import { addExistingUser, fetchRoles } from '#utils/database/dbExistingUser';
import {
unRestrict,
checkActive,
unRestrict,
unRestrictLegacy,
} from '#utils/database/moderation/restriction';
import {
getCategoryChannel,
getGuildMember,
getTextBasedChannel,
getUser,
getVoiceChannel,
} from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
import {
isCategoryChannel,
isGuildMember,
isTextBasedChannel,
isTextChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
export class UnRestrictCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -69,14 +84,14 @@ export class UnRestrictCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await interaction.deferReply();
const info = await this.unRestrictRun(user?.id, mod.id, guild);
const info = await this.unRestrictRun(user.id, mod.id, guild);
await interaction.editReply({
content: info.message,
@ -108,7 +123,7 @@ export class UnRestrictCommand extends Command {
const channelRun = message.channel;
const info = await this.unRestrictRun(
user?.id,
user.id,
mod.id,
guild,
channelRun.id,
@ -132,21 +147,18 @@ export class UnRestrictCommand extends Command {
runInVeganRestrict: false,
};
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
if (!isUser(user)) {
info.message = 'Error fetching user';
return info;
}
}
// Gets mod's GuildMember
const mod = guild.members.cache.get(modId);
const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
info.message = 'Error fetching mod';
return info;
}
@ -155,13 +167,9 @@ export class UnRestrictCommand extends Command {
await addExistingUser(mod);
// Gets guildMember
let member = guild.members.cache.get(userId);
const member = await getGuildMember(userId, guild);
if (member === undefined) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = "Can't unrestrict the user as they are not on this server";
return info;
}
@ -180,16 +188,20 @@ export class UnRestrictCommand extends Command {
if (await checkActive(userId)) {
const roles = await fetchRoles(userId);
await member.roles.add(roles);
// Unrestricts the user on the database
await unRestrict(userId, modId);
} else {
let section = 1;
for (let i = 0; i < restrictRoles.length; i += 1) {
if (member.roles.cache.has(restrictRoles[i])) {
section = i + 1;
}
}
await member.roles.add(IDs.roles.nonvegan.nonvegan);
// Unrestricts the user on the database but for restricts done on the old bot
await unRestrictLegacy(userId, modId, section);
}
@ -198,57 +210,73 @@ export class UnRestrictCommand extends Command {
// Remove vegan restrict channels
if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
const category = guild.channels.cache.get(IDs.categories.restricted) as
| CategoryChannel
| undefined;
const category = await getCategoryChannel(IDs.categories.restricted);
if (!isCategoryChannel(category)) {
info.message =
'Could not find the restricted category! The channels will have to be deleted manually.';
return info;
}
let topic: string[];
if (category !== undefined) {
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
const textChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
for (const c of textChannels) {
const channel = c[1];
// Checks that the channel is a text channel
if (!isTextChannel(channel)) {
continue;
}
// Checks that the channel has a topic
if (channel.topic === null) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (textChannel.topic?.includes(userId)) {
if (textChannel.id === channelRun) {
if (channel.topic.includes(userId)) {
if (channel.id === channelRun) {
info.runInVeganRestrict = true;
}
topic = textChannel.topic.split(' ');
const vcId = topic[topic.indexOf(userId) + 1];
const voiceChannel = guild.channels.cache.get(vcId);
topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(user.id) + 1];
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
isVoiceChannel(voiceChannel) &&
// Used for sanitising the channel topic, so another voice channel does not get deleted
voiceChannel.parentId === IDs.categories.restricted
) {
voiceChannel.delete();
await voiceChannel.delete();
}
textChannel.delete();
await channel.delete();
}
});
}
}
info.success = true;
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(
IDs.channels.logs.restricted,
)) as TextChannel | undefined;
if (logChannel === undefined) {
this.container.logger.error(
'Restrict Error: Could not fetch log channel',
);
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('Unrestrict: Could not fetch log channel');
info.message = `Unrestricted ${user} but could not find the log channel. This has been logged to the database.`;
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Unrestrict: The bot does not have permission to send in the logs channel!',
);
info.message = `Unrestricted ${user} but could not find the log channel. This hasn't been logged in a text channel as the bot does not have permission to send logs!`;
return info;
}
}
const message = new EmbedBuilder()

View File

@ -18,10 +18,13 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Message, TextBasedChannel } from 'discord.js';
import { ChannelType } from 'discord.js';
import { Message, MessageFlagsBitField, TextBasedChannel } from 'discord.js';
import { Duration, DurationFormatter } from '@sapphire/time-utilities';
import { isNumber } from '#utils/maths';
import {
isTextBasedChannel,
isTextChannel,
} from '@sapphire/discord.js-utilities';
export class SlowmodeCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -58,11 +61,11 @@ export class SlowmodeCommand extends Command {
const duration = interaction.options.getString('duration', true);
const { channel } = interaction;
if (channel === null) {
if (!isTextBasedChannel(channel)) {
await interaction.reply({
content: 'Could not fetch channel!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -94,7 +97,7 @@ export class SlowmodeCommand extends Command {
message: '',
success: false,
};
if (channel.type !== ChannelType.GuildText) {
if (!isTextChannel(channel)) {
info.message = 'Channel is not a text channel!';
return info;
}

View File

@ -18,8 +18,10 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { GuildMember, Message } from 'discord.js';
import { GuildMember, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class SoftMuteCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -64,39 +66,39 @@ export class SoftMuteCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching the guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Gets guildMember whilst removing the ability of each other variables being null
const guildMember = guild.members.cache.get(user.id);
// Gets GuildMember whilst removing the ability of each other variables being null
const member = await getGuildMember(user.id, guild);
// Checks if guildMember is null
if (guildMember === undefined) {
if (!isGuildMember(member)) {
await interaction.reply({
content: 'Error fetching user!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
if (guildMember.roles.cache.has(IDs.roles.restrictions.softMute)) {
await guildMember.roles.remove(IDs.roles.restrictions.softMute);
if (member.roles.cache.has(IDs.roles.restrictions.softMute)) {
await member.roles.remove(IDs.roles.restrictions.softMute);
await interaction.reply({
content: `Removed soft muted for ${user}`,
fetchReply: true,
withResponse: true,
});
return;
}
await guildMember.roles.add(IDs.roles.restrictions.softMute);
await member.roles.add(IDs.roles.restrictions.softMute);
await interaction.reply({
content: `Soft muted ${user}`,
fetchReply: true,
withResponse: true,
});
}

View File

@ -27,8 +27,6 @@ import {
ButtonStyle,
User,
Guild,
TextChannel,
GuildMember,
Snowflake,
MessageFlagsBitField,
} from 'discord.js';
@ -43,6 +41,13 @@ import {
import { checkStaff } from '#utils/checker';
import IDs from '#utils/ids';
import { createSusLogEmbed } from '#utils/embeds';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
import {
isGuildMember,
isTextBasedChannel,
isTextChannel,
} from '@sapphire/discord.js-utilities';
// TODO add a check when they join the server to give the user the sus role again
@ -229,19 +234,20 @@ export class SusCommand extends Subcommand {
info.success = true;
// Log the sus note
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.sus)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
this.container.logger.error('Sus Error: Could not fetch log channel');
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('Sus: Could not fetch log channel.');
info.message = `Added a sus note for ${user} but could not find the log channel. This has been logged to the database.`;
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Sus: Does not have permission to message in the log channel.',
);
info.message = `Added a sus note for ${user} but could not send in the logs channel. This has been logged to the database.`;
return info;
}
}
const message = new EmbedBuilder()
@ -265,15 +271,9 @@ export class SusCommand extends Subcommand {
private async addSusRole(user: User, guild: Guild) {
// Get GuildMember for user to add a sus note for
let member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
// Checks if Member was not found in cache
if (member === undefined) {
// Fetches Member from API call to Discord
member = await guild.members.fetch(user.id).catch(() => undefined);
}
if (member === undefined) {
if (!isGuildMember(member)) {
return;
}
@ -289,7 +289,7 @@ export class SusCommand extends Subcommand {
const { guild } = interaction;
// Checks if all the variables are of the right type
if (guild == null) {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
flags: MessageFlagsBitField.Flags.Ephemeral,
@ -330,7 +330,7 @@ export class SusCommand extends Subcommand {
const { guild, channel } = interaction;
// Checks if all the variables are of the right type
if (guild === null || channel === null) {
if (guild === null || !isTextBasedChannel(channel)) {
await interaction.reply({
content: 'Error fetching guild or channel!',
flags: MessageFlagsBitField.Flags.Ephemeral,
@ -356,11 +356,8 @@ export class SusCommand extends Subcommand {
const modId = note.modId;
// Get user GuildMembers for user and mod and person who ran command
let user = guild.client.users.cache.get(userId);
if (!(user instanceof User)) {
user = await guild.client.users.fetch(userId).catch(() => undefined);
}
if (user === undefined) {
const user = await getUser(userId);
if (!isUser(user)) {
await interaction.reply({
content: 'Error fetching user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
@ -369,15 +366,11 @@ export class SusCommand extends Subcommand {
return;
}
let modCreator = guild.client.users.cache.get(modId);
if (!(modCreator instanceof User)) {
modCreator = await guild.client.users.fetch(modId).catch(() => undefined);
}
const modCreator = await getUser(modId);
let modCreatorDisplay = modId;
if (modCreator instanceof User) {
modCreatorDisplay = modCreator.displayName;
}
const modCreatorDisplay = isUser(modCreator)
? modCreator.displayName
: modId;
// Create an embed for the note
const noteEmbed = new EmbedBuilder()
@ -443,18 +436,15 @@ export class SusCommand extends Subcommand {
// Checks if there are no notes on the user and if there's none, remove the sus role
if (notes.length === 0) {
let member = guild.members.cache.get(userId);
if (!(member instanceof GuildMember)) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
const member = guild.members.cache.get(userId);
if (member instanceof GuildMember) {
if (isGuildMember(member)) {
await member.roles.remove(IDs.roles.restrictions.sus);
}
}
// Logs the removal of the sus note
await this.deleteNoteLogger(userId, mod, noteId, guild);
await this.deleteNoteLogger(userId, mod, noteId);
}
});
@ -467,32 +457,22 @@ export class SusCommand extends Subcommand {
}
// Logs removal of 1 sus note
private async deleteNoteLogger(
userId: Snowflake,
mod: User,
noteId: number,
guild: Guild,
) {
private async deleteNoteLogger(userId: Snowflake, mod: User, noteId: number) {
// Find user
let user = guild.client.users.cache.get(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId).catch(() => undefined);
}
if (user === undefined) return;
const user = await getUser(userId);
if (!isUser(user)) return;
// Log the sus note
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.sus)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
this.container.logger.error('Sus Error: Could not fetch log channel');
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('Sus: Could not fetch log channel.');
return;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Sus: The bot does not have permission to send in the log channel',
);
return;
}
}
const embed = new EmbedBuilder()
@ -521,7 +501,7 @@ export class SusCommand extends Subcommand {
const { guild, channel } = interaction;
// Checks if all the variables are of the right type
if (guild === null || channel === null) {
if (guild === null || !isTextBasedChannel(channel)) {
await interaction.reply({
content: 'Error fetching guild or channel!',
flags: MessageFlagsBitField.Flags.Ephemeral,
@ -530,10 +510,10 @@ export class SusCommand extends Subcommand {
return;
}
const member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
// Checks if managed to find GuildMember for the user
if (member === undefined) {
if (!isGuildMember(member)) {
await interaction.reply({
content: 'Error fetching user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
@ -570,10 +550,11 @@ export class SusCommand extends Subcommand {
) {
// Get mod name
let mod = notes[i].modId;
const modGuildMember = guild.members.cache.get(mod);
if (modGuildMember !== undefined) {
const modGuildMember = await getGuildMember(mod, guild);
if (isGuildMember(modGuildMember)) {
mod = modGuildMember.displayName;
}
// Add sus note to embed
noteEmbed.addFields({
name: `Sus ID: ${
@ -633,7 +614,7 @@ export class SusCommand extends Subcommand {
});
}
await this.deleteAllNotesLogger(user, mod, guild);
await this.deleteAllNotesLogger(user, mod);
});
// Remove the buttons after they have been clicked
@ -648,20 +629,18 @@ export class SusCommand extends Subcommand {
}
// Logs removal of 1 sus note
private async deleteAllNotesLogger(user: User, mod: User, guild: Guild) {
private async deleteAllNotesLogger(user: User, mod: User) {
// Log the sus note
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.sus)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
this.container.logger.error('Sus Error: Could not fetch log channel');
if (!isTextChannel(logChannel)) {
this.container.logger.error('Sus: Could not fetch log channel.');
return;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Sus: Could not not send in the log channel.',
);
return;
}
}
const embed = new EmbedBuilder()

View File

@ -18,13 +18,15 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { GuildMember, Message } from 'discord.js';
import { GuildMember, Message, MessageFlagsBitField } from 'discord.js';
import {
addMute,
removeMute,
checkActive,
} from '#utils/database/moderation/vcMute';
import { addExistingUser } from '#utils/database/dbExistingUser';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VCMuteCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -66,29 +68,38 @@ export class VCMuteCommand extends Command {
// Get the arguments
const user = interaction.options.getUser('user', true);
const reason = interaction.options.getString('reason');
const modUser = interaction.user;
const mod = interaction.member;
const { guild } = interaction;
// Checks if all the variables are of the right type
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Gets guildMember whilst removing the ability of each other variables being null
const member = guild.members.cache.get(user.id);
const mod = guild.members.cache.get(modUser.id);
const member = await getGuildMember(user.id, guild);
// Checks if guildMember is null
if (member === undefined || mod === undefined) {
// Checks if `member` was found
if (!isGuildMember(member)) {
await interaction.reply({
content: 'Error fetching user!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Checks if `mod` was found
if (!isGuildMember(mod)) {
await interaction.reply({
content: 'Error fetching your user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -102,8 +113,8 @@ export class VCMuteCommand extends Command {
await interaction.reply({
content: `Removed server mute from ${user}`,
fetchReply: true,
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -118,8 +129,8 @@ export class VCMuteCommand extends Command {
await addMute(member.id, mod.id, reason);
await interaction.reply({
content: `Server muted ${user}`,
fetchReply: true,
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
}
@ -137,7 +148,7 @@ export class VCMuteCommand extends Command {
const reason = args.finished ? null : await args.rest('string');
const mod = message.member;
if (mod === null) {
if (!isGuildMember(mod)) {
await message.react('❌');
await message.reply(
'Moderator not found! Try again or contact a developer!',

View File

@ -18,14 +18,17 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, TextChannel } from 'discord.js';
import type { Message, Guild, User } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import type { Message, User } from 'discord.js';
import IDs from '#utils/ids';
import {
deleteWarning,
fetchWarning,
} from '#utils/database/moderation/warnings';
import { checkStaff } from '#utils/checker';
import { getTextBasedChannel, getUser } from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
import { isTextChannel } from '@sapphire/discord.js-utilities';
export class DeleteWarningCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,23 +65,14 @@ export class DeleteWarningCommand extends Command {
// Get the arguments
const warningId = interaction.options.getInteger('id', true);
const mod = interaction.user;
const { guild } = interaction;
// Checks if all the variables are of the right type
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
});
return;
}
const staffChannel = checkStaff(interaction.channel);
await interaction.deferReply({ ephemeral: !staffChannel });
await interaction.deferReply({
flags: staffChannel ? undefined : MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.deleteWarning(warningId, mod, guild);
const info = await this.deleteWarning(warningId, mod);
await interaction.editReply({
content: info.message,
@ -108,7 +102,7 @@ export class DeleteWarningCommand extends Command {
return;
}
const info = await this.deleteWarning(warningId, mod, guild);
const info = await this.deleteWarning(warningId, mod);
await message.reply({ content: info.message, embeds: info.embeds });
if (!info.success) {
@ -116,7 +110,7 @@ export class DeleteWarningCommand extends Command {
}
}
private async deleteWarning(warningId: number, mod: User, guild: Guild) {
private async deleteWarning(warningId: number, mod: User) {
const info = {
message: '',
embeds: [] as EmbedBuilder[],
@ -134,34 +128,34 @@ export class DeleteWarningCommand extends Command {
info.success = true;
const userId = warning.userId;
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
if (!isUser(user)) {
info.message = `Deleted warning ID \`${warningId}\`, but the user could not be found!`;
return info;
}
}
// Log the warnings deletion
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.sus)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
if (!isTextChannel(logChannel)) {
this.container.logger.error(
'Delete Warning Error: Could not fetch log channel',
'Delete Warning: Could not fetch log channel',
);
info.message =
`Deleted warning for ${user} (Warning ID: ${warningId} but ` +
'could not find the log channel.';
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Delete Warning: The bot does not have permission to send in the logs channel!',
);
info.message =
`Deleted warning for ${user} (Warning ID: ${warningId} but ` +
"But this hasn't been logged in a text channel as the bot does not have permission to send logs!";
return info;
}
}
const message = new EmbedBuilder()

View File

@ -17,17 +17,21 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import {
Args,
Command,
container,
RegisterBehavior,
} from '@sapphire/framework';
import type { User, Message, Snowflake, Guild, TextChannel } from 'discord.js';
EmbedBuilder,
Guild,
Message,
MessageFlagsBitField,
Snowflake,
User,
} from 'discord.js';
import { updateUser } from '#utils/database/dbExistingUser';
import { addWarn } from '#utils/database/moderation/warnings';
import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
import { isUser } from '#utils/typeChecking';
export class WarnCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -76,8 +80,8 @@ export class WarnCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -103,7 +107,7 @@ export class WarnCommand extends Command {
return;
}
const reason = args.finished ? null : await args.rest('string');
const mod = message.member;
const mod = message.author;
if (reason === null) {
await message.react('❌');
@ -111,14 +115,6 @@ export class WarnCommand extends Command {
return;
}
if (mod === null) {
await message.react('❌');
await message.reply(
'Moderator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -149,10 +145,10 @@ export class WarnCommand extends Command {
};
// Gets mod's GuildMember
const mod = guild.members.cache.get(modId);
const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null
if (mod === undefined) {
if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!';
return info;
}
@ -161,15 +157,12 @@ export class WarnCommand extends Command {
await updateUser(mod);
// Gets User for person being restricted
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
if (!isUser(user)) {
info.message = 'Error fetching user';
return info;
}
}
await addWarn(userId, modId, reason);
@ -190,19 +183,20 @@ export class WarnCommand extends Command {
await user.send({ embeds: [dmEmbed] }).catch(() => {});
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(IDs.channels.logs.sus)) as
| TextChannel
| undefined;
if (logChannel === undefined) {
container.logger.error('Warn Error: Could not fetch log channel');
if (!isTextChannel(logChannel)) {
this.container.logger.error('Warn: Could not fetch log channel');
info.message = `Warned ${user} but could not find the log channel. This has been logged to the database.`;
return info;
} else if (!logChannel.isSendable()) {
this.container.logger.error(
'Warn: The bot does not have permission to send in the logs channel!',
);
info.message = `Warned ${user}, but the bot does not have permission to send in the logs channel!`;
return info;
}
}
const message = new EmbedBuilder()

View File

@ -18,12 +18,15 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { ChannelType, EmbedBuilder } from 'discord.js';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import type { Message, Guild, User } from 'discord.js';
import IDs from '#utils/ids';
import { fetchWarnings } from '#utils/database/moderation/warnings';
import { checkStaff } from '#utils/checker';
import { createWarningsEmbed } from '#utils/embeds';
import { isUser } from '#utils/typeChecking';
import { isTextChannel } from '@sapphire/discord.js-utilities';
import { getUser } from '#utils/fetcher';
export class WarningsCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -65,15 +68,17 @@ export class WarningsCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
const staffChannel = checkStaff(interaction.channel);
await interaction.deferReply({ ephemeral: !staffChannel });
await interaction.deferReply({
flags: staffChannel ? undefined : MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.warnings(user, guild);
@ -101,10 +106,10 @@ export class WarningsCommand extends Command {
return;
}
if (user === undefined) {
if (!isUser(user)) {
const { channel } = message;
if (channel.type !== ChannelType.GuildText) {
if (!isTextChannel(channel)) {
await message.react('❌');
await message.reply('User was not provided!');
return;
@ -119,18 +124,16 @@ export class WarningsCommand extends Command {
// eslint-disable-next-line prefer-destructuring
const userId = topic[2];
user = guild.client.users.cache.get(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
}
user = await getUser(userId);
}
}
}
if (user === undefined) {
if (!isUser(user)) {
await message.react('❌');
await message.reply('User was not provided!');
await message.reply(
'User was not provided! (You most likely provided a user incorrectly.)',
);
return;
}

View File

@ -19,7 +19,12 @@
import { Subcommand } from '@sapphire/plugin-subcommands';
import { RegisterBehavior } from '@sapphire/framework';
import { ChannelType, PermissionsBitField, Snowflake } from 'discord.js';
import {
ChannelType,
MessageFlagsBitField,
PermissionsBitField,
Snowflake,
} from 'discord.js';
import { updateUser } from '#utils/database/dbExistingUser';
import {
addStatUser,
@ -36,6 +41,11 @@ import {
} from '#utils/database/outreach';
import IDs from '#utils/ids';
import { EmbedBuilder } from 'discord.js';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
import { getGuildMember, getTextBasedChannel } from '#utils/fetcher';
export class OutreachCommand extends Subcommand {
public constructor(
@ -184,23 +194,21 @@ export class OutreachCommand extends Subcommand {
interaction: Subcommand.ChatInputCommandInteraction,
) {
// const start = interaction.options.getBoolean('start');
const modUser = interaction.user;
const mod = interaction.member;
const { guild } = interaction;
if (guild === null) {
await interaction.reply({
content: 'Mod or guild was not found!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
const mod = guild.members.cache.get(modUser.id);
if (mod === undefined) {
if (!isGuildMember(mod)) {
await interaction.reply({
content: 'Outreach Leader was not found!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -208,7 +216,7 @@ export class OutreachCommand extends Subcommand {
if (!mod.roles.cache.has(IDs.roles.staff.outreachLeader)) {
await interaction.reply({
content: 'You need to be an Outreach Leader to run this command!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -216,39 +224,37 @@ export class OutreachCommand extends Subcommand {
if (await checkActiveEvent()) {
await interaction.reply({
content: 'There is already an active event!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await updateUser(mod);
await createEvent(modUser.id);
await createEvent(mod.id);
await interaction.reply({
content: 'Created the event!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
}
public async eventEnd(interaction: Subcommand.ChatInputCommandInteraction) {
const modUser = interaction.user;
const mod = interaction.member;
const { guild } = interaction;
if (guild === null) {
await interaction.reply({
content: 'Guild not found!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
const mod = guild.members.cache.get(modUser.id);
if (mod === undefined) {
if (!isGuildMember(mod)) {
await interaction.reply({
content: 'Your guild member was not found!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -256,12 +262,14 @@ export class OutreachCommand extends Subcommand {
if (!mod.roles.cache.has(IDs.roles.staff.outreachLeader)) {
await interaction.reply({
content: 'You need to be an Outreach Leader to run this command!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const event = await getCurrentEvent();
@ -299,9 +307,9 @@ export class OutreachCommand extends Subcommand {
educated += group.educated;
});
const activist = guild.channels.cache.get(IDs.channels.activism.activism);
const activist = await getTextBasedChannel(IDs.channels.activism.activism);
if (activist === undefined || !activist.isTextBased()) {
if (!isTextBasedChannel(activist)) {
await interaction.editReply(
'Event has now ended, but could not post statistics!',
);
@ -351,12 +359,14 @@ export class OutreachCommand extends Subcommand {
if (guild === null) {
await interaction.reply({
content: 'Guild not found!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
if ((await getStatFromLeader(leader.id)) !== null) {
await interaction.editReply(
@ -377,9 +387,9 @@ export class OutreachCommand extends Subcommand {
const statGroups = await getStatGroups(event.id);
const groupNo = statGroups.length + 1;
const leaderMember = await guild.members.cache.get(leader.id);
const leaderMember = await getGuildMember(leader.id, guild);
if (leaderMember === undefined) {
if (!isGuildMember(leaderMember)) {
await interaction.editReply({
content: `Could not find ${leader}'s guild member.`,
});
@ -456,18 +466,27 @@ export class OutreachCommand extends Subcommand {
public async groupAdd(interaction: Subcommand.ChatInputCommandInteraction) {
const user = interaction.options.getUser('user', true);
const group = interaction.options.getRole('group');
const leader = interaction.user;
const leader = interaction.member;
const { guild } = interaction;
if (guild === null) {
await interaction.reply({
content: 'Could not find guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await interaction.deferReply({ ephemeral: true });
if (!isGuildMember(leader)) {
await interaction.editReply({
content: 'Could not find your GuildMember!',
});
return;
}
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
let statId: number;
let roleId: Snowflake | undefined;
@ -483,18 +502,9 @@ export class OutreachCommand extends Subcommand {
return;
}
const leaderMember = guild.members.cache.get(leader.id);
if (leaderMember === undefined) {
await interaction.editReply({
content: 'Could not find your GuildMember in cache!',
});
return;
}
if (
leader.id !== stat.stat.leaderId &&
!leaderMember.roles.cache.has(IDs.roles.staff.outreachLeader)
!leader.roles.cache.has(IDs.roles.staff.outreachLeader)
) {
await interaction.editReply({
content: `You are not the leader for ${group}`,
@ -526,9 +536,9 @@ export class OutreachCommand extends Subcommand {
return;
}
const member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
if (member === undefined) {
if (!isGuildMember(member)) {
await interaction.editReply({
content: 'Could not fetch the member!',
});
@ -568,15 +578,9 @@ export class OutreachCommand extends Subcommand {
educated: educated !== null ? educated : 0,
};
if (leader === null) {
await interaction.reply({
content: 'Could not find your user!',
ephemeral: true,
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await interaction.deferReply({ ephemeral: true });
const stat = await getStatFromLeader(leader.id);

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class BookClubCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class BookClubCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageBookClub(user, mod, guild);
@ -88,14 +93,6 @@ export class BookClubCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Event coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class BookClubCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const bookClub = guild.roles.cache.get(IDs.roles.bookClub);
const member = await getGuildMember(user.id, guild);
const bookClub = await getRole(IDs.roles.bookClub, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (bookClub === undefined) {
if (!isRole(bookClub)) {
info.message = 'Error fetching book club role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class DebateHostCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class DebateHostCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageDebateHost(user, mod, guild);
@ -89,14 +94,6 @@ export class DebateHostCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Event coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -116,16 +113,16 @@ export class DebateHostCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const debateHost = guild.roles.cache.get(IDs.roles.debateHost);
const member = await getGuildMember(user.id, guild);
const debateHost = await getRole(IDs.roles.debateHost, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (debateHost === undefined) {
if (!isRole(debateHost)) {
info.message = 'Error fetching debate host role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class GameNightHostCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class GameNightHostCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageGameNight(user, mod, guild);
@ -88,14 +93,6 @@ export class GameNightHostCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Event coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class GameNightHostCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const gameNightHost = guild.roles.cache.get(IDs.roles.gameNightHost);
const member = await getGuildMember(user.id, guild);
const gameNightHost = await getRole(IDs.roles.gameNightHost, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (gameNightHost === undefined) {
if (!isRole(gameNightHost)) {
info.message = 'Error fetching game night host role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class GuestCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class GuestCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageGuest(user, mod, guild);
@ -88,14 +93,6 @@ export class GuestCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Event coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class GuestCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const guest = guild.roles.cache.get(IDs.roles.guest);
const member = await getGuildMember(user.id, guild);
const guest = await getRole(IDs.roles.guest, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (guest === undefined) {
if (!isRole(guest)) {
info.message = 'Error fetching guest role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { isRole } from '#utils/typeChecking';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class MentorCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class MentorCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageMentor(user, mod, guild);
@ -89,14 +94,6 @@ export class MentorCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Mentor coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -116,16 +113,16 @@ export class MentorCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const mentor = guild.roles.cache.get(IDs.roles.staff.mentor);
const member = await getGuildMember(user.id, guild);
const mentor = await getRole(IDs.roles.staff.mentor, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (mentor === undefined) {
if (!isRole(mentor)) {
info.message = 'Error fetching mentor role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class ModCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class ModCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageMod(user, mod, guild);
@ -88,14 +93,6 @@ export class ModCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Mod coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class ModCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const moderator = guild.roles.cache.get(IDs.roles.staff.moderator);
const member = await getGuildMember(user.id, guild);
const moderator = await getRole(IDs.roles.staff.moderator, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (moderator === undefined) {
if (!isRole(moderator)) {
info.message = 'Error fetching the moderator role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class RestrictedAccessCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class RestrictedAccessCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageRestrictedAccess(user, mod, guild);
@ -89,14 +94,6 @@ export class RestrictedAccessCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Mod coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -116,16 +113,16 @@ export class RestrictedAccessCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const restricted = guild.roles.cache.get(IDs.roles.staff.restricted);
const member = await getGuildMember(user.id, guild);
const restricted = await getRole(IDs.roles.staff.restricted, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (restricted === undefined) {
if (!isRole(restricted)) {
info.message = 'Error fetching the restricted access role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class StageHostCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class StageHostCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageStageHost(user, mod, guild);
@ -88,14 +93,6 @@ export class StageHostCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Event coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class StageHostCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const stageHost = guild.roles.cache.get(IDs.roles.stageHost);
const member = await getGuildMember(user.id, guild);
const stageHost = await getRole(IDs.roles.stageHost, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (stageHost === undefined) {
if (!isRole(stageHost)) {
info.message = 'Error fetching stage host role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class TrialModCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class TrialModCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageMod(user, mod, guild);
@ -89,14 +94,6 @@ export class TrialModCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Mod coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -116,16 +113,16 @@ export class TrialModCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const moderator = guild.roles.cache.get(IDs.roles.staff.trialModerator);
const member = await getGuildMember(user.id, guild);
const moderator = await getRole(IDs.roles.staff.trialModerator, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (moderator === undefined) {
if (!isRole(moderator)) {
info.message = 'Error fetching the trial moderator role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class TrialVerifierCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class TrialVerifierCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageTrialVerifier(user, mod, guild);
@ -88,14 +93,6 @@ export class TrialVerifierCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Verifier coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class TrialVerifierCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const trialVerifier = guild.roles.cache.get(IDs.roles.staff.trialVerifier);
const member = await getGuildMember(user.id, guild);
const trialVerifier = await getRole(IDs.roles.staff.trialVerifier, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (trialVerifier === undefined) {
if (!isRole(trialVerifier)) {
info.message = 'Error fetching the trial verifier role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class VerifierCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,13 +65,15 @@ export class VerifierCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageVerifier(user, mod, guild);
@ -88,14 +93,6 @@ export class VerifierCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Verifier coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +112,16 @@ export class VerifierCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const verifier = guild.roles.cache.get(IDs.roles.staff.verifier);
const member = await getGuildMember(user.id, guild);
const verifier = await getRole(IDs.roles.staff.verifier, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (verifier === undefined) {
if (!isRole(verifier)) {
info.message = 'Error fetching verifier role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class ActivistCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -65,13 +68,15 @@ export class ActivistCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageActivist(user, mod, guild);
@ -91,12 +96,6 @@ export class ActivistCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply('Staff not found! Try again or contact a developer!');
return;
}
const { guild } = message;
if (guild === null) {
@ -116,22 +115,22 @@ export class ActivistCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const modMember = guild.members.cache.get(mod.id);
const activist = guild.roles.cache.get(IDs.roles.vegan.activist);
const member = await getGuildMember(user.id, guild);
const modMember = await getGuildMember(mod.id, guild);
const activist = await getRole(IDs.roles.vegan.activist, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (modMember === undefined) {
if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!";
return info;
}
if (activist === undefined) {
if (!isRole(activist)) {
info.message = 'Error fetching activist role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class ARAVeganCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -64,13 +67,15 @@ export class ARAVeganCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageVegan(user, mod, guild);
@ -90,12 +95,6 @@ export class ARAVeganCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply('Staff not found! Try again or contact a developer!');
return;
}
const { guild } = message;
if (guild === null) {
@ -115,22 +114,22 @@ export class ARAVeganCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const modMember = guild.members.cache.get(mod.id);
const vegan = guild.roles.cache.get(IDs.roles.vegan.araVegan);
const member = await getGuildMember(user.id, guild);
const modMember = await getGuildMember(mod.id, guild);
const vegan = await getRole(IDs.roles.vegan.araVegan, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (modMember === undefined) {
if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!";
return info;
}
if (vegan === undefined) {
if (!isRole(vegan)) {
info.message = 'Error fetching vegan role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class ConvincedCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class ConvincedCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageConvinced(user, mod, guild);
@ -89,12 +94,6 @@ export class ConvincedCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply('Mod not found! Try again or contact a developer!');
return;
}
const { guild } = message;
if (guild === null) {
@ -114,16 +113,16 @@ export class ConvincedCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const convinced = guild.roles.cache.get(IDs.roles.nonvegan.convinced);
const member = await getGuildMember(user.id, guild);
const convinced = await getRole(IDs.roles.nonvegan.convinced, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (convinced === undefined) {
if (!isRole(convinced)) {
info.message = 'Error fetching coordinator role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class PlusCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,7 +66,7 @@ export class PlusCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -88,14 +91,6 @@ export class PlusCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply(
'Coordinator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message;
if (guild === null) {
@ -115,16 +110,16 @@ export class PlusCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const plus = guild.roles.cache.get(IDs.roles.vegan.plus);
const member = await getGuildMember(user.id, guild);
const plus = await getRole(IDs.roles.vegan.plus, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (plus === undefined) {
if (!isRole(plus)) {
info.message = 'Error fetching plus role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class TrustedCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class TrustedCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageTrusted(user, mod, guild);
@ -89,12 +94,6 @@ export class TrustedCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply('Mod not found! Try again or contact a developer!');
return;
}
const { guild } = message;
if (guild === null) {
@ -114,16 +113,16 @@ export class TrustedCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const trusted = guild.roles.cache.get(IDs.roles.trusted);
const member = await getGuildMember(user.id, guild);
const trusted = await getRole(IDs.roles.trusted, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (trusted === undefined) {
if (!isRole(trusted)) {
info.message = 'Error fetching trusted role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class VeganCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -65,13 +68,15 @@ export class VeganCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageVegan(user, mod, guild);
@ -91,12 +96,6 @@ export class VeganCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply('Staff not found! Try again or contact a developer!');
return;
}
const { guild } = message;
if (guild === null) {
@ -116,22 +115,22 @@ export class VeganCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const modMember = guild.members.cache.get(mod.id);
const vegan = guild.roles.cache.get(IDs.roles.vegan.vegan);
const member = await getGuildMember(user.id, guild);
const modMember = await getGuildMember(mod.id, guild);
const vegan = await getRole(IDs.roles.vegan.vegan, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (modMember === undefined) {
if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!";
return info;
}
if (vegan === undefined) {
if (!isRole(vegan)) {
info.message = 'Error fetching vegan role from cache!';
return info;
}

View File

@ -18,9 +18,12 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, User, Message } from 'discord.js';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role';
import { getGuildMember, getRole } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
import { isRole } from '#utils/typeChecking';
export class VegCuriousCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -63,13 +66,15 @@ export class VegCuriousCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
const info = await this.manageVegCurious(user, mod, guild);
@ -89,12 +94,6 @@ export class VegCuriousCommand extends Command {
const mod = message.author;
if (mod === null) {
await message.react('❌');
await message.reply('Staff not found! Try again or contact a developer!');
return;
}
const { guild } = message;
if (guild === null) {
@ -114,22 +113,22 @@ export class VegCuriousCommand extends Command {
message: '',
success: false,
};
const member = guild.members.cache.get(user.id);
const modMember = guild.members.cache.get(mod.id);
const vegCurious = guild.roles.cache.get(IDs.roles.nonvegan.vegCurious);
const member = await getGuildMember(user.id, guild);
const modMember = await getGuildMember(mod.id, guild);
const vegCurious = await getRole(IDs.roles.nonvegan.vegCurious, guild);
// Checks if user's GuildMember was found in cache
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!';
return info;
}
if (modMember === undefined) {
if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!";
return info;
}
if (vegCurious === undefined) {
if (!isRole(vegCurious)) {
info.message = 'Error fetching veg curious role from cache!';
return info;
}

View File

@ -18,7 +18,7 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import type { Message } from 'discord.js';
import { Message, MessageFlagsBitField } from 'discord.js';
export class ApplyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -47,8 +47,8 @@ export class ApplyCommand extends Command {
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
await interaction.reply({
content: this.message,
fetchReply: true,
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
}

View File

@ -18,8 +18,10 @@
*/
import { Command, RegisterBehavior } from '@sapphire/framework';
import type { Message } from 'discord.js';
import { Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { getRole } from '#utils/fetcher';
import { isRole } from '#utils/typeChecking';
export class RenameUserCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -47,22 +49,22 @@ export class RenameUserCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await guild.members.fetch();
const vegan = await guild.roles.cache.get(IDs.roles.vegan.vegan);
const notVegan = await guild.roles.cache.get(IDs.roles.nonvegan.nonvegan);
const vegan = await getRole(IDs.roles.vegan.vegan, guild);
const notVegan = await getRole(IDs.roles.nonvegan.nonvegan, guild);
if (vegan === undefined || notVegan === undefined) {
if (!isRole(vegan) || !isRole(notVegan)) {
await interaction.reply({
content: 'Error fetching roles!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -71,7 +73,7 @@ export class RenameUserCommand extends Command {
content:
`${vegan.name}s: \`${vegan.members.size}\`` +
`\n${notVegan.name}s: \`${notVegan.members.size}\``,
fetchReply: true,
withResponse: true,
});
}
@ -88,8 +90,8 @@ export class RenameUserCommand extends Command {
await guild.members.fetch();
const vegan = await guild.roles.cache.get(IDs.roles.vegan.vegan);
const notVegan = await guild.roles.cache.get(IDs.roles.nonvegan.nonvegan);
const vegan = guild.roles.cache.get(IDs.roles.vegan.vegan);
const notVegan = guild.roles.cache.get(IDs.roles.nonvegan.nonvegan);
if (vegan === undefined || notVegan === undefined) {
await message.react('❌');

View File

@ -19,6 +19,7 @@
import { Command, RegisterBehavior } from '@sapphire/framework';
import IDs from '#utils/ids';
import { MessageFlagsBitField } from 'discord.js';
export class InfoCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -66,11 +67,7 @@ export class InfoCommand extends Command {
const option = interaction.options.getString('info', true);
let ephemeral = interaction.options.getBoolean('visible');
if (ephemeral === null) {
ephemeral = true;
} else {
ephemeral = !ephemeral;
}
ephemeral = ephemeral !== true;
let message: string;
@ -115,7 +112,7 @@ export class InfoCommand extends Command {
await interaction.reply({
content: message,
ephemeral,
flags: ephemeral ? MessageFlagsBitField.Flags.Ephemeral : undefined,
});
}
}

View File

@ -18,13 +18,21 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Message, User, Guild, Snowflake } from 'discord.js';
import {
Message,
User,
Guild,
Snowflake,
MessageFlagsBitField,
} from 'discord.js';
import IDs from '#utils/ids';
import {
finishVerifyMessages,
giveVerificationRoles,
} from '#utils/verification';
import { manualVerification } from '#utils/database/verification';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VerifyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -77,8 +85,8 @@ export class VerifyCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
@ -93,7 +101,7 @@ export class VerifyCommand extends Command {
await interaction.reply({
content: verify.message,
fetchReply: true,
withResponse: true,
});
}
@ -159,32 +167,26 @@ export class VerifyCommand extends Command {
convinced: false,
};
let member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
// Checks if member is null
if (member === undefined) {
member = await guild.members.fetch(user.id).catch(() => undefined);
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'Failed to fetch member';
return info;
}
}
if (member.roles.cache.hasAny(...IDs.roles.restrictions.restricted)) {
info.message = "Can't verify a restricted user!";
return info;
}
let verifier = guild.members.cache.get(verifierId);
const verifier = await getGuildMember(verifierId, guild);
// Checks if verifier is null
if (verifier === undefined) {
verifier = await guild.members.fetch(user.id).catch(() => undefined);
if (verifier === undefined) {
if (!isGuildMember(verifier)) {
info.message = 'Failed to fetch verifier';
return info;
}
}
const roleArgs = rolesString.split(' ');

View File

@ -20,6 +20,9 @@
import { Command, RegisterBehavior } from '@sapphire/framework';
import IDs from '#utils/ids';
import { checkVerificationFinish } from '#utils/database/verification';
import { MessageFlagsBitField } from 'discord.js';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VerifyTimeoutRemoveCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -60,23 +63,22 @@ export class VerifyTimeoutRemoveCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Error fetching guild!',
ephemeral: true,
fetchReply: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
await interaction.deferReply({ ephemeral: true });
await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral,
});
let member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
if (member === undefined) {
member = await guild.members.fetch(user.id).catch(undefined);
if (member === undefined) {
if (!isGuildMember(member)) {
await interaction.editReply(`${user} is not on this server!`);
return;
}
}
if (!member.roles.cache.has(IDs.roles.verifyBlock)) {
await interaction.editReply(`${user} is not blocked from verification!`);

View File

@ -18,9 +18,11 @@
*/
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { User, Guild, Message } from 'discord.js';
import { User, Guild, Message, MessageFlagsBitField } from 'discord.js';
import { EmbedBuilder } from 'discord.js';
import { getRank, xpToNextLevel } from '#utils/database/fun/xp';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class RankCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -55,7 +57,7 @@ export class RankCommand extends Command {
if (guild === null) {
await interaction.reply({
content: 'Could not find the guild!',
ephemeral: true,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
@ -108,15 +110,12 @@ export class RankCommand extends Command {
success: false,
};
let member = guild.members.cache.get(user.id);
const member = await getGuildMember(user.id, guild);
if (member === undefined) {
member = await guild.members.fetch(user.id).catch(() => undefined);
if (member === undefined) {
if (!isGuildMember(member)) {
info.message = 'The user is not on this server!';
return info;
}
}
const rank = await getRank(user.id);

View File

@ -21,12 +21,9 @@ import {
InteractionHandler,
InteractionHandlerTypes,
} from '@sapphire/framework';
import {
ButtonInteraction,
GuildMember,
MessageFlagsBitField,
} from 'discord.js';
import { ButtonInteraction, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class NonVeganAccessButtonHandler extends InteractionHandler {
public constructor(
@ -46,13 +43,13 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
}
public async run(interaction: ButtonInteraction) {
let { member } = interaction;
const { member } = interaction;
const errorMessage =
'There was an error giving you the role, please try again later or contact ModMail/the developer ' +
'to sort out this problem.';
if (member === null) {
if (!isGuildMember(member)) {
await interaction.reply({
content: errorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
@ -60,18 +57,13 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
return;
}
try {
member = member as GuildMember;
if (!member.roles.cache.has(IDs.roles.vegan.vegan)) {
await interaction.reply({
content: 'You need to be vegan to use this button!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
if (member.roles.cache.has(IDs.roles.vegan.nvAccess)) {
} else if (member.roles.cache.has(IDs.roles.vegan.nvAccess)) {
await member.roles.remove(IDs.roles.vegan.nvAccess);
await interaction.reply({
content:
@ -80,8 +72,7 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
} else {
await member.roles.add(IDs.roles.vegan.nvAccess);
await interaction.reply({
content:
@ -89,12 +80,6 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
'If you want to remove access again, click this button again.',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
} catch (error) {
this.container.logger.error(`Non Vegan Access Interaction: ${error}`);
await interaction.reply({
content: errorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
}
}
}

View File

@ -21,14 +21,12 @@ import {
InteractionHandler,
InteractionHandlerTypes,
} from '@sapphire/framework';
import {
ButtonInteraction,
GuildMember,
MessageFlagsBitField,
} from 'discord.js';
import { ButtonInteraction, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids';
import { checkActive } from '#utils/database/moderation/restriction';
import { addUser } from '#utils/database/dbExistingUser';
import { getTextBasedChannel } from '#utils/fetcher';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
export class WelcomeButtonHandler extends InteractionHandler {
public constructor(
@ -49,9 +47,7 @@ export class WelcomeButtonHandler extends InteractionHandler {
public async run(interaction: ButtonInteraction) {
const { member } = interaction;
let general = this.container.client.channels.cache.get(
IDs.channels.nonVegan.general,
);
const general = await getTextBasedChannel(IDs.channels.nonVegan.general);
// Messages that are used multiple times
const roleErrorMessage =
@ -63,14 +59,7 @@ export class WelcomeButtonHandler extends InteractionHandler {
'to be verified and gain access to more channels.';
// Checks if general is not in the cache
if (general === undefined) {
// Sends an API request to get the channel
const generalFetch = await this.container.client.channels
.fetch(IDs.channels.nonVegan.general)
.catch(() => undefined);
// If general does not exist
if (generalFetch === null || generalFetch === undefined) {
if (!isTextChannel(general)) {
this.container.logger.error(
'WelcomeButtonHandler: Could not find and fetch the general channel!',
);
@ -83,12 +72,8 @@ export class WelcomeButtonHandler extends InteractionHandler {
return;
}
// Replace fetched version of general with the cached version
general = generalFetch;
}
// If the member could not be found
if (!(member instanceof GuildMember)) {
if (!isGuildMember(member)) {
await interaction.reply({
content: roleErrorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,

View File

@ -19,10 +19,12 @@
import { Listener } from '@sapphire/framework';
import type { GuildBan } from 'discord.js';
import { AuditLogEvent, EmbedBuilder, TextChannel } from 'discord.js';
import { AuditLogEvent, EmbedBuilder } from 'discord.js';
import { addBan, checkBan } from '#utils/database/moderation/ban';
import IDs from '#utils/ids';
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser';
import { getGuildMember, getTextBasedChannel } from '#utils/fetcher';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
export class BanListener extends Listener {
public constructor(
@ -82,18 +84,13 @@ export class BanListener extends Listener {
const { guild } = ban;
// Gets mod's GuildMember
let mod = guild.members.cache.get(executor.id);
const mod = await getGuildMember(executor.id, guild);
// Checks if GuildMember is null
if (mod === undefined) {
mod = await guild.members.fetch(executor.id).catch(() => undefined);
if (mod === undefined) {
this.container.logger.error(
'UnbanListener: Could not fetch moderator.',
);
if (!isGuildMember(mod)) {
this.container.logger.error('UnbanListener: Could not fetch moderator.');
return;
}
}
// Check if mod is in database
await addExistingUser(mod);
@ -118,19 +115,12 @@ export class BanListener extends Listener {
await addBan(user.id, mod.id, `${reason}`);
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(
IDs.channels.logs.restricted,
)) as TextChannel | undefined;
if (logChannel === undefined) {
if (!isTextChannel(logChannel)) {
this.container.logger.error('BanListener: Could not fetch log channel');
return;
}
}
const log = new EmbedBuilder()
.setColor('#FF0000')

View File

@ -19,10 +19,12 @@
import { Listener } from '@sapphire/framework';
import type { GuildBan } from 'discord.js';
import { AuditLogEvent, EmbedBuilder, TextChannel } from 'discord.js';
import { AuditLogEvent, EmbedBuilder } from 'discord.js';
import { addBan, checkBan, removeBan } from '#utils/database/moderation/ban';
import IDs from '#utils/ids';
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser';
import { getGuildMember, getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class UnbanListener extends Listener {
public constructor(
@ -71,18 +73,13 @@ export class UnbanListener extends Listener {
const { guild } = ban;
// Gets mod's GuildMember
let mod = guild.members.cache.get(executor.id);
const mod = await getGuildMember(executor.id, guild);
// Checks if GuildMember is null
if (mod === undefined) {
mod = await guild.members.fetch(executor.id).catch(() => undefined);
if (mod === undefined) {
this.container.logger.error(
'UnbanListener: Could not fetch moderator.',
);
this.container.logger.error('UnbanListener: Could not fetch moderator.');
return;
}
}
// Check if mod is in database
await addExistingUser(mod);
@ -100,21 +97,12 @@ export class UnbanListener extends Listener {
await removeBan(user.id, mod.id);
// Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted) as
| TextChannel
| undefined;
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) {
logChannel = (await guild.channels.fetch(
IDs.channels.logs.restricted,
)) as TextChannel | undefined;
if (logChannel === undefined) {
this.container.logger.error(
'UnbanListener: Could not fetch log channel',
);
if (!isTextBasedChannel(logChannel)) {
this.container.logger.error('UnbanListener: Could not fetch log channel');
return;
}
}
const log = new EmbedBuilder()
.setColor('#28A745')

View File

@ -44,19 +44,22 @@ export class XpListener extends Listener {
return;
}
if (!message.channel.isSendable()) {
this.container.logger.error(
'Counting: The bot does not have permission to send messages in the counting chat!',
);
return;
}
let lastCount = await getLastCount();
// If no counts exist on the database, then create the first count from the bot
if (lastCount === null) {
if (this.container.client.id === null) {
if (!message.channel.isSendable()) {
// TODO manage logging/errors properly
return;
}
message.channel.send(
'An unexpected error occurred trying to set up the counting channel, please contact a developer!',
);
return;
}
@ -68,14 +71,10 @@ export class XpListener extends Listener {
lastCount = await getLastCount();
if (lastCount === null) {
if (!message.channel.isSendable()) {
// TODO manage logging/errors properly
return;
}
message.channel.send(
'An unexpected error occurred, please contact a developer!',
);
return;
}
}

View File

@ -22,11 +22,12 @@
import { Listener } from '@sapphire/framework';
import { DurationFormatter } from '@sapphire/time-utilities';
import { Client } from 'discord.js';
import IDs from '#utils/ids';
import { fetchRoles } from '#utils/database/dbExistingUser';
import { checkActive } from '#utils/database/moderation/restriction';
import { getUser } from '#utils/database/fun/xp';
import { getGuild, getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class FixRolesOnReady extends Listener {
public constructor(
@ -45,13 +46,13 @@ export class FixRolesOnReady extends Listener {
});
}
public async run(client: Client) {
public async run() {
this.container.logger.info(
'FixRolesOnReady: Preparation before starting to fix the roles for each user...',
);
// Fetching the Guild
const guild = await client.guilds.fetch(IDs.guild).catch(() => undefined);
const guild = await getGuild(IDs.guild);
if (guild === undefined) {
this.container.logger.error('FixRolesOnReady: Could not find the server');
@ -60,8 +61,8 @@ export class FixRolesOnReady extends Listener {
// Fetching the channel for the logs
// Leave the snowflake parameter empty for no logs
const logChannel = await client.channels.fetch('').catch(() => null);
const sendLogs = logChannel !== null;
const logChannel = await getTextBasedChannel('');
const sendLogs = isTextBasedChannel(logChannel);
if (!sendLogs) {
this.container.logger.error(
@ -134,11 +135,7 @@ export class FixRolesOnReady extends Listener {
if (
restricted ||
member.roles.cache.has(IDs.roles.restrictions.restricted1) ||
member.roles.cache.has(IDs.roles.restrictions.restricted2) ||
member.roles.cache.has(IDs.roles.restrictions.restricted3) ||
member.roles.cache.has(IDs.roles.restrictions.restricted4) ||
member.roles.cache.has(IDs.roles.restrictions.restrictedVegan)
member.roles.cache.hasAny(...IDs.roles.restrictions.restricted)
) {
continue;
}

View File

@ -18,7 +18,6 @@
*/
import { Listener } from '@sapphire/framework';
import { ChannelType } from 'discord.js';
import type { GuildChannel, EmbedBuilder } from 'discord.js';
import { setTimeout } from 'timers/promises';
import IDs from '#utils/ids';
@ -33,6 +32,9 @@ import {
createWarningsEmbed,
} from '#utils/embeds';
import { fetchWarnings } from '#utils/database/moderation/warnings';
import { isTextChannel } from '@sapphire/discord.js-utilities';
import { getUser } from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
export class ModMailCreateListener extends Listener {
public constructor(
@ -50,8 +52,7 @@ export class ModMailCreateListener extends Listener {
if (channel.parentId !== IDs.categories.modMail) return;
// Checks if the channel is not a text channel
if (!channel.isTextBased()) return;
if (channel.type !== ChannelType.GuildText) return;
if (!isTextChannel(channel)) return;
// Gets the guild
const { guild } = channel;
@ -64,14 +65,11 @@ export class ModMailCreateListener extends Listener {
const userId = topic[2];
// Gets user who created ModMail
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
if (!isUser(user)) {
return;
}
}
// Check if the user is currently restricted on the database
if (!(await checkActive(userId))) return;

View File

@ -20,8 +20,9 @@
import { Listener } from '@sapphire/framework';
import { ButtonStyle, ActionRowBuilder, ButtonBuilder } from 'discord.js';
import type { Client, TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class NonVeganAccessReady extends Listener {
public constructor(
@ -35,19 +36,13 @@ export class NonVeganAccessReady extends Listener {
});
}
public async run(client: Client) {
let roles = client.channels.cache.get(IDs.channels.information.roles) as
| TextChannel
| undefined;
if (roles === undefined) {
roles = (await client.channels.fetch(IDs.channels.information.roles)) as
| TextChannel
| undefined;
if (roles === undefined) {
public async run() {
const roles = await getTextBasedChannel(IDs.channels.information.roles);
if (!isTextBasedChannel(roles)) {
this.container.logger.error('nonVeganAccess: Roles not found');
return;
}
}
const botId = this.container.client.id;
const messages = await roles.messages.fetch();

View File

@ -23,6 +23,8 @@
import { Listener } from '@sapphire/framework';
import type { Client } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class ReadyListener extends Listener {
public constructor(
@ -40,9 +42,9 @@ export class ReadyListener extends Listener {
const { username, id } = client.user!;
this.container.logger.info(`Successfully logged in as ${username} (${id})`);
const botLogChannel = await client.channels.fetch(IDs.channels.logs.bot);
const botLogChannel = await getTextBasedChannel(IDs.channels.logs.bot);
if (botLogChannel === null) {
if (!isTextBasedChannel(botLogChannel)) {
this.container.logger.error(
'ReadyListener: Could not find the channel for bot logs.',
);

View File

@ -18,14 +18,7 @@
*/
import { Listener } from '@sapphire/framework';
import type {
GuildMember,
Snowflake,
CategoryChannel,
Guild,
TextChannel,
} from 'discord.js';
import { ChannelType } from 'discord.js';
import type { GuildMember, Snowflake, CategoryChannel } from 'discord.js';
import { fetchRoles, getLeaveRoles } from '#utils/database/dbExistingUser';
import { blockTime } from '#utils/database/verification';
import {
@ -34,6 +27,12 @@ import {
} from '#utils/database/moderation/restriction';
import { blockedRoles, blockedRolesAfterRestricted } from '#utils/blockedRoles';
import IDs from '#utils/ids';
import { getCategoryChannel, getVoiceChannel } from '#utils/fetcher';
import {
isCategoryChannel,
isTextChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
export class RolesJoinServerListener extends Listener {
public constructor(
@ -77,14 +76,11 @@ export class RolesJoinServerListener extends Listener {
// Add user to the restricted vegan channel
if (section === 5) {
const restrictedCategory = member.guild.channels.cache.get(
const restrictedCategory = await getCategoryChannel(
IDs.categories.restricted,
);
if (
restrictedCategory !== undefined &&
restrictedCategory.type === ChannelType.GuildCategory
) {
await this.restrictRun(member.id, restrictedCategory, member.guild);
if (isCategoryChannel(restrictedCategory)) {
await this.restrictRun(member.id, restrictedCategory);
}
}
}
@ -103,76 +99,79 @@ export class RolesJoinServerListener extends Listener {
await member.roles.add(roles);
}
const privateCategory = member.guild.channels.cache.get(
IDs.categories.private,
);
const privateCategory = await getCategoryChannel(IDs.categories.private);
if (
privateCategory !== undefined &&
privateCategory.type === ChannelType.GuildCategory
) {
await this.privateRun(member.id, privateCategory, member.guild);
if (isCategoryChannel(privateCategory)) {
await this.privateRun(member.id, privateCategory);
}
// TODO add access back to diversity team
}
private async restrictRun(
userId: Snowflake,
category: CategoryChannel,
guild: Guild,
) {
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
private async restrictRun(userId: Snowflake, category: CategoryChannel) {
const textChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
for (const c of textChannels) {
const channel = c[1];
if (!isTextChannel(channel)) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (textChannel.topic?.includes(userId)) {
const topic = textChannel.topic.split(' ');
if (channel.topic !== null && channel.topic.includes(userId)) {
const topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(userId) + 1];
const voiceChannel = guild.channels.cache.get(vcId);
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
voiceChannel.parentId === IDs.categories.restricted &&
voiceChannel.isVoiceBased()
isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.restricted
) {
voiceChannel.permissionOverwrites.edit(userId, { ViewChannel: true });
}
textChannel.permissionOverwrites.edit(userId, { ViewChannel: true });
}
await voiceChannel.permissionOverwrites.edit(userId, {
ViewChannel: true,
});
}
private async privateRun(
userId: Snowflake,
category: CategoryChannel,
guild: Guild,
) {
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
await channel.permissionOverwrites.edit(userId, { ViewChannel: true });
}
}
}
private async privateRun(userId: Snowflake, category: CategoryChannel) {
const textChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
for (const c of textChannels) {
const channel = c[1];
if (!isTextChannel(channel)) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (textChannel.topic?.includes(userId)) {
const topic = textChannel.topic.split(' ');
if (channel.topic !== null && channel.topic.includes(userId)) {
const topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(userId) + 2];
const voiceChannel = guild.channels.cache.get(vcId);
const voiceChannel = await getVoiceChannel(vcId);
if (
voiceChannel !== undefined &&
voiceChannel.parentId === IDs.categories.private &&
voiceChannel.isVoiceBased()
isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.private
) {
voiceChannel.permissionOverwrites.edit(userId, { ViewChannel: true });
}
textChannel.permissionOverwrites.edit(userId, { ViewChannel: true });
}
await voiceChannel.permissionOverwrites.edit(userId, {
ViewChannel: true,
});
}
await channel.permissionOverwrites.edit(userId, { ViewChannel: true });
}
}
}
private blockedRole(role: Snowflake) {
return !blockedRoles.includes(role);
}

View File

@ -21,6 +21,8 @@ import { Listener } from '@sapphire/framework';
import { EmbedBuilder } from 'discord.js';
import type { Message } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextChannel } from '@sapphire/discord.js-utilities';
export class Suggestions extends Listener {
public constructor(
@ -38,14 +40,19 @@ export class Suggestions extends Listener {
return;
}
const mailbox = await this.container.client.channels.cache.get(
IDs.channels.staff.mailbox,
);
const mailbox = await getTextBasedChannel(IDs.channels.staff.mailbox);
if (mailbox === undefined || !mailbox.isTextBased()) {
if (!isTextChannel(mailbox)) {
this.container.logger.error(
'Mailbox is not a TextBased channel or is undefined',
);
return;
} else if (!mailbox.isSendable()) {
this.container.logger.error(
'Suggestions: The bot does not have permissions to send messages in the mailbox!',
);
return;
}
@ -83,11 +90,6 @@ export class Suggestions extends Listener {
return;
}
if (!mailbox.isSendable()) {
// TODO manage logging/errors properly
return;
}
const sent = await mailbox.send({
embeds: [suggestion],
content: message.author.toString(),

View File

@ -20,6 +20,7 @@
import { Listener } from '@sapphire/framework';
import type { VoiceState } from 'discord.js';
import { checkActive, removeMute } from '#utils/database/moderation/vcMute';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VCMuteListener extends Listener {
public constructor(
@ -37,7 +38,7 @@ export class VCMuteListener extends Listener {
if (oldState.channel === null && newState.channel !== null) {
const { member } = newState;
if (member === null) {
if (!isGuildMember(member)) {
this.container.logger.error(
'VCMute Listener - GuildMember not found when joining',
);

View File

@ -19,10 +19,8 @@
import { container, Listener } from '@sapphire/framework';
import type {
CategoryChannel,
ColorResolvable,
TextChannel,
VoiceChannel,
VoiceState,
GuildMember,
Guild,
@ -30,7 +28,6 @@ import type {
} from 'discord.js';
import {
time,
ChannelType,
PermissionsBitField,
ButtonBuilder,
ButtonInteraction,
@ -54,6 +51,16 @@ import { findNotes } from '#utils/database/moderation/sus';
import { addExistingUser } from '#utils/database/dbExistingUser';
import { rolesToString } from '#utils/formatter';
import IDs from '#utils/ids';
import {
getCategoryChannel,
getGuildMember,
getVoiceChannel,
} from '#utils/fetcher';
import {
isCategoryChannel,
isGuildMember,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
export class VerificationJoinVCListener extends Listener {
public constructor(
@ -84,20 +91,19 @@ export class VerificationJoinVCListener extends Listener {
const { client } = container;
const guild = client.guilds.cache.get(newState.guild.id);
if (channel === null || member === null || guild === undefined) {
if (member === null || guild === undefined) {
this.container.logger.error('Verification channel not found');
return;
}
// Get current category and channel
const categoryGuild = guild.channels.cache.get(IDs.categories.verification);
const currentChannelGuild = guild.channels.cache.get(channel.id);
if (currentChannelGuild === undefined || categoryGuild === undefined) {
const category = await getCategoryChannel(IDs.categories.verification);
const currentChannel = await getVoiceChannel(channel.id);
if (!isCategoryChannel(category) || !isVoiceChannel(currentChannel)) {
this.container.logger.error('Verification channel not found');
return;
}
const currentChannel = currentChannelGuild as VoiceChannel;
const category = categoryGuild as CategoryChannel;
const roles: Snowflake[] = [];
@ -167,8 +173,8 @@ export class VerificationJoinVCListener extends Listener {
}
// Check how many voice channels there are
const listVoiceChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildVoice,
const listVoiceChannels = category.children.cache.filter((channel) =>
isVoiceChannel(channel),
);
// Create a text channel for verifiers only
@ -300,11 +306,12 @@ export class VerificationJoinVCListener extends Listener {
i += 1
) {
// Get mod name
const modGuildMember = guild.members.cache.get(notes[i].modId);
const modGuildMember = await getGuildMember(notes[i].modId, guild);
let mod = notes[i].modId;
if (modGuildMember !== undefined) {
if (isGuildMember(modGuildMember)) {
mod = modGuildMember.displayName;
}
// Add sus note to embed
embed.addFields({
name: `Sus ID: ${
@ -495,10 +502,8 @@ export class VerificationJoinVCListener extends Listener {
// Confirming and finishing the verification
if (button.customId === 'confirm' && info.page >= questionLength) {
// Check verifier is on the database
const verifierGuildMember = await guild.members.cache.get(
button.user.id,
);
if (verifierGuildMember === undefined) {
const verifierGuildMember = await getGuildMember(button.user.id, guild);
if (!isGuildMember(verifierGuildMember)) {
await message.edit({ content: 'Verifier not found!' });
return;
}

View File

@ -18,13 +18,8 @@
*/
import { Listener } from '@sapphire/framework';
import type {
VoiceState,
CategoryChannel,
VoiceChannel,
TextChannel,
} from 'discord.js';
import { time, ChannelType } from 'discord.js';
import type { VoiceState } from 'discord.js';
import { time } from 'discord.js';
import { createVerificationVoice } from '#utils/verification';
import { maxVCs, leaveBan } from '#utils/verificationConfig';
import {
@ -35,6 +30,13 @@ import {
import { fetchRoles } from '#utils/database/dbExistingUser';
import { fibonacci } from '#utils/maths';
import IDs from '#utils/ids';
import {
isCategoryChannel,
isGuildMember,
isTextChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
import { getCategoryChannel, getGuildMember } from '#utils/fetcher';
export class VerificationLeaveVCListener extends Listener {
public constructor(
@ -63,46 +65,44 @@ export class VerificationLeaveVCListener extends Listener {
const { channel } = oldState;
const { guild } = newState;
if (channel === null || guild === undefined) {
if (!isVoiceChannel(channel) || guild === undefined) {
this.container.logger.error('Verification channel not found');
return;
}
// Get the category
const categoryGuild = guild.channels.cache.get(IDs.categories.verification);
if (categoryGuild === null) {
const category = await getCategoryChannel(IDs.categories.verification);
if (!isCategoryChannel(category)) {
this.container.logger.error('Verification channel not found');
return;
}
const category = categoryGuild as CategoryChannel;
// Get the user that was being verified
const userSnowflake = await getUser(channel.id);
if (userSnowflake === null) {
verifier = true;
}
} else {
// Allow more people to join VC if there are less than 10 VCs
if (!verifier) {
const user = guild.members.cache.get(userSnowflake!);
const member = await getGuildMember(userSnowflake, guild);
// Remove verify as vegan and give non vegan role
if (!(await checkFinish(channel.id)) && user !== undefined) {
if (!(await checkFinish(channel.id)) && isGuildMember(member)) {
// Get roles to give back to the user
const roles = await fetchRoles(user.id);
const roles = await fetchRoles(member.id);
roles.push(IDs.roles.verifyBlock);
await user.roles
await member.roles
.add(roles)
.catch(() =>
this.container.logger.error(
'Verification: User left but bot still tried to add roles',
),
);
// Create timeout block for user
// Counts the recent times they have incomplete verifications
const incompleteCount =
(await countIncomplete(user.id)) % (leaveBan + 1);
(await countIncomplete(member.id)) % (leaveBan + 1);
// Creates the length of the time for the ban
const banLength = fibonacci(incompleteCount) * 3600_000;
@ -110,14 +110,14 @@ export class VerificationLeaveVCListener extends Listener {
{
name: 'verifyUnblock',
payload: {
userId: user.id,
userId: member.id,
guildId: guild.id,
},
},
banLength,
);
await user.user
await member.user
.send(
'You have been timed out as a verifier had not joined for 15 minutes or you disconnected from verification.\n\n' +
`You can verify again at: ${time(
@ -129,8 +129,8 @@ export class VerificationLeaveVCListener extends Listener {
}
// Check how many voice channels there are
const listVoiceChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildVoice,
const listVoiceChannels = category.children.cache.filter((channel) =>
isVoiceChannel(channel),
);
// Check that it is not deleting the 'Verification' channel (in case bot crashes)
@ -142,19 +142,22 @@ export class VerificationLeaveVCListener extends Listener {
// Delete text channel
if (!verifier) {
// Gets a list of all the text channels in the verification category
const listTextChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
const listTextChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
listTextChannels.forEach((c) => {
const textChannel = c as TextChannel;
// Checks if the channel topic has the user's snowflake
if (
textChannel.topic !== null &&
textChannel.topic.includes(userSnowflake!)
) {
textChannel.delete();
for (const c of listTextChannels) {
const channel = c[1];
if (!isTextChannel(channel)) {
continue;
}
// Checks if the channel topic has the user's snowflake
if (channel.topic !== null && channel.topic.includes(userSnowflake!)) {
await channel.delete();
}
}
});
}
// If there are no VCs left in verification after having the channel deleted
@ -168,9 +171,9 @@ export class VerificationLeaveVCListener extends Listener {
return;
}
const verification = listVoiceChannels.last() as VoiceChannel | undefined;
const verification = listVoiceChannels.last();
if (verification === undefined) {
if (!isVoiceChannel(verification)) {
this.container.logger.error(
'Verification: Verification channel not found.',
);

View File

@ -18,15 +18,15 @@
*/
import { Listener } from '@sapphire/framework';
import type {
Client,
CategoryChannel,
TextChannel,
VoiceChannel,
} from 'discord.js';
import { ChannelType } from 'discord.js';
import type { VoiceChannel } from 'discord.js';
import { createVerificationVoice } from '#utils/verification';
import IDs from '#utils/ids';
import { getCategoryChannel } from '#utils/fetcher';
import {
isCategoryChannel,
isTextChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
export class VerificationReady extends Listener {
public constructor(
@ -40,62 +40,67 @@ export class VerificationReady extends Listener {
});
}
public async run(client: Client) {
public async run() {
// Get verification category
let category = client.channels.cache.get(IDs.categories.verification) as
| CategoryChannel
| undefined;
if (category === undefined) {
category = (await client.channels.fetch(IDs.categories.verification)) as
| CategoryChannel
| undefined;
if (category === undefined) {
const category = await getCategoryChannel(IDs.categories.verification);
if (!isCategoryChannel(category)) {
this.container.logger.error('verifyStart: Channel not found');
return;
}
}
// Check how many voice channels there are
const voiceChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildVoice,
const voiceChannels = category.children.cache.filter((channel) =>
isVoiceChannel(channel),
);
const currentVCs: VoiceChannel[] = [];
const emptyVC: string[] = [];
// Delete voice channels
voiceChannels.forEach((c) => {
const voiceChannel = c as VoiceChannel;
if (voiceChannel.members.size === 0) {
emptyVC.push(voiceChannel.id);
voiceChannel.delete();
} else {
currentVCs.push(voiceChannel);
for (const c of voiceChannels) {
const channel = c[1];
if (!isVoiceChannel(channel)) {
continue;
}
if (channel.members.size === 0) {
emptyVC.push(channel.id);
await channel.delete();
} else {
currentVCs.push(channel);
}
}
});
// Delete text channels
const textChannels = category.children.cache.filter(
(c) => c.type === ChannelType.GuildText,
const textChannels = category.children.cache.filter((channel) =>
isTextChannel(channel),
);
textChannels.forEach((c) => {
const textChannel = c as TextChannel;
// Checks if the channel topic has the user's snowflake
emptyVC.forEach((snowflake) => {
if (
textChannel.topic !== null &&
textChannel.topic.includes(snowflake)
) {
textChannel.delete();
for (const c of textChannels) {
const channel = c[1];
if (!isTextChannel(channel)) {
continue;
}
// Checks if the channel topic has the user's snowflake
for (const snowflake in emptyVC) {
if (channel.topic !== null && channel.topic.includes(snowflake)) {
await channel.delete();
}
}
}
});
});
// Check if there is no voice channels, create verification
let verification = false;
currentVCs.forEach((c) => {
if (c.name === 'Verification') {
currentVCs.forEach((channel) => {
if (channel.name === 'Verification') {
verification = true;
}
});
if (!verification) {
await createVerificationVoice(category);
}

View File

@ -21,6 +21,8 @@ import { Listener } from '@sapphire/framework';
import { GuildMember } from 'discord.js';
import IDs from '#utils/ids';
import { noModHistory, userPreviouslyHadRole } from '#utils/database/memberMod';
import { getRole } from '#utils/fetcher';
import { isRole } from '#utils/typeChecking';
/**
* Gives the trusted role to users who have levelled up to level 5
@ -51,9 +53,9 @@ export class TrustedListener extends Listener {
}
const { guild } = member;
const trusted = guild.roles.cache.get(IDs.roles.trusted);
const trusted = await getRole(IDs.roles.trusted, guild);
if (trusted === undefined) {
if (!isRole(trusted)) {
this.container.logger.error(
'TrustedXP Listener: the Trusted role could not be found in the guild.',
);

View File

@ -20,8 +20,9 @@
import { Listener } from '@sapphire/framework';
import { ButtonStyle, ActionRowBuilder, ButtonBuilder } from 'discord.js';
import type { Client, TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class VerificationReady extends Listener {
public constructor(
@ -35,20 +36,14 @@ export class VerificationReady extends Listener {
});
}
public async run(client: Client) {
public async run() {
// Get verification category
let welcome = client.channels.cache.get(IDs.channels.welcome) as
| TextChannel
| undefined;
if (welcome === undefined) {
welcome = (await client.channels.fetch(IDs.channels.welcome)) as
| TextChannel
| undefined;
if (welcome === undefined) {
const welcome = await getTextBasedChannel(IDs.channels.welcome);
if (!isTextBasedChannel(welcome)) {
this.container.logger.error('verifyStart: Welcome not found');
return;
}
}
const botId = this.container.client.id;
const messages = await welcome.messages.fetch();

View File

@ -18,9 +18,9 @@
*/
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class DiversityMonMessageTask extends ScheduledTask {
public constructor(
@ -34,8 +34,6 @@ export class DiversityMonMessageTask extends ScheduledTask {
}
public async run() {
const { client } = container;
const message =
'**📌 Diversity Section Code of Conduct**\n\n' +
'❤️ Be *Kind*\n' +
@ -47,12 +45,16 @@ export class DiversityMonMessageTask extends ScheduledTask {
'❤️ Respect the creativity of others.\n' +
'🧡 Actively seek to include others, especially moderators, in heated discourse for the purpose of de-escalation.';
const lgbtqia = client.channels.cache.get(
IDs.channels.diversity.lgbtqia,
) as TextChannel;
const potgm = client.channels.cache.get(
IDs.channels.diversity.potgm,
) as TextChannel;
const lgbtqia = await getTextBasedChannel(IDs.channels.diversity.lgbtqia);
const potgm = await getTextBasedChannel(IDs.channels.diversity.potgm);
if (!isTextBasedChannel(lgbtqia) || !isTextBasedChannel(potgm)) {
this.container.logger.error(
'Diversity Monday: The bot could not find both of the channels!',
);
return;
}
await lgbtqia.send(message);
await potgm.send(message);

View File

@ -18,9 +18,9 @@
*/
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class DiversityWedMessageTask extends ScheduledTask {
public constructor(
@ -34,8 +34,6 @@ export class DiversityWedMessageTask extends ScheduledTask {
}
public async run() {
const { client } = container;
const message =
'**📌 Diversity Section Code of Conduct**\n\n' +
'❤️ Be *Kind*\n' +
@ -47,12 +45,18 @@ export class DiversityWedMessageTask extends ScheduledTask {
'❤️ Respect the creativity of others.\n' +
'🧡 Actively seek to include others, especially moderators, in heated discourse for the purpose of de-escalation.';
const women = client.channels.cache.get(
IDs.channels.diversity.women,
) as TextChannel;
const disabilities = client.channels.cache.get(
const women = await getTextBasedChannel(IDs.channels.diversity.women);
const disabilities = await getTextBasedChannel(
IDs.channels.diversity.disabilities,
) as TextChannel;
);
if (!isTextBasedChannel(women) || !isTextBasedChannel(disabilities)) {
this.container.logger.error(
'Diversity Wednesday: The bot could not find both of the channels!',
);
return;
}
await women.send(message);
await disabilities.send(message);

View File

@ -18,9 +18,9 @@
*/
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class RestrictedMessageTask extends ScheduledTask {
public constructor(
@ -34,14 +34,20 @@ export class RestrictedMessageTask extends ScheduledTask {
}
public async run() {
const { client } = container;
const restricted = client.channels.cache.get(
const restricted = await getTextBasedChannel(
IDs.channels.restricted.restricted,
) as TextChannel;
const tolerance = client.channels.cache.get(
);
const tolerance = await getTextBasedChannel(
IDs.channels.restricted.tolerance,
) as TextChannel;
);
if (!isTextBasedChannel(restricted) || !isTextBasedChannel(tolerance)) {
this.container.logger.error(
'Restricted Reminder: The bot could not find both of the channels!',
);
return;
}
await restricted.send(this.message(IDs.roles.restrictions.restricted1));
await tolerance.send(this.message(IDs.roles.restrictions.restricted3));

View File

@ -18,9 +18,9 @@
*/
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class StandupTask extends ScheduledTask {
public constructor(
@ -34,11 +34,15 @@ export class StandupTask extends ScheduledTask {
}
public async run() {
const { client } = container;
const channel = await getTextBasedChannel(IDs.channels.staff.coordinators);
const channel = client.channels.cache.get(
IDs.channels.staff.coordinators,
) as TextChannel;
if (!isTextBasedChannel(channel)) {
this.container.logger.error(
'Standup: The bot could not find the channel to post the standup in!',
);
return;
}
await channel.send(`Hiya <@&${IDs.roles.staff.coordinator}> it's time for your weekly standup!
\nPlease submit it in <#${IDs.channels.staff.standup}> :)`);

View File

@ -18,9 +18,9 @@
*/
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class VerifyReminder extends ScheduledTask {
public constructor(
@ -34,8 +34,6 @@ export class VerifyReminder extends ScheduledTask {
}
public async run() {
const { client } = container;
// Get the total messages sent in non-vegan general since last message
const redisKey = 'verifyReminderMessageCounter';
@ -45,9 +43,15 @@ export class VerifyReminder extends ScheduledTask {
if (!messageCount || +messageCount < 100) return;
// Send verification reminder to non-vegan general
const channel = client.channels.cache.get(
IDs.channels.nonVegan.general,
) as TextChannel;
const channel = await getTextBasedChannel(IDs.channels.nonVegan.general);
if (!isTextBasedChannel(channel)) {
this.container.logger.error(
'Verify Reminder: The bot could not find the channel to post the reminder!',
);
return;
}
await channel.send(
"If you want to have the vegan or activist role, you'll need to do a voice verification. " +

View File

@ -25,6 +25,9 @@ import {
checkTempBan,
removeTempBan,
} from '#utils/database/moderation/tempBan';
import { getGuild, getTextBasedChannel, getUser } from '#utils/fetcher';
import { isUser } from '#utils/typeChecking';
import { isTextChannel } from '@sapphire/discord.js-utilities';
export class TempBan extends ScheduledTask {
public constructor(
@ -36,31 +39,25 @@ export class TempBan extends ScheduledTask {
public async run(payload: { userId: string; guildId: string }) {
this.container.logger.debug('Temp Unban Task: Currently running unban');
// Get the guild where the user is in
let guild = this.container.client.guilds.cache.get(payload.guildId);
if (guild === undefined) {
guild = await this.container.client.guilds
.fetch(payload.guildId)
.catch(() => undefined);
const guild = await getGuild(payload.guildId);
if (guild === undefined) {
this.container.logger.error('Temp Unban Task: Guild not found!');
return;
}
}
const { userId } = payload;
let user = guild.client.users.cache.get(userId);
const user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId).catch(() => undefined);
if (user === undefined) {
if (!isUser(user)) {
this.container.logger.error(
'Temp Unban Task: Could not fetch banned user!',
);
return;
}
}
if ((await checkBan(userId)) || !(await checkTempBan(userId))) {
this.container.logger.debug(
@ -75,29 +72,15 @@ export class TempBan extends ScheduledTask {
await removeTempBan(userId);
// Log unban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted);
const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) {
const logChannelFetch = await guild.channels
.fetch(IDs.channels.logs.restricted)
.catch(() => null);
if (logChannelFetch === null) {
if (!isTextChannel(logChannel)) {
this.container.logger.error(
`Temp Ban Listener: Could not fetch log channel. User Snowflake: ${userId}`,
);
return;
}
logChannel = logChannelFetch;
}
if (!logChannel.isTextBased()) {
this.container.logger.error(
'Temp Ban Listener: Log channel is not a text based channel!',
);
return;
}
const log = new EmbedBuilder()
.setColor('#28A745')
.setAuthor({

View File

@ -18,7 +18,11 @@
*/
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { ChannelType } from 'discord.js';
import { getGuildMember, getVoiceBasedChannel } from '#utils/fetcher';
import {
isGuildMember,
isVoiceBasedChannel,
} from '@sapphire/discord.js-utilities';
export class VerifyTimeout extends ScheduledTask {
public constructor(
@ -30,29 +34,17 @@ export class VerifyTimeout extends ScheduledTask {
public async run(payload: { channelId: string; userId: string }) {
// Get the guild where the user is in
let channel = this.container.client.channels.cache.get(payload.channelId);
if (channel === undefined) {
const channelFetch = await this.container.client.channels
.fetch(payload.channelId)
.catch(() => null);
if (channelFetch === null) {
const channel = await getVoiceBasedChannel(payload.channelId);
if (!isVoiceBasedChannel(channel)) {
this.container.logger.error('verifyTimeout: Channel not found!');
return;
}
channel = channelFetch;
}
if (channel.type !== ChannelType.GuildVoice) {
this.container.logger.error(
'verifyTimeout: Channel is not a voice channel!',
);
return;
}
if (channel.members.size < 2 && channel.members.has(payload.userId)) {
const user = channel.members.get(payload.userId);
if (user === undefined) {
const user = await getGuildMember(payload.userId, channel.guild);
if (!isGuildMember(user)) {
this.container.logger.error('verifyTimeout: GuildMember not found!');
return;
}

View File

@ -19,6 +19,8 @@
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import IDs from '#utils/ids';
import { getGuild, getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VerifyUnblock extends ScheduledTask {
public constructor(
@ -30,29 +32,23 @@ export class VerifyUnblock extends ScheduledTask {
public async run(payload: { userId: string; guildId: string }) {
// Get the guild where the user is in
let guild = this.container.client.guilds.cache.get(payload.guildId);
if (guild === undefined) {
guild = await this.container.client.guilds
.fetch(payload.guildId)
.catch(() => undefined);
const guild = await getGuild(payload.guildId);
if (guild === undefined) {
this.container.logger.error('verifyUnblock: Guild not found!');
return;
}
}
// Find GuildMember for the user
let user = guild.members.cache.get(payload.userId);
if (user === undefined) {
user = await guild.members.fetch(payload.userId).catch(() => undefined);
if (user === undefined) {
const member = await getGuildMember(payload.userId, guild);
if (!isGuildMember(member)) {
this.container.logger.error('verifyUnblock: GuildMember not found!');
return;
}
}
// Remove the 'verify block' role
await user.roles.remove(IDs.roles.verifyBlock);
await member.roles.remove(IDs.roles.verifyBlock);
}
}

View File

@ -19,7 +19,8 @@
import type { TextBasedChannel } from 'discord.js';
import IDs from '#utils/ids';
import { ChannelType } from 'discord.js';
import { Nullish } from '@sapphire/utilities';
import { isTextChannel } from '@sapphire/discord.js-utilities';
/**
* Checks if the channel is in the staff category.
@ -27,12 +28,8 @@ import { ChannelType } from 'discord.js';
* @returns {boolean} true if is in staff channel
*/
export function checkStaff(channel: TextBasedChannel | null) {
if (channel === null) {
return false;
}
if (channel.type !== ChannelType.GuildText) {
export function checkStaff(channel: TextBasedChannel | Nullish): boolean {
if (!isTextChannel(channel)) {
return false;
}

245
src/utils/fetcher.ts Normal file
View File

@ -0,0 +1,245 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
Animal Rights Advocates Discord Bot
Copyright (C) 2025 Anthony Berg
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
CategoryChannel,
Guild,
GuildMember,
Role,
Snowflake,
TextBasedChannel,
User,
VoiceBasedChannel,
VoiceChannel,
} from 'discord.js';
import { isRole, isUser } from '#utils/typeChecking';
import { container } from '@sapphire/framework';
import {
isCategoryChannel,
isGuildMember,
isTextBasedChannel,
isVoiceBasedChannel,
isVoiceChannel,
} from '@sapphire/discord.js-utilities';
/**
* Gets a User from their Snowflake.
* Checks the cache first, if it is not in the cache, will fetch from Discord.
* @param userId Snowflake of the user fetch
*/
export async function getUser(userId: Snowflake): Promise<User | undefined> {
// Attempts to get the User from the cache first
let user = container.client.users.cache.get(userId);
// If the user is not in the cache, fetch from Discord
if (!isUser(user)) {
user = await container.client.users.fetch(userId).catch(() => undefined);
}
return user;
}
/**
* Gets the Guild from the Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param guildId the Snowflake of the Guild
*/
export async function getGuild(guildId: Snowflake): Promise<Guild | undefined> {
// Attempts to get the GuildMember from the cache first
let guild = container.client.guilds.cache.get(guildId);
// If the Role is not in the cache, fetch from Discord
if (!(guild instanceof Guild)) {
guild = await container.client.guilds.fetch(guildId).catch(() => undefined);
}
return guild;
}
/**
* Gets the GuildMember from their Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param memberId the Snowflake of the GuildMember
* @param guild the Guild to get the GuildMember from
*/
export async function getGuildMember(
memberId: Snowflake,
guild: Guild,
): Promise<GuildMember | undefined> {
// Attempts to get the GuildMember from the cache first
let member = guild.members.cache.get(memberId);
// If the GuildMember is not in the cache, fetch from Discord
if (!isGuildMember(member)) {
member = await guild.members.fetch(memberId).catch(() => undefined);
}
return member;
}
/**
* Gets the Role from the Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param roleId the Snowflake of the Role
* @param guild the Guild to get the Role from
*/
export async function getRole(
roleId: Snowflake,
guild: Guild,
): Promise<Role | undefined> {
// Attempts to get the Role from the cache first
const role = guild.roles.cache.get(roleId);
// If the Role is not in the cache, fetch from Discord
if (isRole(role)) {
return role;
}
const fetchRole = await guild.roles.fetch(roleId).catch(() => undefined);
if (isRole(fetchRole)) {
return fetchRole;
} else {
return undefined;
}
}
/**
* Gets a TextBasedChannel from a Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param channelId the Snowflake of the TextBasedChannel
*/
export async function getTextBasedChannel(
channelId: Snowflake,
): Promise<TextBasedChannel | undefined> {
// Attempts to get the TextChannel from the cache first
const channel = container.client.channels.cache.get(channelId);
if (channel !== undefined) {
if (channel.isTextBased()) {
return channel;
} else {
return undefined;
}
}
// Fetches the Channel from Discord if the channel is not found in cache
const fetchChannel = await container.client.channels
.fetch(channelId)
.catch(() => undefined);
if (isTextBasedChannel(fetchChannel)) {
return fetchChannel;
} else {
return undefined;
}
}
/**
* Gets a CategoryChannel from a Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param categoryId the Snowflake of the Category
*/
export async function getCategoryChannel(
categoryId: Snowflake,
): Promise<CategoryChannel | undefined> {
// Attempts to get the CategoryChannel from the cache first
const category = container.client.channels.cache.get(categoryId);
if (category !== undefined) {
if (isCategoryChannel(category)) {
return category;
} else {
return undefined;
}
}
// Fetches the Channel from Discord if the channel is not found in cache
const fetchCategory = await container.client.channels
.fetch(categoryId)
.catch(() => undefined);
if (isCategoryChannel(fetchCategory)) {
return fetchCategory;
} else {
return undefined;
}
}
/**
* Gets a VoiceChannel from a Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param vcId the Snowflake of the VoiceChannel
*/
export async function getVoiceChannel(
vcId: Snowflake,
): Promise<VoiceChannel | undefined> {
// Attempts to get the VoiceChannel from the cache first
const vc = container.client.channels.cache.get(vcId);
if (vc !== undefined) {
if (isVoiceChannel(vc)) {
return vc;
} else {
return undefined;
}
}
// Fetches the Channel from Discord if the channel is not found in cache
const fetchVC = await container.client.channels
.fetch(vcId)
.catch(() => undefined);
if (isVoiceChannel(fetchVC)) {
return fetchVC;
} else {
return undefined;
}
}
/**
* Gets a VoiceBasedChannel from a Snowflake.
* Checks if it is in the cache first, if not, attempts to fetch from Discord.
* @param vcId the Snowflake of the VoiceBasedChannel
*/
export async function getVoiceBasedChannel(
vcId: Snowflake,
): Promise<VoiceBasedChannel | undefined> {
// Attempts to get the VoiceBasedChannel from the cache first
const vc = container.client.channels.cache.get(vcId);
if (vc !== undefined) {
if (isVoiceBasedChannel(vc)) {
return vc;
} else {
return undefined;
}
}
// Fetches the Channel from Discord if the channel is not found in cache
const fetchVC = await container.client.channels
.fetch(vcId)
.catch(() => undefined);
if (isVoiceBasedChannel(fetchVC)) {
return fetchVC;
} else {
return undefined;
}
}

37
src/utils/typeChecking.ts Normal file
View File

@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
Animal Rights Advocates Discord Bot
Copyright (C) 2025 Anthony Berg
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Role, User } from 'discord.js';
import { Nullish } from '@sapphire/utilities';
/**
* Checks if a user is a `User`, and that they are not `undefined`/`null`.
* @param user The user to check
*/
export function isUser(user: User | Nullish): user is User {
return user instanceof User;
}
/**
* Checks if the role is a `Role` type, and they are not `undefined`/`null`.
* @param role the role to check
*/
export function isRole(role: Role | Nullish): role is Role {
return role instanceof Role;
}

View File

@ -23,12 +23,16 @@ import {
ChannelType,
GuildMember,
PermissionsBitField,
TextChannel,
time,
User,
} from 'discord.js';
import type { Snowflake, VoiceBasedChannel } from 'discord.js';
import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import {
isDMChannel,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
export async function createVerificationText(
member: GuildMember,
@ -252,12 +256,16 @@ export async function finishVerifyMessages(
// Not vegan
if (!roles.vegan) {
const general = container.client.channels.cache.get(
IDs.channels.nonVegan.general,
) as TextChannel | undefined;
if (general === undefined) {
const general = await getTextBasedChannel(IDs.channels.nonVegan.general);
if (!isTextBasedChannel(general)) {
container.logger.error(
'Verification: Could not find general chat to welcome a non-vegan!',
);
return;
}
let msg =
`${user}, you have been verified! Please check <#${IDs.channels.information.roles}> ` +
`and remember to follow the <#${IDs.channels.information.conduct}> and to respect ongoing discussion and debates.`;
@ -270,10 +278,13 @@ export async function finishVerifyMessages(
}
// Vegan
const general = container.client.channels.cache.get(
IDs.channels.vegan.general,
) as TextChannel | undefined;
if (general === undefined) {
const general = await getTextBasedChannel(IDs.channels.vegan.general);
if (!isTextBasedChannel(general)) {
container.logger.error(
'Verification: Could not find general chat to welcome a vegan!',
);
return;
}
const msg = `Welcome ${user}! Please check out <#${IDs.channels.information.roles}> :)`;
@ -289,14 +300,16 @@ export async function finishVerifyMessages(
'3. Have evidence for claims you make. "I don\'t know" is an acceptable answer. Chances are someone here knows or you can take time to find out\n' +
"4. Don't advocate for baby steps towards veganism. Participation in exploitation can stop today\n" +
'5. Differences in opinion between activists should be resolved in vegan spaces, not in the chat with non-vegans';
await user.send(activistMsg).catch(() => {
const activist = container.client.channels.cache.get(
await user.send(activistMsg).catch(async () => {
const activist = await getTextBasedChannel(
IDs.channels.activism.activism,
) as TextChannel | undefined;
if (activist === undefined) {
);
if (!isDMChannel(activist)) {
return;
}
activist.send(activistMsg);
await activist.send(activistMsg);
});
}
}