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

This commit is contained in:
Anthony Berg 2025-01-19 16:56:07 +01:00
parent db9204c115
commit 132e3cc62b
84 changed files with 1389 additions and 1312 deletions

View File

@ -18,8 +18,10 @@
*/ */
import { Command, RegisterBehavior } from '@sapphire/framework'; import { Command, RegisterBehavior } from '@sapphire/framework';
import { ChannelType, MessageFlagsBitField } from 'discord.js'; import { MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { isRole, isUser } from '#utils/typeChecking';
import { isTextChannel } from '@sapphire/discord.js-utilities';
export class AccessCommand extends Command { export class AccessCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,7 +93,7 @@ export class AccessCommand extends Command {
const role = interaction.options.getRole('role'); const role = interaction.options.getRole('role');
// Checks if all the variables are of the right type // Checks if all the variables are of the right type
if (user === null && role === null) { if (!isUser(user) && !isRole(role)) {
await interaction.reply({ await interaction.reply({
content: 'Error fetching slash command data!', content: 'Error fetching slash command data!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -100,7 +102,7 @@ export class AccessCommand extends Command {
} }
// If user and role is provided, the return an error // If user and role is provided, the return an error
if (user !== null && role !== null) { if (isUser(user) && isRole(role)) {
await interaction.reply({ await interaction.reply({
content: content:
'You have entered a user and a role at the same time! Please only enter one at a time.', 'You have entered a user and a role at the same time! Please only enter one at a time.',
@ -110,10 +112,7 @@ export class AccessCommand extends Command {
} }
// Checks that the channel is a GuildText or GuildVoice, otherwise, return error // Checks that the channel is a GuildText or GuildVoice, otherwise, return error
if ( if (!isTextChannel(channel) && !channel.isVoiceBased()) {
channel.type !== ChannelType.GuildText &&
channel.type !== ChannelType.GuildVoice
) {
await interaction.reply({ await interaction.reply({
content: 'Please only select a text or voice channel!', content: 'Please only select a text or voice channel!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -149,7 +148,7 @@ export class AccessCommand extends Command {
} }
// Set permissions of voice channel // Set permissions of voice channel
if (channel.type === ChannelType.GuildVoice) { if (channel.isVoiceBased()) {
switch (permission) { switch (permission) {
case 'add': case 'add':
await channel.permissionOverwrites.create(permId, { await channel.permissionOverwrites.create(permId, {

View File

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

View File

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

View File

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

View File

@ -22,6 +22,8 @@ import { User, Guild, Message, MessageFlagsBitField } from 'discord.js';
import { updateUser } from '#utils/database/dbExistingUser'; import { updateUser } from '#utils/database/dbExistingUser';
import { getBalance } from '#utils/database/fun/economy'; import { getBalance } from '#utils/database/fun/economy';
import { EmbedBuilder } from 'discord.js'; import { EmbedBuilder } from 'discord.js';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class BalanceCommand extends Command { export class BalanceCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -93,9 +95,9 @@ export class BalanceCommand extends Command {
success: false, 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!'; info.message = 'Could not find your guild member!';
return info; return info;
} }

View File

@ -30,6 +30,8 @@ import { updateUser } from '#utils/database/dbExistingUser';
import { daily, getLastDaily } from '#utils/database/fun/economy'; import { daily, getLastDaily } from '#utils/database/fun/economy';
import { EmbedBuilder } from 'discord.js'; import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class DailyCommand extends Command { export class DailyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -114,9 +116,9 @@ export class DailyCommand extends Command {
return info; 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!'; info.message = 'Could not find your guild member!';
return info; return info;
} }

View File

@ -23,6 +23,8 @@ import { updateUser } from '#utils/database/dbExistingUser';
import { getBalance, transfer } from '#utils/database/fun/economy'; import { getBalance, transfer } from '#utils/database/fun/economy';
import { EmbedBuilder } from 'discord.js'; import { EmbedBuilder } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getGuildMember, getTextBasedChannel } from '#utils/fetcher';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
export class BalanceCommand extends Command { export class BalanceCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -158,15 +160,15 @@ export class BalanceCommand extends Command {
return info; return info;
} }
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const recipientMember = guild.members.cache.get(recipient.id); const recipientMember = await getGuildMember(recipient.id, guild);
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Could not find your guild member!'; info.message = 'Could not find your guild member!';
return info; return info;
} }
if (recipientMember === undefined) { if (!isGuildMember(recipientMember)) {
info.message = 'Could not find the user!'; info.message = 'Could not find the user!';
return info; return info;
} }
@ -200,22 +202,12 @@ export class BalanceCommand extends Command {
info.embeds.push(embed); info.embeds.push(embed);
// Log the payment in the server // Log the payment in the server
let logChannel = guild.channels.cache.get(IDs.channels.logs.economy); const logChannel = await getTextBasedChannel(IDs.channels.logs.economy);
if (logChannel === undefined) { if (!isTextChannel(logChannel)) {
const fetchLogChannel = await guild.channels
.fetch(IDs.channels.logs.economy)
.catch(() => undefined);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error('Pay: Could not fetch log channel'); this.container.logger.error('Pay: Could not fetch log channel');
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Pay: the bot does not have permission to send in the log channel', 'Pay: the bot does not have permission to send in the log channel',
); );

View File

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

View File

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

View File

@ -18,8 +18,9 @@
*/ */
import { Command, RegisterBehavior } from '@sapphire/framework'; import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember, MessageFlagsBitField } from 'discord.js'; import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Happy } from '#utils/gifs'; import { Happy } from '#utils/gifs';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class HappyCommand extends Command { export class HappyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -46,7 +47,7 @@ export class HappyCommand extends Command {
const { member } = interaction; const { member } = interaction;
// Type checks // Type checks
if (!(member instanceof GuildMember)) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: 'Failed to fetch your user on the bot!', content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,

View File

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

View File

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

View File

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

View File

@ -18,8 +18,9 @@
*/ */
import { Command, RegisterBehavior } from '@sapphire/framework'; import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember, MessageFlagsBitField } from 'discord.js'; import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Sad } from '#utils/gifs'; import { Sad } from '#utils/gifs';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class SadCommand extends Command { export class SadCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -46,7 +47,7 @@ export class SadCommand extends Command {
const { member } = interaction; const { member } = interaction;
// Type checks // Type checks
if (!(member instanceof GuildMember)) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: 'Failed to fetch your user on the bot!', content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,

View File

@ -18,8 +18,9 @@
*/ */
import { Command, RegisterBehavior } from '@sapphire/framework'; import { Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, GuildMember, MessageFlagsBitField } from 'discord.js'; import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import { Shrug } from '#utils/gifs'; import { Shrug } from '#utils/gifs';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class ShrugCommand extends Command { export class ShrugCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -46,7 +47,7 @@ export class ShrugCommand extends Command {
const { member } = interaction; const { member } = interaction;
// Type checks // Type checks
if (!(member instanceof GuildMember)) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: 'Failed to fetch your user on the bot!', content: 'Failed to fetch your user on the bot!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,

View File

@ -33,6 +33,12 @@ import {
checkTempBan, checkTempBan,
removeTempBan, removeTempBan,
} from '#utils/database/moderation/tempBan'; } 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 { export class BanCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -150,17 +156,19 @@ export class BanCommand extends Command {
success: false, success: false,
}; };
let user = guild.client.users.cache.get(userId); const user = await getUser(userId);
if (user === undefined) { if (!isUser(user)) {
user = (await guild.client.users.fetch(userId)) as 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 // Gets mod's GuildMember
const mod = guild.members.cache.get(modId); const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null // Checks if guildMember is null
if (mod === undefined) { if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!'; info.message = 'Error fetching mod!';
return info; return info;
} }
@ -174,13 +182,9 @@ export class BanCommand extends Command {
await updateUser(mod); await updateUser(mod);
// Gets guildMember // Gets guildMember
let member = guild.members.cache.get(userId); const member = await getGuildMember(userId, guild);
if (member === undefined) { if (isGuildMember(member)) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
if (member !== undefined) {
// Checks if the user is not restricted // Checks if the user is not restricted
if (member.roles.cache.has(IDs.roles.vegan.vegan)) { if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
info.message = 'You need to restrict the user first!'; info.message = 'You need to restrict the user first!';
@ -214,24 +218,14 @@ export class BanCommand extends Command {
info.success = true; info.success = true;
// Log the ban // Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted); const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) { if (!isTextBasedChannel(logChannel)) {
const fetchLogChannel = await guild.channels.fetch(
IDs.channels.logs.restricted,
);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error('Ban: Could not fetch log channel'); 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`; info.message = `${user} has been banned. This hasn't been logged in a text channel as log channel could not be found`;
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Ban: The bot does not have permission to send in the logs channel!', 'Ban: The bot does not have permission to send in the logs channel!',
); );

View File

@ -24,6 +24,12 @@ import { EmbedBuilder, Message } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { addTempBan, checkTempBan } from '#utils/database/moderation/tempBan'; import { addTempBan, checkTempBan } from '#utils/database/moderation/tempBan';
import { addEmptyUser, updateUser } from '#utils/database/dbExistingUser'; 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 { export class TempBanCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -203,17 +209,19 @@ export class TempBanCommand extends Command {
const banLength = new DurationFormatter().format(time.offset); const banLength = new DurationFormatter().format(time.offset);
let user = guild.client.users.cache.get(userId); const user = await getUser(userId);
if (user === undefined) { if (!isUser(user)) {
user = (await guild.client.users.fetch(userId)) as 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 // Gets mod's GuildMember
const mod = guild.members.cache.get(modId); const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null // Checks if guildMember is null
if (mod === undefined) { if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!'; info.message = 'Error fetching mod!';
return info; return info;
} }
@ -227,13 +235,9 @@ export class TempBanCommand extends Command {
await updateUser(mod); await updateUser(mod);
// Gets guildMember // Gets guildMember
let member = guild.members.cache.get(userId); const member = await getGuildMember(userId, guild);
if (member === undefined) { if (isGuildMember(member)) {
member = await guild.members.fetch(userId).catch(() => undefined);
}
if (member !== undefined) {
// Checks if the user is not restricted // Checks if the user is not restricted
if (member.roles.cache.has(IDs.roles.vegan.vegan)) { if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
info.message = 'You need to restrict the user first!'; info.message = 'You need to restrict the user first!';
@ -275,14 +279,9 @@ export class TempBanCommand extends Command {
info.success = true; info.success = true;
// Log the ban // Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted); const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) { if (!isTextBasedChannel(logChannel)) {
const fetchLogChannel = await guild.channels.fetch(
IDs.channels.logs.restricted,
);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error('Temp Ban: Could not fetch log channel'); this.container.logger.error('Temp Ban: Could not fetch log channel');
info.message = info.message =
@ -290,12 +289,7 @@ export class TempBanCommand extends Command {
"This hasn't been logged in a text channel as log channel could not be found"; "This hasn't been logged in a text channel as log channel could not be found";
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Temp Ban: The bot does not have permission to send in the logs channel!', 'Temp Ban: The bot does not have permission to send in the logs channel!',
); );

View File

@ -34,6 +34,12 @@ import {
removeTempBan, removeTempBan,
} from '#utils/database/moderation/tempBan'; } from '#utils/database/moderation/tempBan';
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser'; 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 { export class UnbanCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -123,10 +129,10 @@ export class UnbanCommand extends Command {
}; };
// Gets mod's GuildMember // Gets mod's GuildMember
const mod = guild.members.cache.get(modId); const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null // Checks if guildMember is null
if (mod === undefined) { if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!'; info.message = 'Error fetching mod!';
return info; return info;
} }
@ -134,15 +140,12 @@ export class UnbanCommand extends Command {
// Check if mod is in database // Check if mod is in database
await addExistingUser(mod); 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) { if (user === undefined) {
info.message = 'Could not fetch the user!'; info.message = 'Could not fetch the user!';
return info; return info;
} }
}
let dbBan = await checkBan(userId); let dbBan = await checkBan(userId);
const dbTempBan = await checkTempBan(userId); const dbTempBan = await checkTempBan(userId);
@ -161,7 +164,7 @@ export class UnbanCommand extends Command {
} }
let { reason } = ban; let { reason } = ban;
if (reason === null || reason === undefined) { if (isNullish(reason)) {
reason = ''; reason = '';
} }
@ -191,23 +194,14 @@ export class UnbanCommand extends Command {
info.success = true; info.success = true;
// Log unban // Log unban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted); let logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) { if (!isTextBasedChannel(logChannel)) {
const fetchLogChannel = await guild.channels.fetch(
IDs.channels.logs.restricted,
);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error('Unban Error: Could not fetch log channel'); 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`; info.message = `${user} has been unbanned. This hasn't been logged in a text channel as log channel could not be found`;
return info; return info;
} else {
logChannel = fetchLogChannel;
} }
}
if (!logChannel.isSendable()) { if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Unban: The bot does not have permission to send in the logs channel!', 'Unban: The bot does not have permission to send in the logs channel!',

View File

@ -22,14 +22,20 @@
import { Args, container, RegisterBehavior } from '@sapphire/framework'; import { Args, container, RegisterBehavior } from '@sapphire/framework';
import { Subcommand } from '@sapphire/plugin-subcommands'; import { Subcommand } from '@sapphire/plugin-subcommands';
import { import {
ChannelType,
GuildMember, GuildMember,
Message, Message,
MessageFlagsBitField, MessageFlagsBitField,
PermissionsBitField, PermissionsBitField,
} from 'discord.js'; } from 'discord.js';
import type { TextChannel, Snowflake } from 'discord.js'; import type { Snowflake } from 'discord.js';
import IDs from '#utils/ids'; 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 { export class DiversityCommand extends Subcommand {
public constructor( public constructor(
@ -90,30 +96,11 @@ export class DiversityCommand extends Subcommand {
// Command run // Command run
public async toggleOpen(interaction: Subcommand.ChatInputCommandInteraction) { public async toggleOpen(interaction: Subcommand.ChatInputCommandInteraction) {
// Check if guild is not null
if (interaction.guild === null) {
await interaction.reply({
content: 'Guild not found!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Get the channel // Get the channel
const channel = interaction.guild.channels.cache.get(interaction.channelId); const channel = await getTextBasedChannel(interaction.channelId);
// Check if channel is not undefined
if (channel === undefined) {
await interaction.reply({
content: 'Channel not found!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Check if channel is text // Check if channel is text
if (channel.type !== ChannelType.GuildText) { if (!isTextChannel(channel)) {
await interaction.reply({ await interaction.reply({
content: 'Channel is not a text channel!', content: 'Channel is not a text channel!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -122,9 +109,6 @@ export class DiversityCommand extends Subcommand {
return; return;
} }
// Converts GuildBasedChannel to TextChannel
const channelText = channel as TextChannel;
// Check if the command was run in the diversity section // Check if the command was run in the diversity section
if (channel.parentId !== IDs.categories.diversity) { if (channel.parentId !== IDs.categories.diversity) {
await interaction.reply({ await interaction.reply({
@ -141,7 +125,7 @@ export class DiversityCommand extends Subcommand {
.has([PermissionsBitField.Flags.SendMessages]); .has([PermissionsBitField.Flags.SendMessages]);
// Toggle send message in channel // Toggle send message in channel
await channelText.permissionOverwrites.edit(IDs.roles.vegan.vegan, { await channel.permissionOverwrites.edit(IDs.roles.vegan.vegan, {
SendMessages: !open, SendMessages: !open,
}); });
@ -156,28 +140,46 @@ export class DiversityCommand extends Subcommand {
) { ) {
// TODO add database updates // TODO add database updates
// Get the arguments // Get the arguments
const user = interaction.options.getUser('user'); const user = interaction.options.getUser('user', true);
const mod = interaction.member; const mod = interaction.member;
const { guild } = interaction; const { guild } = interaction;
// Checks if all the variables are of the right type // Checks if all the variables are of the right type
if (user === null || guild === null || mod === null) { if (guild === null) {
await interaction.reply({ await interaction.reply({
content: 'Error fetching user!', content: 'Error fetching the guild!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true, withResponse: true,
}); });
return; return;
} }
// Gets guildMember whilst removing the ability of each other variables being null if (!isGuildMember(mod)) {
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) {
await interaction.reply({ await interaction.reply({
content: 'Error fetching user!', 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, flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true, withResponse: true,
}); });
@ -185,10 +187,10 @@ export class DiversityCommand extends Subcommand {
} }
// Checks if the user has Diversity and to give them or remove them based on if they have it // 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 // Remove the Diversity role from the user
await guildMember.roles.remove(diversity); await member.roles.remove(diversity);
await this.threadManager(guildMember.id, false); await this.threadManager(member.id, false);
await interaction.reply({ await interaction.reply({
content: `Removed the ${diversity.name} role from ${user}`, content: `Removed the ${diversity.name} role from ${user}`,
withResponse: true, withResponse: true,
@ -196,8 +198,8 @@ export class DiversityCommand extends Subcommand {
return; return;
} }
// Add Diversity Team role to the user // Add Diversity Team role to the user
await guildMember.roles.add(diversity); await member.roles.add(diversity);
await this.threadManager(guildMember.id, true); await this.threadManager(member.id, true);
await interaction.reply({ await interaction.reply({
content: `Gave ${user} the ${diversity.name} role!`, content: `Gave ${user} the ${diversity.name} role!`,
withResponse: true, withResponse: true,
@ -220,7 +222,7 @@ export class DiversityCommand extends Subcommand {
const mod = message.member; const mod = message.member;
if (mod === null) { if (!isGuildMember(mod)) {
await message.react('❌'); await message.react('❌');
await message.reply( await message.reply(
'Diversity coordinator not found! Try again or contact a developer!', 'Diversity coordinator not found! Try again or contact a developer!',
@ -236,9 +238,9 @@ export class DiversityCommand extends Subcommand {
return; 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.react('❌');
await message.reply('Role not found! Try again or contact a developer!'); await message.reply('Role not found! Try again or contact a developer!');
return; return;
@ -271,11 +273,8 @@ export class DiversityCommand extends Subcommand {
const thread = await container.client.channels.fetch( const thread = await container.client.channels.fetch(
IDs.channels.diversity.diversity, IDs.channels.diversity.diversity,
); );
if (thread === null) {
return;
}
if (!thread.isThread()) { if (!isThreadChannel(thread)) {
return; return;
} }

View File

@ -23,6 +23,11 @@
import { Args, Command, RegisterBehavior } from '@sapphire/framework'; import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Message, MessageFlagsBitField } from 'discord.js'; import { Message, MessageFlagsBitField } from 'discord.js';
import { ChannelType } 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 { export class MoveAllCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -83,40 +88,31 @@ export class MoveAllCommand extends Command {
return; return;
} }
if (member === null) { if (!isGuildMember(member)) {
await interaction.editReply({ await interaction.editReply({
content: 'Error fetching your user', content: 'Error fetching your user',
}); });
return; return;
} }
const mod = guild.members.cache.get(member.user.id); if (member.voice.channelId === null) {
if (mod === undefined) {
await interaction.editReply({
content: 'Error fetching user from guild',
});
return;
}
if (mod.voice.channelId === null) {
await interaction.editReply({ await interaction.editReply({
content: 'You need to be in a voice channel to run this command!', content: 'You need to be in a voice channel to run this command!',
}); });
return; 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({ await interaction.editReply({
content: 'Error fetching your current voice channel!', content: 'Error fetching your current voice channel!',
}); });
return; return;
} }
voice.members.forEach((memberVC) => { voice.members.forEach((vcMember) => {
memberVC.voice.setChannel(channel.id); vcMember.voice.setChannel(channel.id);
}); });
await interaction.editReply({ await interaction.editReply({
@ -137,7 +133,7 @@ export class MoveAllCommand extends Command {
const mod = message.member; const mod = message.member;
const { guild } = message; const { guild } = message;
if (mod === null) { if (!isGuildMember(mod)) {
await message.react('❌'); await message.react('❌');
await message.reply('Could not find your user!'); await message.reply('Could not find your user!');
return; return;
@ -157,9 +153,9 @@ export class MoveAllCommand extends Command {
return; 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.react('❌');
await message.reply('Could not fetch current voice channel!'); await message.reply('Could not fetch current voice channel!');
return; return;

View File

@ -19,6 +19,8 @@
import { Args, Command, RegisterBehavior } from '@sapphire/framework'; import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { GuildMember, Message, MessageFlagsBitField } 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 { export class RenameUserCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -75,10 +77,10 @@ export class RenameUserCommand extends Command {
} }
// Gets guildMember whilst removing the ability of each other variables being null // 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 // Checks if guildMember is null
if (member === undefined) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: 'Error fetching user!', content: 'Error fetching user!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,

View File

@ -40,6 +40,11 @@ import {
import { restrict, checkActive } from '#utils/database/moderation/restriction'; import { restrict, checkActive } from '#utils/database/moderation/restriction';
import { randint } from '#utils/maths'; import { randint } from '#utils/maths';
import { blockedRolesAfterRestricted } from '#utils/blockedRoles'; import { blockedRolesAfterRestricted } from '#utils/blockedRoles';
import { getGuildMember, getTextBasedChannel, getUser } from '#utils/fetcher';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
export async function restrictRun( export async function restrictRun(
userId: Snowflake, userId: Snowflake,
@ -53,21 +58,18 @@ export async function restrictRun(
success: false, 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).catch(() => undefined);
if (user === undefined) { if (user === undefined) {
info.message = 'Error fetching user'; info.message = 'Error fetching user';
return info; return info;
} }
}
// Gets mod's GuildMember // Gets mod's GuildMember
const mod = guild.members.cache.get(modId); const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null // Checks if guildMember is null
if (mod === undefined) { if (!isGuildMember(mod)) {
info.message = 'Error fetching mod'; info.message = 'Error fetching mod';
return info; return info;
} }
@ -81,17 +83,13 @@ export async function restrictRun(
} }
// Gets guildMember // 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);
}
const restrictRoles = IDs.roles.restrictions.restricted; const restrictRoles = IDs.roles.restrictions.restricted;
let section = tolerance ? randint(3, 4) : randint(1, 2); let section = tolerance ? randint(3, 4) : randint(1, 2);
if (member !== undefined) { if (isGuildMember(member)) {
// Checks if the user is not restricted // Checks if the user is not restricted
if (member.roles.cache.hasAny(...restrictRoles)) { if (member.roles.cache.hasAny(...restrictRoles)) {
info.message = `${member} is already restricted!`; info.message = `${member} is already restricted!`;
@ -219,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(); await member.voice.disconnect();
} }
@ -243,23 +241,14 @@ export async function restrictRun(
await user.send({ embeds: [dmEmbed] }).catch(() => {}); await user.send({ embeds: [dmEmbed] }).catch(() => {});
// Log the ban // Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted); const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) { if (!isTextBasedChannel(logChannel)) {
const fetchLogChannel = await guild.channels.fetch(
IDs.channels.logs.restricted,
);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
container.logger.error('Restrict: Could not fetch log channel'); 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.`; info.message = `Restricted ${user} but could not find the log channel. This has been logged to the database.`;
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
container.logger.error( container.logger.error(
'Restrict: The bot does not have permission to send in the logs channel!', 'Restrict: The bot does not have permission to send in the logs channel!',
); );

View File

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

View File

@ -19,9 +19,15 @@
import { RegisterBehavior } from '@sapphire/framework'; import { RegisterBehavior } from '@sapphire/framework';
import { Subcommand } from '@sapphire/plugin-subcommands'; import { Subcommand } from '@sapphire/plugin-subcommands';
import { MessageFlagsBitField, TextChannel } from 'discord.js'; import { MessageFlagsBitField } from 'discord.js';
import { CategoryChannel, ChannelType } from 'discord.js';
import IDs from '#utils/ids'; 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 { export class RestrictToolsCommand extends Subcommand {
public constructor( public constructor(
@ -92,8 +98,8 @@ export class RestrictToolsCommand extends Subcommand {
let topic: string[]; let topic: string[];
if (user === null) { if (!isUser(user)) {
if (channel.type !== ChannelType.GuildText) { if (!isTextChannel(channel)) {
await interaction.editReply({ await interaction.editReply({
content: content:
'Please make sure you ran this command in the original restricted text channel!', 'Please make sure you ran this command in the original restricted text channel!',
@ -132,10 +138,10 @@ export class RestrictToolsCommand extends Subcommand {
await channel.delete(); await channel.delete();
const vcId = topic[3]; const vcId = topic[3];
const voiceChannel = guild.channels.cache.get(vcId); const voiceChannel = await getVoiceChannel(vcId);
if ( if (
voiceChannel !== undefined && isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.restricted voiceChannel.parentId === IDs.categories.restricted
) { ) {
await voiceChannel.delete(); await voiceChannel.delete();
@ -144,55 +150,45 @@ export class RestrictToolsCommand extends Subcommand {
return; return;
} }
const category = guild.channels.cache.get(IDs.categories.restricted); const category = await getCategoryChannel(IDs.categories.restricted);
if (!(category instanceof CategoryChannel)) { if (!isCategoryChannel(category)) {
await interaction.editReply({ await interaction.editReply({
content: 'Could not find category!', content: 'Could not find category!',
}); });
return; return;
} }
const textChannels = category.children.cache.filter( const textChannels = category.children.cache.filter((channel) =>
(c) => c.type === ChannelType.GuildText, isTextChannel(channel),
); );
for (const channel of textChannels) { for (const c of textChannels) {
const textChannel = channel[1]; const channel = c[1];
// Checks that the channel is a text channel // Checks that the channel is a text channel
if (!(textChannel instanceof TextChannel)) { if (!isTextChannel(channel)) {
continue; continue;
} }
// Checks that the channel has a topic // Checks that the channel has a topic
if (textChannel.topic === null) { if (channel.topic === null) {
continue; continue;
} }
// Checks if the channel topic has the user's snowflake // Checks if the channel topic has the user's snowflake
if (textChannel.topic.includes(user.id)) { if (channel.topic.includes(user.id)) {
topic = textChannel.topic.split(' '); topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(user.id) + 1]; const vcId = topic[topic.indexOf(user.id) + 1];
let voiceChannel = guild.channels.cache.get(vcId); const voiceChannel = await getVoiceChannel(vcId);
if (voiceChannel === undefined) {
const fetchVoiceChannel = await guild.channels
.fetch(vcId)
.catch(() => undefined);
if (fetchVoiceChannel !== null && fetchVoiceChannel !== undefined) {
voiceChannel = fetchVoiceChannel;
}
}
if ( if (
voiceChannel !== undefined && isVoiceChannel(voiceChannel) &&
voiceChannel.parentId === IDs.categories.restricted voiceChannel.parentId === IDs.categories.restricted
) { ) {
await voiceChannel.delete(); await voiceChannel.delete();
} }
await textChannel.delete(); await channel.delete();
} }
} }

View File

@ -19,13 +19,7 @@
import { Args, Command, RegisterBehavior } from '@sapphire/framework'; import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import type { Guild, Message, Snowflake, User } from 'discord.js'; import type { Guild, Message, Snowflake, User } from 'discord.js';
import { import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
CategoryChannel,
ChannelType,
EmbedBuilder,
MessageFlagsBitField,
TextChannel,
} from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { addExistingUser, fetchRoles } from '#utils/database/dbExistingUser'; import { addExistingUser, fetchRoles } from '#utils/database/dbExistingUser';
import { import {
@ -33,6 +27,21 @@ import {
unRestrict, unRestrict,
unRestrictLegacy, unRestrictLegacy,
} from '#utils/database/moderation/restriction'; } 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 { export class UnRestrictCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -138,22 +147,18 @@ export class UnRestrictCommand extends Command {
runInVeganRestrict: false, runInVeganRestrict: false,
}; };
let user = guild.client.users.cache.get(userId); const user = await getUser(userId);
if (user === undefined) { if (!isUser(user)) {
user = await guild.client.users.fetch(userId).catch(() => undefined);
if (user === undefined) {
info.message = 'Error fetching user'; info.message = 'Error fetching user';
return info; return info;
} }
}
// Gets mod's GuildMember // Gets mod's GuildMember
const mod = guild.members.cache.get(modId); const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null // Checks if guildMember is null
if (mod === undefined) { if (!isGuildMember(mod)) {
info.message = 'Error fetching mod'; info.message = 'Error fetching mod';
return info; return info;
} }
@ -162,17 +167,12 @@ export class UnRestrictCommand extends Command {
await addExistingUser(mod); await addExistingUser(mod);
// Gets guildMember // Gets guildMember
let member = guild.members.cache.get(userId); const member = await getGuildMember(userId, guild);
if (member === undefined) { if (!isGuildMember(member)) {
member = await guild.members.fetch(userId).catch(() => undefined); info.message = "Can't unrestrict the user as they are not on this server";
if (member === undefined) {
info.message =
"Can't unrestrict the user as they are not on this server";
return info; return info;
} }
}
// Check if user is in database // Check if user is in database
await addExistingUser(member); await addExistingUser(member);
@ -210,9 +210,9 @@ export class UnRestrictCommand extends Command {
// Remove vegan restrict channels // Remove vegan restrict channels
if (member.roles.cache.has(IDs.roles.vegan.vegan)) { if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
const category = guild.channels.cache.get(IDs.categories.restricted); const category = await getCategoryChannel(IDs.categories.restricted);
if (!(category instanceof CategoryChannel)) { if (!isCategoryChannel(category)) {
info.message = info.message =
'Could not find the restricted category! The channels will have to be deleted manually.'; 'Could not find the restricted category! The channels will have to be deleted manually.';
return info; return info;
@ -220,52 +220,42 @@ export class UnRestrictCommand extends Command {
let topic: string[]; let topic: string[];
const textChannels = category.children.cache.filter( const textChannels = category.children.cache.filter((channel) =>
(c) => c.type === ChannelType.GuildText, isTextChannel(channel),
); );
for (const channel of textChannels) { for (const c of textChannels) {
const textChannel = channel[1]; const channel = c[1];
// Checks that the channel is a text channel // Checks that the channel is a text channel
if (!(textChannel instanceof TextChannel)) { if (!isTextChannel(channel)) {
continue; continue;
} }
// Checks that the channel has a topic // Checks that the channel has a topic
if (textChannel.topic === null) { if (channel.topic === null) {
continue; continue;
} }
// Checks if the channel topic has the user's snowflake // Checks if the channel topic has the user's snowflake
if (textChannel.topic.includes(userId)) { if (channel.topic.includes(userId)) {
if (textChannel.id === channelRun) { if (channel.id === channelRun) {
info.runInVeganRestrict = true; info.runInVeganRestrict = true;
} }
topic = textChannel.topic.split(' '); topic = channel.topic.split(' ');
const vcId = topic[topic.indexOf(user.id) + 1]; const vcId = topic[topic.indexOf(user.id) + 1];
let voiceChannel = guild.channels.cache.get(vcId); const voiceChannel = await getVoiceChannel(vcId);
if (voiceChannel === undefined) {
const fetchVoiceChannel = await guild.channels
.fetch(vcId)
.catch(() => undefined);
if (fetchVoiceChannel !== null && fetchVoiceChannel !== undefined) {
voiceChannel = fetchVoiceChannel;
}
}
if ( if (
voiceChannel !== undefined && isVoiceChannel(voiceChannel) &&
// Used for sanitising the channel topic, so another voice channel does not get deleted // Used for sanitising the channel topic, so another voice channel does not get deleted
voiceChannel.parentId === IDs.categories.restricted voiceChannel.parentId === IDs.categories.restricted
) { ) {
await voiceChannel.delete(); await voiceChannel.delete();
} }
await textChannel.delete(); await channel.delete();
} }
} }
} }
@ -273,23 +263,14 @@ export class UnRestrictCommand extends Command {
info.success = true; info.success = true;
// Log the ban // Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted); const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) { if (!isTextBasedChannel(logChannel)) {
const fetchLogChannel = await guild.channels.fetch(
IDs.channels.logs.restricted,
);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error('Unrestrict: Could not fetch log channel'); 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.`; info.message = `Unrestricted ${user} but could not find the log channel. This has been logged to the database.`;
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Unrestrict: The bot does not have permission to send in the logs channel!', 'Unrestrict: The bot does not have permission to send in the logs channel!',
); );

View File

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

View File

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

View File

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

View File

@ -25,6 +25,8 @@ import {
checkActive, checkActive,
} from '#utils/database/moderation/vcMute'; } from '#utils/database/moderation/vcMute';
import { addExistingUser } from '#utils/database/dbExistingUser'; import { addExistingUser } from '#utils/database/dbExistingUser';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VCMuteCommand extends Command { export class VCMuteCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -66,7 +68,7 @@ export class VCMuteCommand extends Command {
// Get the arguments // Get the arguments
const user = interaction.options.getUser('user', true); const user = interaction.options.getUser('user', true);
const reason = interaction.options.getString('reason'); const reason = interaction.options.getString('reason');
const modUser = interaction.user; const mod = interaction.member;
const { guild } = interaction; const { guild } = interaction;
// Checks if all the variables are of the right type // Checks if all the variables are of the right type
@ -80,11 +82,10 @@ export class VCMuteCommand extends Command {
} }
// Gets guildMember whilst removing the ability of each other variables being null // 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);
const mod = guild.members.cache.get(modUser.id);
// Checks if guildMember is null // Checks if `member` was found
if (member === undefined || mod === undefined) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: 'Error fetching user!', content: 'Error fetching user!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -93,6 +94,16 @@ export class VCMuteCommand extends Command {
return; return;
} }
// Checks if `mod` was found
if (!isGuildMember(mod)) {
await interaction.reply({
content: 'Error fetching your user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
// Check if removing VC Mute // Check if removing VC Mute
if (await checkActive(member.id)) { if (await checkActive(member.id)) {
await removeMute(member.id); await removeMute(member.id);
@ -137,7 +148,7 @@ export class VCMuteCommand extends Command {
const reason = args.finished ? null : await args.rest('string'); const reason = args.finished ? null : await args.rest('string');
const mod = message.member; const mod = message.member;
if (mod === null) { if (!isGuildMember(mod)) {
await message.react('❌'); await message.react('❌');
await message.reply( await message.reply(
'Moderator not found! Try again or contact a developer!', 'Moderator not found! Try again or contact a developer!',

View File

@ -19,13 +19,16 @@
import { Args, Command, RegisterBehavior } from '@sapphire/framework'; import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { EmbedBuilder, MessageFlagsBitField } from 'discord.js'; import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import type { Message, Guild, User } from 'discord.js'; import type { Message, User } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { import {
deleteWarning, deleteWarning,
fetchWarning, fetchWarning,
} from '#utils/database/moderation/warnings'; } from '#utils/database/moderation/warnings';
import { checkStaff } from '#utils/checker'; 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 { export class DeleteWarningCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -62,17 +65,6 @@ export class DeleteWarningCommand extends Command {
// Get the arguments // Get the arguments
const warningId = interaction.options.getInteger('id', true); const warningId = interaction.options.getInteger('id', true);
const mod = interaction.user; 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!',
flags: MessageFlagsBitField.Flags.Ephemeral,
withResponse: true,
});
return;
}
const staffChannel = checkStaff(interaction.channel); const staffChannel = checkStaff(interaction.channel);
@ -80,7 +72,7 @@ export class DeleteWarningCommand extends Command {
flags: staffChannel ? undefined : MessageFlagsBitField.Flags.Ephemeral, flags: staffChannel ? undefined : MessageFlagsBitField.Flags.Ephemeral,
}); });
const info = await this.deleteWarning(warningId, mod, guild); const info = await this.deleteWarning(warningId, mod);
await interaction.editReply({ await interaction.editReply({
content: info.message, content: info.message,
@ -110,7 +102,7 @@ export class DeleteWarningCommand extends Command {
return; 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 }); await message.reply({ content: info.message, embeds: info.embeds });
if (!info.success) { if (!info.success) {
@ -118,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 = { const info = {
message: '', message: '',
embeds: [] as EmbedBuilder[], embeds: [] as EmbedBuilder[],
@ -136,24 +128,17 @@ export class DeleteWarningCommand extends Command {
info.success = true; info.success = true;
const userId = warning.userId; const userId = warning.userId;
let user = guild.client.users.cache.get(userId); const user = await getUser(userId);
if (user === undefined) { if (!isUser(user)) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
info.message = `Deleted warning ID \`${warningId}\`, but the user could not be found!`; info.message = `Deleted warning ID \`${warningId}\`, but the user could not be found!`;
return info; return info;
} }
}
// Log the warnings deletion // Log the warnings deletion
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus); const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) { if (!isTextChannel(logChannel)) {
const fetchLogChannel = await guild.channels
.fetch(IDs.channels.logs.sus)
.catch(() => undefined);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error( this.container.logger.error(
'Delete Warning: Could not fetch log channel', 'Delete Warning: Could not fetch log channel',
); );
@ -162,12 +147,7 @@ export class DeleteWarningCommand extends Command {
'could not find the log channel.'; 'could not find the log channel.';
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Delete Warning: The bot does not have permission to send in the logs channel!', 'Delete Warning: The bot does not have permission to send in the logs channel!',
); );

View File

@ -29,6 +29,9 @@ import {
import { updateUser } from '#utils/database/dbExistingUser'; import { updateUser } from '#utils/database/dbExistingUser';
import { addWarn } from '#utils/database/moderation/warnings'; import { addWarn } from '#utils/database/moderation/warnings';
import IDs from '#utils/ids'; 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 { export class WarnCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -104,7 +107,7 @@ export class WarnCommand extends Command {
return; return;
} }
const reason = args.finished ? null : await args.rest('string'); const reason = args.finished ? null : await args.rest('string');
const mod = message.member; const mod = message.author;
if (reason === null) { if (reason === null) {
await message.react('❌'); await message.react('❌');
@ -112,14 +115,6 @@ export class WarnCommand extends Command {
return; return;
} }
if (mod === null) {
await message.react('❌');
await message.reply(
'Moderator not found! Try again or contact a developer!',
);
return;
}
const { guild } = message; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -150,10 +145,10 @@ export class WarnCommand extends Command {
}; };
// Gets mod's GuildMember // Gets mod's GuildMember
const mod = guild.members.cache.get(modId); const mod = await getGuildMember(modId, guild);
// Checks if guildMember is null // Checks if guildMember is null
if (mod === undefined) { if (!isGuildMember(mod)) {
info.message = 'Error fetching mod!'; info.message = 'Error fetching mod!';
return info; return info;
} }
@ -162,15 +157,12 @@ export class WarnCommand extends Command {
await updateUser(mod); await updateUser(mod);
// Gets User for person being restricted // Gets User for person being restricted
let user = guild.client.users.cache.get(userId); const user = await getUser(userId);
if (user === undefined) { if (!isUser(user)) {
user = await guild.client.users.fetch(userId);
if (user === undefined) {
info.message = 'Error fetching user'; info.message = 'Error fetching user';
return info; return info;
} }
}
await addWarn(userId, modId, reason); await addWarn(userId, modId, reason);
@ -191,24 +183,14 @@ export class WarnCommand extends Command {
await user.send({ embeds: [dmEmbed] }).catch(() => {}); await user.send({ embeds: [dmEmbed] }).catch(() => {});
// Log the ban // Log the ban
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus); const logChannel = await getTextBasedChannel(IDs.channels.logs.sus);
if (logChannel === undefined) { if (!isTextChannel(logChannel)) {
const fetchLogChannel = await guild.channels
.fetch(IDs.channels.logs.sus)
.catch(() => undefined);
if (fetchLogChannel === null || fetchLogChannel === undefined) {
this.container.logger.error('Warn: Could not fetch log channel'); 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.`; info.message = `Warned ${user} but could not find the log channel. This has been logged to the database.`;
return info; return info;
} else { } else if (!logChannel.isSendable()) {
logChannel = fetchLogChannel;
}
}
if (!logChannel.isSendable()) {
this.container.logger.error( this.container.logger.error(
'Warn: The bot does not have permission to send in the logs channel!', 'Warn: The bot does not have permission to send in the logs channel!',
); );

View File

@ -18,12 +18,15 @@
*/ */
import { Args, Command, RegisterBehavior } from '@sapphire/framework'; import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { ChannelType, EmbedBuilder, MessageFlagsBitField } from 'discord.js'; import { EmbedBuilder, MessageFlagsBitField } from 'discord.js';
import type { Message, Guild, User } from 'discord.js'; import type { Message, Guild, User } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { fetchWarnings } from '#utils/database/moderation/warnings'; import { fetchWarnings } from '#utils/database/moderation/warnings';
import { checkStaff } from '#utils/checker'; import { checkStaff } from '#utils/checker';
import { createWarningsEmbed } from '#utils/embeds'; 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 { export class WarningsCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -103,10 +106,10 @@ export class WarningsCommand extends Command {
return; return;
} }
if (user === undefined) { if (!isUser(user)) {
const { channel } = message; const { channel } = message;
if (channel.type !== ChannelType.GuildText) { if (!isTextChannel(channel)) {
await message.react('❌'); await message.react('❌');
await message.reply('User was not provided!'); await message.reply('User was not provided!');
return; return;
@ -121,18 +124,16 @@ export class WarningsCommand extends Command {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
const userId = topic[2]; const userId = topic[2];
user = guild.client.users.cache.get(userId); user = await getUser(userId);
if (user === undefined) {
user = await guild.client.users.fetch(userId);
}
} }
} }
} }
if (user === undefined) { if (!isUser(user)) {
await message.react('❌'); 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; return;
} }

View File

@ -41,6 +41,11 @@ import {
} from '#utils/database/outreach'; } from '#utils/database/outreach';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { EmbedBuilder } from 'discord.js'; import { EmbedBuilder } from 'discord.js';
import {
isGuildMember,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
import { getGuildMember, getTextBasedChannel } from '#utils/fetcher';
export class OutreachCommand extends Subcommand { export class OutreachCommand extends Subcommand {
public constructor( public constructor(
@ -189,7 +194,7 @@ export class OutreachCommand extends Subcommand {
interaction: Subcommand.ChatInputCommandInteraction, interaction: Subcommand.ChatInputCommandInteraction,
) { ) {
// const start = interaction.options.getBoolean('start'); // const start = interaction.options.getBoolean('start');
const modUser = interaction.user; const mod = interaction.member;
const { guild } = interaction; const { guild } = interaction;
if (guild === null) { if (guild === null) {
@ -200,9 +205,7 @@ export class OutreachCommand extends Subcommand {
return; return;
} }
const mod = guild.members.cache.get(modUser.id); if (!isGuildMember(mod)) {
if (mod === undefined) {
await interaction.reply({ await interaction.reply({
content: 'Outreach Leader was not found!', content: 'Outreach Leader was not found!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -228,7 +231,7 @@ export class OutreachCommand extends Subcommand {
await updateUser(mod); await updateUser(mod);
await createEvent(modUser.id); await createEvent(mod.id);
await interaction.reply({ await interaction.reply({
content: 'Created the event!', content: 'Created the event!',
@ -237,7 +240,7 @@ export class OutreachCommand extends Subcommand {
} }
public async eventEnd(interaction: Subcommand.ChatInputCommandInteraction) { public async eventEnd(interaction: Subcommand.ChatInputCommandInteraction) {
const modUser = interaction.user; const mod = interaction.member;
const { guild } = interaction; const { guild } = interaction;
if (guild === null) { if (guild === null) {
@ -248,9 +251,7 @@ export class OutreachCommand extends Subcommand {
return; return;
} }
const mod = guild.members.cache.get(modUser.id); if (!isGuildMember(mod)) {
if (mod === undefined) {
await interaction.reply({ await interaction.reply({
content: 'Your guild member was not found!', content: 'Your guild member was not found!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -306,9 +307,9 @@ export class OutreachCommand extends Subcommand {
educated += group.educated; 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( await interaction.editReply(
'Event has now ended, but could not post statistics!', 'Event has now ended, but could not post statistics!',
); );
@ -386,9 +387,9 @@ export class OutreachCommand extends Subcommand {
const statGroups = await getStatGroups(event.id); const statGroups = await getStatGroups(event.id);
const groupNo = statGroups.length + 1; 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({ await interaction.editReply({
content: `Could not find ${leader}'s guild member.`, content: `Could not find ${leader}'s guild member.`,
}); });
@ -465,7 +466,7 @@ export class OutreachCommand extends Subcommand {
public async groupAdd(interaction: Subcommand.ChatInputCommandInteraction) { public async groupAdd(interaction: Subcommand.ChatInputCommandInteraction) {
const user = interaction.options.getUser('user', true); const user = interaction.options.getUser('user', true);
const group = interaction.options.getRole('group'); const group = interaction.options.getRole('group');
const leader = interaction.user; const leader = interaction.member;
const { guild } = interaction; const { guild } = interaction;
if (guild === null) { if (guild === null) {
@ -476,6 +477,13 @@ export class OutreachCommand extends Subcommand {
return; return;
} }
if (!isGuildMember(leader)) {
await interaction.editReply({
content: 'Could not find your GuildMember!',
});
return;
}
await interaction.deferReply({ await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });
@ -494,18 +502,9 @@ export class OutreachCommand extends Subcommand {
return; 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 ( if (
leader.id !== stat.stat.leaderId && leader.id !== stat.stat.leaderId &&
!leaderMember.roles.cache.has(IDs.roles.staff.outreachLeader) !leader.roles.cache.has(IDs.roles.staff.outreachLeader)
) { ) {
await interaction.editReply({ await interaction.editReply({
content: `You are not the leader for ${group}`, content: `You are not the leader for ${group}`,
@ -537,9 +536,9 @@ export class OutreachCommand extends Subcommand {
return; 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({ await interaction.editReply({
content: 'Could not fetch the member!', content: 'Could not fetch the member!',
}); });
@ -579,14 +578,6 @@ export class OutreachCommand extends Subcommand {
educated: educated !== null ? educated : 0, educated: educated !== null ? educated : 0,
}; };
if (leader === null) {
await interaction.reply({
content: 'Could not find your user!',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
await interaction.deferReply({ await interaction.deferReply({
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class BookClubCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class BookClubCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class BookClubCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const bookClub = guild.roles.cache.get(IDs.roles.bookClub); const bookClub = await getRole(IDs.roles.bookClub, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (bookClub === undefined) { if (!isRole(bookClub)) {
info.message = 'Error fetching book club role from cache!'; info.message = 'Error fetching book club role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class DebateHostCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,14 +94,6 @@ export class DebateHostCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -118,16 +113,16 @@ export class DebateHostCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const debateHost = guild.roles.cache.get(IDs.roles.debateHost); const debateHost = await getRole(IDs.roles.debateHost, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (debateHost === undefined) { if (!isRole(debateHost)) {
info.message = 'Error fetching debate host role from cache!'; info.message = 'Error fetching debate host role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class GameNightHostCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class GameNightHostCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class GameNightHostCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const gameNightHost = guild.roles.cache.get(IDs.roles.gameNightHost); const gameNightHost = await getRole(IDs.roles.gameNightHost, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (gameNightHost === undefined) { if (!isRole(gameNightHost)) {
info.message = 'Error fetching game night host role from cache!'; info.message = 'Error fetching game night host role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class GuestCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class GuestCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class GuestCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const guest = guild.roles.cache.get(IDs.roles.guest); const guest = await getRole(IDs.roles.guest, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (guest === undefined) { if (!isRole(guest)) {
info.message = 'Error fetching guest role from cache!'; info.message = 'Error fetching guest role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class MentorCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,14 +94,6 @@ export class MentorCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -118,16 +113,16 @@ export class MentorCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const mentor = guild.roles.cache.get(IDs.roles.staff.mentor); const mentor = await getRole(IDs.roles.staff.mentor, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (mentor === undefined) { if (!isRole(mentor)) {
info.message = 'Error fetching mentor role from cache!'; info.message = 'Error fetching mentor role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class ModCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class ModCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class ModCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const moderator = guild.roles.cache.get(IDs.roles.staff.moderator); const moderator = await getRole(IDs.roles.staff.moderator, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (moderator === undefined) { if (!isRole(moderator)) {
info.message = 'Error fetching the moderator role from cache!'; info.message = 'Error fetching the moderator role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class RestrictedAccessCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,14 +94,6 @@ export class RestrictedAccessCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -118,16 +113,16 @@ export class RestrictedAccessCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const restricted = guild.roles.cache.get(IDs.roles.staff.restricted); const restricted = await getRole(IDs.roles.staff.restricted, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (restricted === undefined) { if (!isRole(restricted)) {
info.message = 'Error fetching the restricted access role from cache!'; info.message = 'Error fetching the restricted access role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class StageHostCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class StageHostCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class StageHostCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const stageHost = guild.roles.cache.get(IDs.roles.stageHost); const stageHost = await getRole(IDs.roles.stageHost, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (stageHost === undefined) { if (!isRole(stageHost)) {
info.message = 'Error fetching stage host role from cache!'; info.message = 'Error fetching stage host role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class TrialModCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,14 +94,6 @@ export class TrialModCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -118,16 +113,16 @@ export class TrialModCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const moderator = guild.roles.cache.get(IDs.roles.staff.trialModerator); const moderator = await getRole(IDs.roles.staff.trialModerator, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (moderator === undefined) { if (!isRole(moderator)) {
info.message = 'Error fetching the trial moderator role from cache!'; info.message = 'Error fetching the trial moderator role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class TrialVerifierCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class TrialVerifierCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class TrialVerifierCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const trialVerifier = guild.roles.cache.get(IDs.roles.staff.trialVerifier); const trialVerifier = await getRole(IDs.roles.staff.trialVerifier, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (trialVerifier === undefined) { if (!isRole(trialVerifier)) {
info.message = 'Error fetching the trial verifier role from cache!'; info.message = 'Error fetching the trial verifier role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class VerifierCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -90,14 +93,6 @@ export class VerifierCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,16 +112,16 @@ export class VerifierCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const verifier = guild.roles.cache.get(IDs.roles.staff.verifier); const verifier = await getRole(IDs.roles.staff.verifier, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (verifier === undefined) { if (!isRole(verifier)) {
info.message = 'Error fetching verifier role from cache!'; info.message = 'Error fetching verifier role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class ActivistCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -93,12 +96,6 @@ export class ActivistCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -118,22 +115,22 @@ export class ActivistCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const modMember = guild.members.cache.get(mod.id); const modMember = await getGuildMember(mod.id, guild);
const activist = guild.roles.cache.get(IDs.roles.vegan.activist); const activist = await getRole(IDs.roles.vegan.activist, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (modMember === undefined) { if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!"; info.message = "Error fetching the staff's guild member!";
return info; return info;
} }
if (activist === undefined) { if (!isRole(activist)) {
info.message = 'Error fetching activist role from cache!'; info.message = 'Error fetching activist role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class ARAVeganCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -92,12 +95,6 @@ export class ARAVeganCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -117,22 +114,22 @@ export class ARAVeganCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const modMember = guild.members.cache.get(mod.id); const modMember = await getGuildMember(mod.id, guild);
const vegan = guild.roles.cache.get(IDs.roles.vegan.araVegan); const vegan = await getRole(IDs.roles.vegan.araVegan, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (modMember === undefined) { if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!"; info.message = "Error fetching the staff's guild member!";
return info; return info;
} }
if (vegan === undefined) { if (!isRole(vegan)) {
info.message = 'Error fetching vegan role from cache!'; info.message = 'Error fetching vegan role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class ConvincedCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,12 +94,6 @@ export class ConvincedCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -116,16 +113,16 @@ export class ConvincedCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const convinced = guild.roles.cache.get(IDs.roles.nonvegan.convinced); const convinced = await getRole(IDs.roles.nonvegan.convinced, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (convinced === undefined) { if (!isRole(convinced)) {
info.message = 'Error fetching coordinator role from cache!'; info.message = 'Error fetching coordinator role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class PlusCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -88,14 +91,6 @@ export class PlusCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -115,16 +110,16 @@ export class PlusCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const plus = guild.roles.cache.get(IDs.roles.vegan.plus); const plus = await getRole(IDs.roles.vegan.plus, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (plus === undefined) { if (!isRole(plus)) {
info.message = 'Error fetching plus role from cache!'; info.message = 'Error fetching plus role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class TrustedCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,12 +94,6 @@ export class TrustedCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -116,16 +113,16 @@ export class TrustedCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const trusted = guild.roles.cache.get(IDs.roles.trusted); const trusted = await getRole(IDs.roles.trusted, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (trusted === undefined) { if (!isRole(trusted)) {
info.message = 'Error fetching trusted role from cache!'; info.message = 'Error fetching trusted role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class VeganCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -93,12 +96,6 @@ export class VeganCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -118,22 +115,22 @@ export class VeganCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const modMember = guild.members.cache.get(mod.id); const modMember = await getGuildMember(mod.id, guild);
const vegan = guild.roles.cache.get(IDs.roles.vegan.vegan); const vegan = await getRole(IDs.roles.vegan.vegan, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (modMember === undefined) { if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!"; info.message = "Error fetching the staff's guild member!";
return info; return info;
} }
if (vegan === undefined) { if (!isRole(vegan)) {
info.message = 'Error fetching vegan role from cache!'; info.message = 'Error fetching vegan role from cache!';
return info; return info;
} }

View File

@ -21,6 +21,9 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { Guild, User, Message, MessageFlagsBitField } from 'discord.js'; import { Guild, User, Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { roleAddLog, roleRemoveLog } from '#utils/logging/role'; 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 { export class VegCuriousCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -91,12 +94,6 @@ export class VegCuriousCommand extends Command {
const mod = message.author; 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; const { guild } = message;
if (guild === null) { if (guild === null) {
@ -116,22 +113,22 @@ export class VegCuriousCommand extends Command {
message: '', message: '',
success: false, success: false,
}; };
const member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
const modMember = guild.members.cache.get(mod.id); const modMember = await getGuildMember(mod.id, guild);
const vegCurious = guild.roles.cache.get(IDs.roles.nonvegan.vegCurious); const vegCurious = await getRole(IDs.roles.nonvegan.vegCurious, guild);
// Checks if user's GuildMember was found in cache // Checks if user's GuildMember was found in cache
if (member === undefined) { if (!isGuildMember(member)) {
info.message = 'Error fetching guild member for the user!'; info.message = 'Error fetching guild member for the user!';
return info; return info;
} }
if (modMember === undefined) { if (!isGuildMember(modMember)) {
info.message = "Error fetching the staff's guild member!"; info.message = "Error fetching the staff's guild member!";
return info; return info;
} }
if (vegCurious === undefined) { if (!isRole(vegCurious)) {
info.message = 'Error fetching veg curious role from cache!'; info.message = 'Error fetching veg curious role from cache!';
return info; return info;
} }

View File

@ -20,6 +20,8 @@
import { Command, RegisterBehavior } from '@sapphire/framework'; import { Command, RegisterBehavior } from '@sapphire/framework';
import { Message, MessageFlagsBitField } from 'discord.js'; import { Message, MessageFlagsBitField } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getRole } from '#utils/fetcher';
import { isRole } from '#utils/typeChecking';
export class RenameUserCommand extends Command { export class RenameUserCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -55,10 +57,10 @@ export class RenameUserCommand extends Command {
await guild.members.fetch(); await guild.members.fetch();
const vegan = guild.roles.cache.get(IDs.roles.vegan.vegan); const vegan = await getRole(IDs.roles.vegan.vegan, guild);
const notVegan = guild.roles.cache.get(IDs.roles.nonvegan.nonvegan); const notVegan = await getRole(IDs.roles.nonvegan.nonvegan, guild);
if (vegan === undefined || notVegan === undefined) { if (!isRole(vegan) || !isRole(notVegan)) {
await interaction.reply({ await interaction.reply({
content: 'Error fetching roles!', content: 'Error fetching roles!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,

View File

@ -31,6 +31,8 @@ import {
giveVerificationRoles, giveVerificationRoles,
} from '#utils/verification'; } from '#utils/verification';
import { manualVerification } from '#utils/database/verification'; import { manualVerification } from '#utils/database/verification';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VerifyCommand extends Command { export class VerifyCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -165,32 +167,26 @@ export class VerifyCommand extends Command {
convinced: false, convinced: false,
}; };
let member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
// Checks if member is null // Checks if member is null
if (member === undefined) { if (!isGuildMember(member)) {
member = await guild.members.fetch(user.id).catch(() => undefined);
if (member === undefined) {
info.message = 'Failed to fetch member'; info.message = 'Failed to fetch member';
return info; return info;
} }
}
if (member.roles.cache.hasAny(...IDs.roles.restrictions.restricted)) { if (member.roles.cache.hasAny(...IDs.roles.restrictions.restricted)) {
info.message = "Can't verify a restricted user!"; info.message = "Can't verify a restricted user!";
return info; return info;
} }
let verifier = guild.members.cache.get(verifierId); const verifier = await getGuildMember(verifierId, guild);
// Checks if verifier is null // Checks if verifier is null
if (verifier === undefined) { if (!isGuildMember(verifier)) {
verifier = await guild.members.fetch(user.id).catch(() => undefined);
if (verifier === undefined) {
info.message = 'Failed to fetch verifier'; info.message = 'Failed to fetch verifier';
return info; return info;
} }
}
const roleArgs = rolesString.split(' '); const roleArgs = rolesString.split(' ');

View File

@ -21,6 +21,8 @@ import { Command, RegisterBehavior } from '@sapphire/framework';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { checkVerificationFinish } from '#utils/database/verification'; import { checkVerificationFinish } from '#utils/database/verification';
import { MessageFlagsBitField } from 'discord.js'; import { MessageFlagsBitField } from 'discord.js';
import { getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VerifyTimeoutRemoveCommand extends Command { export class VerifyTimeoutRemoveCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -71,15 +73,12 @@ export class VerifyTimeoutRemoveCommand extends Command {
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });
let member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
if (member === undefined) { if (!isGuildMember(member)) {
member = await guild.members.fetch(user.id).catch(undefined);
if (member === undefined) {
await interaction.editReply(`${user} is not on this server!`); await interaction.editReply(`${user} is not on this server!`);
return; return;
} }
}
if (!member.roles.cache.has(IDs.roles.verifyBlock)) { if (!member.roles.cache.has(IDs.roles.verifyBlock)) {
await interaction.editReply(`${user} is not blocked from verification!`); await interaction.editReply(`${user} is not blocked from verification!`);

View File

@ -21,6 +21,8 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
import { User, Guild, Message, MessageFlagsBitField } from 'discord.js'; import { User, Guild, Message, MessageFlagsBitField } from 'discord.js';
import { EmbedBuilder } from 'discord.js'; import { EmbedBuilder } from 'discord.js';
import { getRank, xpToNextLevel } from '#utils/database/fun/xp'; 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 { export class RankCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) { public constructor(context: Command.LoaderContext, options: Command.Options) {
@ -108,15 +110,12 @@ export class RankCommand extends Command {
success: false, success: false,
}; };
let member = guild.members.cache.get(user.id); const member = await getGuildMember(user.id, guild);
if (member === undefined) { if (!isGuildMember(member)) {
member = await guild.members.fetch(user.id).catch(() => undefined);
if (member === undefined) {
info.message = 'The user is not on this server!'; info.message = 'The user is not on this server!';
return info; return info;
} }
}
const rank = await getRank(user.id); const rank = await getRank(user.id);

View File

@ -21,12 +21,9 @@ import {
InteractionHandler, InteractionHandler,
InteractionHandlerTypes, InteractionHandlerTypes,
} from '@sapphire/framework'; } from '@sapphire/framework';
import { import { ButtonInteraction, MessageFlagsBitField } from 'discord.js';
ButtonInteraction,
GuildMember,
MessageFlagsBitField,
} from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class NonVeganAccessButtonHandler extends InteractionHandler { export class NonVeganAccessButtonHandler extends InteractionHandler {
public constructor( public constructor(
@ -46,13 +43,13 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
} }
public async run(interaction: ButtonInteraction) { public async run(interaction: ButtonInteraction) {
let { member } = interaction; const { member } = interaction;
const errorMessage = const errorMessage =
'There was an error giving you the role, please try again later or contact ModMail/the developer ' + 'There was an error giving you the role, please try again later or contact ModMail/the developer ' +
'to sort out this problem.'; 'to sort out this problem.';
if (member === null) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: errorMessage, content: errorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
@ -60,18 +57,13 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
return; return;
} }
try {
member = member as GuildMember;
if (!member.roles.cache.has(IDs.roles.vegan.vegan)) { if (!member.roles.cache.has(IDs.roles.vegan.vegan)) {
await interaction.reply({ await interaction.reply({
content: 'You need to be vegan to use this button!', content: 'You need to be vegan to use this button!',
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });
return; return;
} } else if (member.roles.cache.has(IDs.roles.vegan.nvAccess)) {
if (member.roles.cache.has(IDs.roles.vegan.nvAccess)) {
await member.roles.remove(IDs.roles.vegan.nvAccess); await member.roles.remove(IDs.roles.vegan.nvAccess);
await interaction.reply({ await interaction.reply({
content: content:
@ -80,8 +72,7 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });
return; return;
} } else {
await member.roles.add(IDs.roles.vegan.nvAccess); await member.roles.add(IDs.roles.vegan.nvAccess);
await interaction.reply({ await interaction.reply({
content: content:
@ -89,12 +80,6 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
'If you want to remove access again, click this button again.', 'If you want to remove access again, click this button again.',
flags: MessageFlagsBitField.Flags.Ephemeral, 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, InteractionHandler,
InteractionHandlerTypes, InteractionHandlerTypes,
} from '@sapphire/framework'; } from '@sapphire/framework';
import { import { ButtonInteraction, MessageFlagsBitField } from 'discord.js';
ButtonInteraction,
GuildMember,
MessageFlagsBitField,
} from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { checkActive } from '#utils/database/moderation/restriction'; import { checkActive } from '#utils/database/moderation/restriction';
import { addUser } from '#utils/database/dbExistingUser'; import { addUser } from '#utils/database/dbExistingUser';
import { getTextBasedChannel } from '#utils/fetcher';
import { isGuildMember, isTextChannel } from '@sapphire/discord.js-utilities';
export class WelcomeButtonHandler extends InteractionHandler { export class WelcomeButtonHandler extends InteractionHandler {
public constructor( public constructor(
@ -49,9 +47,7 @@ export class WelcomeButtonHandler extends InteractionHandler {
public async run(interaction: ButtonInteraction) { public async run(interaction: ButtonInteraction) {
const { member } = interaction; const { member } = interaction;
let general = this.container.client.channels.cache.get( const general = await getTextBasedChannel(IDs.channels.nonVegan.general);
IDs.channels.nonVegan.general,
);
// Messages that are used multiple times // Messages that are used multiple times
const roleErrorMessage = const roleErrorMessage =
@ -63,14 +59,7 @@ export class WelcomeButtonHandler extends InteractionHandler {
'to be verified and gain access to more channels.'; 'to be verified and gain access to more channels.';
// Checks if general is not in the cache // Checks if general is not in the cache
if (general === undefined) { if (!isTextChannel(general)) {
// 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) {
this.container.logger.error( this.container.logger.error(
'WelcomeButtonHandler: Could not find and fetch the general channel!', 'WelcomeButtonHandler: Could not find and fetch the general channel!',
); );
@ -83,12 +72,8 @@ export class WelcomeButtonHandler extends InteractionHandler {
return; return;
} }
// Replace fetched version of general with the cached version
general = generalFetch;
}
// If the member could not be found // If the member could not be found
if (!(member instanceof GuildMember)) { if (!isGuildMember(member)) {
await interaction.reply({ await interaction.reply({
content: roleErrorMessage, content: roleErrorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral, flags: MessageFlagsBitField.Flags.Ephemeral,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,8 @@ import { Listener } from '@sapphire/framework';
import { GuildMember } from 'discord.js'; import { GuildMember } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { noModHistory, userPreviouslyHadRole } from '#utils/database/memberMod'; 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 * 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 { 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( this.container.logger.error(
'TrustedXP Listener: the Trusted role could not be found in the guild.', 'TrustedXP Listener: the Trusted role could not be found in the guild.',
); );

View File

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

View File

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

View File

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

View File

@ -18,9 +18,9 @@
*/ */
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class RestrictedMessageTask extends ScheduledTask { export class RestrictedMessageTask extends ScheduledTask {
public constructor( public constructor(
@ -34,14 +34,20 @@ export class RestrictedMessageTask extends ScheduledTask {
} }
public async run() { public async run() {
const { client } = container; const restricted = await getTextBasedChannel(
const restricted = client.channels.cache.get(
IDs.channels.restricted.restricted, IDs.channels.restricted.restricted,
) as TextChannel; );
const tolerance = client.channels.cache.get( const tolerance = await getTextBasedChannel(
IDs.channels.restricted.tolerance, 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 restricted.send(this.message(IDs.roles.restrictions.restricted1));
await tolerance.send(this.message(IDs.roles.restrictions.restricted3)); await tolerance.send(this.message(IDs.roles.restrictions.restricted3));

View File

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

View File

@ -18,9 +18,9 @@
*/ */
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import { container } from '@sapphire/framework';
import type { TextChannel } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
export class VerifyReminder extends ScheduledTask { export class VerifyReminder extends ScheduledTask {
public constructor( public constructor(
@ -34,8 +34,6 @@ export class VerifyReminder extends ScheduledTask {
} }
public async run() { public async run() {
const { client } = container;
// Get the total messages sent in non-vegan general since last message // Get the total messages sent in non-vegan general since last message
const redisKey = 'verifyReminderMessageCounter'; const redisKey = 'verifyReminderMessageCounter';
@ -45,9 +43,15 @@ export class VerifyReminder extends ScheduledTask {
if (!messageCount || +messageCount < 100) return; if (!messageCount || +messageCount < 100) return;
// Send verification reminder to non-vegan general // Send verification reminder to non-vegan general
const channel = client.channels.cache.get( const channel = await getTextBasedChannel(IDs.channels.nonVegan.general);
IDs.channels.nonVegan.general,
) as TextChannel; if (!isTextBasedChannel(channel)) {
this.container.logger.error(
'Verify Reminder: The bot could not find the channel to post the reminder!',
);
return;
}
await channel.send( await channel.send(
"If you want to have the vegan or activist role, you'll need to do a voice verification. " + "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, checkTempBan,
removeTempBan, removeTempBan,
} from '#utils/database/moderation/tempBan'; } 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 { export class TempBan extends ScheduledTask {
public constructor( public constructor(
@ -36,31 +39,25 @@ export class TempBan extends ScheduledTask {
public async run(payload: { userId: string; guildId: string }) { public async run(payload: { userId: string; guildId: string }) {
this.container.logger.debug('Temp Unban Task: Currently running unban'); this.container.logger.debug('Temp Unban Task: Currently running unban');
// Get the guild where the user is in // Get the guild where the user is in
let guild = this.container.client.guilds.cache.get(payload.guildId); const guild = await getGuild(payload.guildId);
if (guild === undefined) {
guild = await this.container.client.guilds
.fetch(payload.guildId)
.catch(() => undefined);
if (guild === undefined) { if (guild === undefined) {
this.container.logger.error('Temp Unban Task: Guild not found!'); this.container.logger.error('Temp Unban Task: Guild not found!');
return; return;
} }
}
const { userId } = payload; const { userId } = payload;
let user = guild.client.users.cache.get(userId); const user = await getUser(userId);
if (user === undefined) { if (!isUser(user)) {
user = await guild.client.users.fetch(userId).catch(() => undefined);
if (user === undefined) {
this.container.logger.error( this.container.logger.error(
'Temp Unban Task: Could not fetch banned user!', 'Temp Unban Task: Could not fetch banned user!',
); );
return; return;
} }
}
if ((await checkBan(userId)) || !(await checkTempBan(userId))) { if ((await checkBan(userId)) || !(await checkTempBan(userId))) {
this.container.logger.debug( this.container.logger.debug(
@ -75,29 +72,15 @@ export class TempBan extends ScheduledTask {
await removeTempBan(userId); await removeTempBan(userId);
// Log unban // Log unban
let logChannel = guild.channels.cache.get(IDs.channels.logs.restricted); const logChannel = await getTextBasedChannel(IDs.channels.logs.restricted);
if (logChannel === undefined) { if (!isTextChannel(logChannel)) {
const logChannelFetch = await guild.channels
.fetch(IDs.channels.logs.restricted)
.catch(() => null);
if (logChannelFetch === null) {
this.container.logger.error( this.container.logger.error(
`Temp Ban Listener: Could not fetch log channel. User Snowflake: ${userId}`, `Temp Ban Listener: Could not fetch log channel. User Snowflake: ${userId}`,
); );
return; 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() const log = new EmbedBuilder()
.setColor('#28A745') .setColor('#28A745')
.setAuthor({ .setAuthor({

View File

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

View File

@ -19,6 +19,8 @@
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getGuild, getGuildMember } from '#utils/fetcher';
import { isGuildMember } from '@sapphire/discord.js-utilities';
export class VerifyUnblock extends ScheduledTask { export class VerifyUnblock extends ScheduledTask {
public constructor( public constructor(
@ -30,29 +32,23 @@ export class VerifyUnblock extends ScheduledTask {
public async run(payload: { userId: string; guildId: string }) { public async run(payload: { userId: string; guildId: string }) {
// Get the guild where the user is in // Get the guild where the user is in
let guild = this.container.client.guilds.cache.get(payload.guildId); const guild = await getGuild(payload.guildId);
if (guild === undefined) {
guild = await this.container.client.guilds
.fetch(payload.guildId)
.catch(() => undefined);
if (guild === undefined) { if (guild === undefined) {
this.container.logger.error('verifyUnblock: Guild not found!'); this.container.logger.error('verifyUnblock: Guild not found!');
return; return;
} }
}
// Find GuildMember for the user // Find GuildMember for the user
let user = guild.members.cache.get(payload.userId); const member = await getGuildMember(payload.userId, guild);
if (user === undefined) {
user = await guild.members.fetch(payload.userId).catch(() => undefined); if (!isGuildMember(member)) {
if (user === undefined) {
this.container.logger.error('verifyUnblock: GuildMember not found!'); this.container.logger.error('verifyUnblock: GuildMember not found!');
return; return;
} }
}
// Remove the 'verify block' role // 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 type { TextBasedChannel } from 'discord.js';
import IDs from '#utils/ids'; 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. * 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 * @returns {boolean} true if is in staff channel
*/ */
export function checkStaff(channel: TextBasedChannel | null) { export function checkStaff(channel: TextBasedChannel | Nullish): boolean {
if (channel === null) { if (!isTextChannel(channel)) {
return false;
}
if (channel.type !== ChannelType.GuildText) {
return false; 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, ChannelType,
GuildMember, GuildMember,
PermissionsBitField, PermissionsBitField,
TextChannel,
time, time,
User, User,
} from 'discord.js'; } from 'discord.js';
import type { Snowflake, VoiceBasedChannel } from 'discord.js'; import type { Snowflake, VoiceBasedChannel } from 'discord.js';
import IDs from '#utils/ids'; import IDs from '#utils/ids';
import { getTextBasedChannel } from '#utils/fetcher';
import {
isDMChannel,
isTextBasedChannel,
} from '@sapphire/discord.js-utilities';
export async function createVerificationText( export async function createVerificationText(
member: GuildMember, member: GuildMember,
@ -252,12 +256,16 @@ export async function finishVerifyMessages(
// Not vegan // Not vegan
if (!roles.vegan) { if (!roles.vegan) {
const general = container.client.channels.cache.get( const general = await getTextBasedChannel(IDs.channels.nonVegan.general);
IDs.channels.nonVegan.general,
) as TextChannel | undefined; if (!isTextBasedChannel(general)) {
if (general === undefined) { container.logger.error(
'Verification: Could not find general chat to welcome a non-vegan!',
);
return; return;
} }
let msg = let msg =
`${user}, you have been verified! Please check <#${IDs.channels.information.roles}> ` + `${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.`; `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 // Vegan
const general = container.client.channels.cache.get( const general = await getTextBasedChannel(IDs.channels.vegan.general);
IDs.channels.vegan.general,
) as TextChannel | undefined; if (!isTextBasedChannel(general)) {
if (general === undefined) { container.logger.error(
'Verification: Could not find general chat to welcome a vegan!',
);
return; return;
} }
const msg = `Welcome ${user}! Please check out <#${IDs.channels.information.roles}> :)`; 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' + '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" + "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'; '5. Differences in opinion between activists should be resolved in vegan spaces, not in the chat with non-vegans';
await user.send(activistMsg).catch(() => { await user.send(activistMsg).catch(async () => {
const activist = container.client.channels.cache.get( const activist = await getTextBasedChannel(
IDs.channels.activism.activism, IDs.channels.activism.activism,
) as TextChannel | undefined; );
if (activist === undefined) {
if (!isDMChannel(activist)) {
return; return;
} }
activist.send(activistMsg);
await activist.send(activistMsg);
}); });
} }
} }