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

View File

@ -25,10 +25,10 @@ import {
ButtonInteraction, ButtonInteraction,
GuildMember, GuildMember,
MessageFlagsBitField, MessageFlagsBitField,
TextChannel,
} from 'discord.js'; } 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';
export class WelcomeButtonHandler extends InteractionHandler { export class WelcomeButtonHandler extends InteractionHandler {
public constructor( public constructor(
@ -48,54 +48,25 @@ export class WelcomeButtonHandler extends InteractionHandler {
} }
public async run(interaction: ButtonInteraction) { public async run(interaction: ButtonInteraction) {
const { member } = interaction; let { member } = interaction;
let general = this.container.client.channels.cache.get( const general = this.container.client.channels.cache.get(
IDs.channels.nonVegan.general, IDs.channels.nonVegan.general,
); ) as TextChannel | undefined;
// 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
if (general === undefined) { if (general === undefined) {
// Sends an API request to get the channel return;
const generalFetch = await this.container.client.channels }
.fetch(IDs.channels.nonVegan.general)
.catch(() => undefined);
// If general does not exist if (member === null) {
if (generalFetch === null || generalFetch === undefined) {
this.container.logger.error(
'WelcomeButtonHandler: Could not find and fetch the general channel!',
);
await interaction.reply({ await interaction.reply({
content: 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, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });
return; return;
} }
// Replace fetched version of general with the cached version try {
general = generalFetch; member = member as GuildMember;
}
// If the member could not be found
if (!(member instanceof GuildMember)) {
await interaction.reply({
content: roleErrorMessage,
flags: MessageFlagsBitField.Flags.Ephemeral,
});
return;
}
// Checks if the user is currently restricted // Checks if the user is currently restricted
if (await checkActive(member.id)) { if (await checkActive(member.id)) {
@ -108,41 +79,29 @@ export class WelcomeButtonHandler extends InteractionHandler {
} }
// Give non-vegan role // 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({ await interaction.reply({
content: 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.", "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, flags: MessageFlagsBitField.Flags.Ephemeral,
}); });
} catch (error) {
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) {
await interaction.reply({ 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, 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 SHOULD BE DISABLED BY DEFAULT
// THIS IS ONLY USED FOR RESTORING ROLES TO THE SERVER! // THIS IS ONLY USED FOR RESTORING ROLES TO THE SERVER!
// ENABLING THIS UNINTENTIONALLY WILL CAUSE SLOWDOWNS TO THE BOT DUE TO RATE LIMITING! // ENABLING THIS UNINTENTIONALLY WILL CAUSE SLOWDOWNS TO THE BOT DUE TO RATE LIMITING!
enabled: false, enabled: true,
}); });
} }
public async run(client: Client) { public async run(client: Client) {
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 nonvegans...',
); );
// Fetching the Guild // Fetching the Guild
@ -60,7 +60,9 @@ 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 client.channels
.fetch('1329152627312824320')
.catch(() => null);
const sendLogs = logChannel !== null; const sendLogs = logChannel !== null;
if (!sendLogs) { if (!sendLogs) {
@ -107,13 +109,10 @@ export class FixRolesOnReady extends Listener {
); );
for (const [userId, member] of members) { 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 // Send a message with an update for every 50 completions
// Checks if `channelLog` has been set to null // Checks if `channelLog` has been set to null
// The RHS of the modulo should be around 100 // 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 currentTime = new Date().getTime();
const runningTime = currentTime - startTime; const runningTime = currentTime - startTime;
@ -128,6 +127,14 @@ export class FixRolesOnReady extends Listener {
} }
// Checks if the user already has vegan or non-vegan role // 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 // Checks if the user is restricted, and skips over them if they are
const restricted = await checkActive(userId); const restricted = await checkActive(userId);
@ -136,10 +143,9 @@ export class FixRolesOnReady extends Listener {
restricted || restricted ||
member.roles.cache.has(IDs.roles.restrictions.restricted1) || member.roles.cache.has(IDs.roles.restrictions.restricted1) ||
member.roles.cache.has(IDs.roles.restrictions.restricted2) || member.roles.cache.has(IDs.roles.restrictions.restricted2) ||
member.roles.cache.has(IDs.roles.restrictions.restricted3) ||
member.roles.cache.has(IDs.roles.restrictions.restricted4) ||
member.roles.cache.has(IDs.roles.restrictions.restrictedVegan) member.roles.cache.has(IDs.roles.restrictions.restrictedVegan)
) { ) {
count++;
continue; continue;
} }
@ -154,6 +160,9 @@ export class FixRolesOnReady extends Listener {
if (xp !== null && xp.xp > 0) { if (xp !== null && xp.xp > 0) {
roles.push(IDs.roles.nonvegan.nonvegan); roles.push(IDs.roles.nonvegan.nonvegan);
} else {
count++;
continue;
} }
} }
@ -163,12 +172,13 @@ export class FixRolesOnReady extends Listener {
} }
// Log the completion // Log the completion
count += 1;
this.container.logger.info( this.container.logger.info(
`FixRolesOnReady: Given roles to ${count}/${totalMembers}.`, `FixRolesOnReady: Given roles to ${count}/${totalMembers}.`,
); );
// Add a delay so that there's around 4 users processed a second // 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. // 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/>. 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 { container } from '@sapphire/framework';
import IDs from '#utils/ids'; 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 * Checks if the user exists on the User table in the database
* @param {string} userId Snowflake for the user being checked * @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 // Counts if the user is on the database by their snowflake
const userQuery = await container.database.user.findFirst({ const userQuery = await container.database.user.findFirst({
where: { where: {
@ -64,26 +66,6 @@ function getRoles(roles: GuildMemberRoleManager) {
return rolesDict; 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 * 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 * @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. * Gets the roles that the user that is on the User table.
* @param {string} userId Snowflake of the user to fetch roles from * @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 // Get the user's roles
const roleQuery = await container.database.user.findUnique({ const roleQuery = await container.database.user.findUnique({
where: { 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. * 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 * @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({ const roles = container.database.leaveLog.findFirst({
where: { where: {
userId, userId,