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,54 +48,25 @@ 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:
'Sorry there was a problem trying to give you access to the server. Please try again later.',
'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;
}
// Replace fetched version of general with the cached version
general = generalFetch;
}
// If the member could not be found
if (!(member instanceof GuildMember)) {
await interaction.reply({
content: roleErrorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
try {
member = member as GuildMember;
// Checks if the user is currently restricted
if (await checkActive(member.id)) {
@ -108,41 +79,29 @@ export class WelcomeButtonHandler extends InteractionHandler {
}
// Give non-vegan role
if (member.voice.channel) {
if (!member.voice.channel) {
await member.roles.add(IDs.roles.nonvegan.nonvegan);
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;
}
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,