Compare commits

..

No commits in common. "2207d996a1b586b64cff629a084e30f12015e8cc" and "9b3908cdc4fa8c855e9fec7bddfc890871177994" have entirely different histories.

4 changed files with 72 additions and 139 deletions

View File

@ -21,11 +21,7 @@ import {
InteractionHandler,
InteractionHandlerTypes,
} from '@sapphire/framework';
import {
ButtonInteraction,
GuildMember,
MessageFlagsBitField,
} from 'discord.js';
import type { ButtonInteraction, GuildMember } from 'discord.js';
import IDs from '#utils/ids';
export class NonVeganAccessButtonHandler extends InteractionHandler {
@ -55,7 +51,7 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
if (member === null) {
await interaction.reply({
content: errorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
ephemeral: true,
});
return;
}
@ -66,7 +62,7 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
if (!member.roles.cache.has(IDs.roles.vegan.vegan)) {
await interaction.reply({
content: 'You need to be vegan to use this button!',
flags: MessageFlagsBitField.Flags.Ephemeral,
ephemeral: true,
});
return;
}
@ -77,7 +73,7 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
content:
'Your access from the non vegan section has been removed. ' +
'If you want to gain access again, click this button again.',
flags: MessageFlagsBitField.Flags.Ephemeral,
ephemeral: true,
});
return;
}
@ -87,13 +83,13 @@ export class NonVeganAccessButtonHandler extends InteractionHandler {
content:
'Your access to the non vegan section has been given back. ' +
'If you want to remove access again, click this button again.',
flags: MessageFlagsBitField.Flags.Ephemeral,
ephemeral: true,
});
} catch (error) {
this.container.logger.error(`Non Vegan Access Interaction: ${error}`);
await interaction.reply({
content: errorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
ephemeral: true,
});
}
}

View File

@ -25,10 +25,10 @@ import {
ButtonInteraction,
GuildMember,
MessageFlagsBitField,
TextChannel,
} from 'discord.js';
import IDs from '#utils/ids';
import { checkActive } from '#utils/database/moderation/restriction';
import { addUser } from '#utils/database/dbExistingUser';
export class WelcomeButtonHandler extends InteractionHandler {
public constructor(
@ -48,101 +48,60 @@ export class WelcomeButtonHandler extends InteractionHandler {
}
public async run(interaction: ButtonInteraction) {
const { member } = interaction;
let general = this.container.client.channels.cache.get(
let { member } = interaction;
const general = this.container.client.channels.cache.get(
IDs.channels.nonVegan.general,
);
// Messages that are used multiple times
const roleErrorMessage =
'There was an error giving you the role, please try again later or contact ModMail to be let into this server.';
const welcomeMessage =
`${member} Welcome to ARA! :D Please check <#${IDs.channels.information.roles}> ` +
`and remember to follow the <#${IDs.channels.information.conduct}> and to respect ongoing discussions and debates.` +
`\n\nIf you are vegan, you can join the 'Verification' voice channel, or use \`/apply\` with the Appy bot in <#${IDs.channels.nonVegan.vcText}>, ` +
'to be verified and gain access to more channels.';
// Checks if general is not in the cache
) as TextChannel | undefined;
if (general === undefined) {
// Sends an API request to get the channel
const generalFetch = await this.container.client.channels
.fetch(IDs.channels.nonVegan.general)
.catch(() => undefined);
return;
}
// If general does not exist
if (generalFetch === null || generalFetch === undefined) {
this.container.logger.error(
'WelcomeButtonHandler: Could not find and fetch the general channel!',
);
if (member === null) {
await interaction.reply({
content:
'There was an error giving you the role, please try again later or contact ModMail to be let into this server.',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
try {
member = member as GuildMember;
// Checks if the user is currently restricted
if (await checkActive(member.id)) {
await interaction.reply({
content:
'Sorry there was a problem trying to give you access to the server. Please try again later.',
content: `You are currently restricted from this server! Contact the moderators by sending a DM to <@${IDs.modMail}>.`,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// Replace fetched version of general with the cached version
general = generalFetch;
}
// Give non-vegan role
if (!member.voice.channel) {
await member.roles.add(IDs.roles.nonvegan.nonvegan);
// If the member could not be found
if (!(member instanceof GuildMember)) {
await interaction.reply({
content: roleErrorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
await general.send(
`${member} Welcome to ARA! :D Please check <#${IDs.channels.information.roles}> ` +
`and remember to follow the <#${IDs.channels.information.conduct}> and to respect ongoing discussions and debates.` +
`\n\nIf you are vegan, you can join the 'Verification' voice channel, or use \`/apply\` with the Appy bot in <#${IDs.channels.nonVegan.vcText}>, ` +
'to be verified and gain access to more channels.',
);
return;
}
return;
}
// Checks if the user is currently restricted
if (await checkActive(member.id)) {
await interaction.reply({
content: `You are currently restricted from this server! Contact the moderators by sending a DM to <@${IDs.modMail}>.`,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// Give non-vegan role
if (member.voice.channel) {
await interaction.reply({
content:
"You're currently in a verification, you'll have to leave the verification or get verified before being able to access the server again.",
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// Add the user to the database
await addUser(member.id);
// Give the role to the member
const role = await member.roles
.add(IDs.roles.nonvegan.nonvegan)
.catch(() => undefined);
// If the role could not be given
if (role === undefined) {
} catch (error) {
await interaction.reply({
content: roleErrorMessage,
content:
'There was an error giving you the role, please try again later or contact ModMail to be let into this server.',
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
if (general.isSendable()) {
await general.send(welcomeMessage);
} else {
this.container.logger.error(
'WelcomeButtonHandler: The bot does not have permission to send in general!',
);
await member.send(welcomeMessage);
}
}
}

View File

@ -41,13 +41,13 @@ export class FixRolesOnReady extends Listener {
// THIS SHOULD BE DISABLED BY DEFAULT
// THIS IS ONLY USED FOR RESTORING ROLES TO THE SERVER!
// ENABLING THIS UNINTENTIONALLY WILL CAUSE SLOWDOWNS TO THE BOT DUE TO RATE LIMITING!
enabled: false,
enabled: true,
});
}
public async run(client: Client) {
this.container.logger.info(
'FixRolesOnReady: Preparation before starting to fix the roles for each user...',
'FixRolesOnReady: Preparation before starting to fix the roles for nonvegans...',
);
// Fetching the Guild
@ -60,7 +60,9 @@ export class FixRolesOnReady extends Listener {
// Fetching the channel for the logs
// Leave the snowflake parameter empty for no logs
const logChannel = await client.channels.fetch('').catch(() => null);
const logChannel = await client.channels
.fetch('1329152627312824320')
.catch(() => null);
const sendLogs = logChannel !== null;
if (!sendLogs) {
@ -107,13 +109,10 @@ export class FixRolesOnReady extends Listener {
);
for (const [userId, member] of members) {
// Update the counter for the total number of users processed
count += 1;
// Send a message with an update for every 50 completions
// Checks if `channelLog` has been set to null
// The RHS of the modulo should be around 100
if (sendLogs && count % 250 === 0) {
if (sendLogs && count % 50 === 0) {
const currentTime = new Date().getTime();
const runningTime = currentTime - startTime;
@ -128,6 +127,14 @@ export class FixRolesOnReady extends Listener {
}
// Checks if the user already has vegan or non-vegan role
if (
member.roles.cache.has(IDs.roles.vegan.vegan) ||
member.roles.cache.has(IDs.roles.nonvegan.nonvegan)
) {
await this.delay(1000);
count++;
continue;
}
// Checks if the user is restricted, and skips over them if they are
const restricted = await checkActive(userId);
@ -136,10 +143,9 @@ export class FixRolesOnReady extends Listener {
restricted ||
member.roles.cache.has(IDs.roles.restrictions.restricted1) ||
member.roles.cache.has(IDs.roles.restrictions.restricted2) ||
member.roles.cache.has(IDs.roles.restrictions.restricted3) ||
member.roles.cache.has(IDs.roles.restrictions.restricted4) ||
member.roles.cache.has(IDs.roles.restrictions.restrictedVegan)
) {
count++;
continue;
}
@ -154,6 +160,9 @@ export class FixRolesOnReady extends Listener {
if (xp !== null && xp.xp > 0) {
roles.push(IDs.roles.nonvegan.nonvegan);
} else {
count++;
continue;
}
}
@ -163,12 +172,13 @@ export class FixRolesOnReady extends Listener {
}
// Log the completion
count += 1;
this.container.logger.info(
`FixRolesOnReady: Given roles to ${count}/${totalMembers}.`,
);
// Add a delay so that there's around 4 users processed a second
await this.delay(1000);
await this.delay(5000);
}
// Send the logs that the fix has finished.

View File

@ -17,18 +17,20 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { GuildMember, GuildMemberRoleManager, Snowflake } from 'discord.js';
import type {
GuildMember,
GuildMemberRoleManager,
Snowflake,
} from 'discord.js';
import { container } from '@sapphire/framework';
import IDs from '#utils/ids';
import { Prisma } from '@prisma/client';
import { DefaultArgs, GetResult } from '@prisma/client/runtime/binary';
/**
* Checks if the user exists on the User table in the database
* @param {string} userId Snowflake for the user being checked
* @return {Promise<boolean>} If the user was found
* @return {boolean} If the user was found
*/
export async function userExists(userId: Snowflake): Promise<boolean> {
export async function userExists(userId: Snowflake) {
// Counts if the user is on the database by their snowflake
const userQuery = await container.database.user.findFirst({
where: {
@ -64,26 +66,6 @@ function getRoles(roles: GuildMemberRoleManager) {
return rolesDict;
}
/**
* Adds a new user to the server
* @param {Snowflake} userId the `User` snowflake to be added to the database
*/
export async function addUser(userId: Snowflake) {
// Uses upsert just in case the user has joined the server previously but has not gotten the roles previously
await container.database.user.upsert({
where: {
id: userId,
},
update: {
notVegan: true,
},
create: {
id: userId,
notVegan: true,
},
});
}
/**
* Add user to the database, if they have not been added beforehand
* @param {GuildMember} member GuildMember for the user to be added to the database
@ -173,9 +155,9 @@ export async function updateUser(member: GuildMember) {
/**
* Gets the roles that the user that is on the User table.
* @param {string} userId Snowflake of the user to fetch roles from
* @return {Promise<Snowflake[]>} Array of Role Snowflakes
* @return {Snowflake[]} Array of Role Snowflakes
*/
export async function fetchRoles(userId: Snowflake): Promise<Snowflake[]> {
export async function fetchRoles(userId: Snowflake) {
// Get the user's roles
const roleQuery = await container.database.user.findUnique({
where: {
@ -248,26 +230,12 @@ export async function logLeaving(member: GuildMember) {
});
}
// The type returned by `getLeaveRoles`.
// Includes a list of all the role Snowflakes when the user last left the server
type GetLeaveRoles = Prisma.Prisma__LeaveLogClient<
GetResult<
Prisma.$LeaveLogPayload<DefaultArgs>,
{
select: { roles: boolean };
},
'findFirst'
> | null,
null,
DefaultArgs
>;
/**
* Get the roles that the user had prior to when they left the server.
* @param {string} userId Snowflake of the user who joined the server
* @return {GetLeaveRoles} Array of Role Snowflakes
* @return {string[]} Array of Role Snowflakes
*/
export function getLeaveRoles(userId: Snowflake): GetLeaveRoles {
export async function getLeaveRoles(userId: Snowflake) {
const roles = container.database.leaveLog.findFirst({
where: {
userId,